diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java index a6c4445619..d66af1ae24 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java @@ -98,9 +98,6 @@ public class NavBarToHomeTouchController implements TouchController, SwipeDetect if (mStartState == OVERVIEW || mStartState == ALL_APPS) { return true; } - if (!mLauncher.hasWindowFocus()) { - return true; - } if (AbstractFloatingView.getTopOpenView(mLauncher) != null) { return true; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index cbc94ba1f6..dc354404af 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -62,6 +62,7 @@ import android.view.WindowManager; import androidx.annotation.BinderThread; +import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.MainThreadExecutor; import com.android.launcher3.R; import com.android.launcher3.ResourceUtils; @@ -79,6 +80,7 @@ import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer; import com.android.quickstep.inputconsumers.InputConsumer; import com.android.quickstep.inputconsumers.OtherActivityInputConsumer; import com.android.quickstep.inputconsumers.OverviewInputConsumer; +import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer; import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.shared.recents.ISystemUiProxy; @@ -566,10 +568,9 @@ public class TouchInteractionService extends Service implements info.id = mSwipeSharedState.nextRunningTaskId; return createOtherActivityInputConsumer(event, info); } else if (mSwipeSharedState.goingToLauncher || activityControl.isResumed()) { - return OverviewInputConsumer.newInstance(activityControl, mInputMonitorCompat, false); - } else if (ENABLE_QUICKSTEP_LIVE_TILE.get() && - activityControl.isInLiveTileMode()) { - return OverviewInputConsumer.newInstance(activityControl, mInputMonitorCompat, false); + return createOverviewInputConsumer(event); + } else if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityControl.isInLiveTileMode()) { + return createOverviewInputConsumer(event); } else if (mGestureBlockingActivity != null && runningTaskInfo != null && mGestureBlockingActivity.equals(runningTaskInfo.topActivity)) { return InputConsumer.NO_OP; @@ -578,20 +579,24 @@ public class TouchInteractionService extends Service implements } } + private boolean disableHorizontalSwipe(MotionEvent event) { + // mExclusionRegion can change on binder thread, use a local instance here. + Region exclusionRegion = mExclusionRegion; + return mMode == Mode.NO_BUTTON && exclusionRegion != null + && exclusionRegion.contains((int) event.getX(), (int) event.getY()); + } + private OtherActivityInputConsumer createOtherActivityInputConsumer(MotionEvent event, RunningTaskInfo runningTaskInfo) { final ActivityControlHelper activityControl = mOverviewComponentObserver.getActivityControlHelper(); boolean shouldDefer = activityControl.deferStartingActivity(mActiveNavBarRegion, event); - // mExclusionRegion can change on binder thread, use a local instance here. - Region exclusionRegion = mExclusionRegion; - boolean disableHorizontalSwipe = mMode == Mode.NO_BUTTON && exclusionRegion != null - && exclusionRegion.contains((int) event.getX(), (int) event.getY()); return new OtherActivityInputConsumer(this, runningTaskInfo, mRecentsModel, mOverviewComponentObserver.getOverviewIntent(), activityControl, shouldDefer, mOverviewCallbacks, mInputConsumer, this::onConsumerInactive, - mSwipeSharedState, mInputMonitorCompat, mSwipeTouchRegion, disableHorizontalSwipe); + mSwipeSharedState, mInputMonitorCompat, mSwipeTouchRegion, + disableHorizontalSwipe(event)); } private InputConsumer createDeviceLockedInputConsumer(RunningTaskInfo taskInfo) { @@ -603,6 +608,23 @@ public class TouchInteractionService extends Service implements } } + public InputConsumer createOverviewInputConsumer(MotionEvent event) { + final ActivityControlHelper activityControl = + mOverviewComponentObserver.getActivityControlHelper(); + BaseDraggingActivity activity = activityControl.getCreatedActivity(); + if (activity == null) { + return InputConsumer.NO_OP; + } + + if (activity.getRootView().hasWindowFocus()) { + return new OverviewInputConsumer(activity, mInputMonitorCompat, + false /* startingInActivityBounds */); + } else { + return new OverviewWithoutFocusInputConsumer(this, mInputMonitorCompat, + disableHorizontalSwipe(event)); + } + } + /** * To be called by the consumer when it's no longer active. */ diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index 45f34e72c1..8b1efb24e1 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -858,7 +858,9 @@ public class WindowTransformSwipeHandler setTargetAlphaProvider(WindowTransformSwipeHandler::getHiddenTargetAlpha); } - return OverviewInputConsumer.newInstance(mActivityControlHelper, null, true); + BaseDraggingActivity activity = mActivityControlHelper.getCreatedActivity(); + return activity == null + ? InputConsumer.NO_OP : new OverviewInputConsumer(activity, null, true); } private void endRunningWindowAnim() { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java index 6e7cb8fca8..489eb278fd 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java @@ -31,6 +31,7 @@ public interface InputConsumer { int TYPE_DEVICE_LOCKED = 1 << 4; int TYPE_ACCESSIBILITY = 1 << 5; int TYPE_SCREEN_PINNED = 1 << 6; + int TYPE_OVERVIEW_WITHOUT_FOCUS = 1 << 7; InputConsumer NO_OP = () -> TYPE_NO_OP; @@ -78,6 +79,8 @@ public interface InputConsumer { return "ACCESSIBILITY"; case TYPE_SCREEN_PINNED: return "SCREEN_PINNED"; + case TYPE_OVERVIEW_WITHOUT_FOCUS: + return "TYPE_OVERVIEW_WITHOUT_FOCUS"; default: return "NO_OP"; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index 0ed4c99a6f..69b25db8f5 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -28,7 +28,6 @@ import static com.android.launcher3.uioverrides.RecentsUiFactory.ROTATION_LANDSC import static com.android.launcher3.uioverrides.RecentsUiFactory.ROTATION_SEASCAPE; import static com.android.launcher3.util.RaceConditionTracker.ENTER; import static com.android.launcher3.util.RaceConditionTracker.EXIT; -import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; @@ -43,10 +42,8 @@ import android.os.Build; import android.os.Handler; import android.os.Looper; import android.view.MotionEvent; -import android.view.Surface; import android.view.VelocityTracker; import android.view.ViewConfiguration; -import android.view.WindowManager; import androidx.annotation.UiThread; @@ -65,6 +62,7 @@ import com.android.quickstep.WindowTransformSwipeHandler; import com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget; import com.android.quickstep.util.CachedEventDispatcher; import com.android.quickstep.util.MotionPauseDetector; +import com.android.quickstep.util.NavBarPosition; import com.android.quickstep.util.RecentsAnimationListenerSet; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.BackgroundExecutor; @@ -95,7 +93,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC private final SysUINavigationMode.Mode mMode; private final RectF mSwipeTouchRegion; - private final int mDisplayRotation; + private final NavBarPosition mNavBarPosition; private final Consumer mOnCompleteCallback; private final MotionPauseDetector mMotionPauseDetector; @@ -157,7 +155,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mInputConsumer = inputConsumer; mSwipeSharedState = swipeSharedState; - mDisplayRotation = getSystemService(WindowManager.class).getDefaultDisplay().getRotation(); + mNavBarPosition = new NavBarPosition(base); mDragSlop = QuickStepContract.getQuickStepDragSlopPx(); float slop = QuickStepContract.getQuickStepTouchSlopPx(); mSquaredTouchSlop = slop * slop; @@ -188,9 +186,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC if (mPassedDragSlop && mInteractionHandler != null && !mRecentsViewDispatcher.hasConsumer()) { mRecentsViewDispatcher.setConsumer(mInteractionHandler.getRecentsViewDispatcher( - isNavBarOnLeft() - ? ROTATION_SEASCAPE - : (isNavBarOnRight() ? ROTATION_LANDSCAPE : RotationMode.NORMAL))); + mNavBarPosition.getRotationMode())); } int edgeFlags = ev.getEdgeFlags(); ev.setEdgeFlags(edgeFlags | EDGE_NAV_BAR); @@ -329,14 +325,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mInteractionHandler.onGestureStarted(); } - private boolean isNavBarOnRight() { - return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_90; - } - - private boolean isNavBarOnLeft() { - return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_270; - } - private void startTouchTrackingForWindowAnimation(long touchTimeMs) { TOUCH_INTERACTION_LOG.addLog("startRecentsAnimation"); @@ -382,8 +370,8 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC ViewConfiguration.get(this).getScaledMaximumFlingVelocity()); float velocityX = mVelocityTracker.getXVelocity(mActivePointerId); float velocityY = mVelocityTracker.getYVelocity(mActivePointerId); - float velocity = isNavBarOnRight() ? velocityX - : isNavBarOnLeft() ? -velocityX + float velocity = mNavBarPosition.isRightEdge() ? velocityX + : mNavBarPosition.isLeftEdge() ? -velocityX : velocityY; mInteractionHandler.updateDisplacement(getDisplacement(ev) - mStartDisplacement); @@ -444,9 +432,9 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC } private float getDisplacement(MotionEvent ev) { - if (isNavBarOnRight()) { + if (mNavBarPosition.isRightEdge()) { return ev.getX() - mDownPos.x; - } else if (isNavBarOnLeft()) { + } else if (mNavBarPosition.isLeftEdge()) { return mDownPos.x - ev.getX(); } else { return ev.getY() - mDownPos.y; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java index bab3c71c60..4851e67e9d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java @@ -51,7 +51,7 @@ public class OverviewInputConsumer private final boolean mStartingInActivityBounds; private boolean mTargetHandledTouch; - OverviewInputConsumer(T activity, @Nullable InputMonitorCompat inputMonitor, + public OverviewInputConsumer(T activity, @Nullable InputMonitorCompat inputMonitor, boolean startingInActivityBounds) { mActivity = activity; mInputMonitor = inputMonitor; @@ -115,12 +115,12 @@ public class OverviewInputConsumer } } - public static InputConsumer newInstance(ActivityControlHelper activityHelper, - @Nullable InputMonitorCompat inputMonitor, boolean startingInActivityBounds) { + public static InputConsumer newInstanceWithinActivityBounds( + ActivityControlHelper activityHelper) { BaseDraggingActivity activity = activityHelper.getCreatedActivity(); if (activity == null) { return InputConsumer.NO_OP; } - return new OverviewInputConsumer(activity, inputMonitor, startingInActivityBounds); + return new OverviewInputConsumer(activity, null, true); } } \ No newline at end of file diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java new file mode 100644 index 0000000000..425b8b6b0b --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.quickstep.inputconsumers; + +import static android.view.MotionEvent.ACTION_CANCEL; +import static android.view.MotionEvent.ACTION_DOWN; +import static android.view.MotionEvent.ACTION_MOVE; +import static android.view.MotionEvent.ACTION_UP; + +import static com.android.launcher3.Utilities.squaredHypot; +import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG; +import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; + +import android.content.Context; +import android.graphics.PointF; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.ViewConfiguration; + +import com.android.launcher3.Utilities; +import com.android.quickstep.OverviewCallbacks; +import com.android.quickstep.util.NavBarPosition; +import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.InputMonitorCompat; + +public class OverviewWithoutFocusInputConsumer implements InputConsumer { + + private final InputMonitorCompat mInputMonitor; + private final boolean mDisableHorizontalSwipe; + private final PointF mDownPos = new PointF(); + private final float mSquaredTouchSlop; + private final Context mContext; + private final NavBarPosition mNavBarPosition; + + private boolean mInterceptedTouch; + private VelocityTracker mVelocityTracker; + + + public OverviewWithoutFocusInputConsumer(Context context, InputMonitorCompat inputMonitor, + boolean disableHorizontalSwipe) { + mInputMonitor = inputMonitor; + mDisableHorizontalSwipe = disableHorizontalSwipe; + mContext = context; + mSquaredTouchSlop = Utilities.squaredTouchSlop(context); + mNavBarPosition = new NavBarPosition(context); + + mVelocityTracker = VelocityTracker.obtain(); + } + + @Override + public int getType() { + return TYPE_OVERVIEW_WITHOUT_FOCUS; + } + + @Override + public boolean allowInterceptByParent() { + return !mInterceptedTouch; + } + + private void endTouchTracking() { + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + } + + @Override + public void onMotionEvent(MotionEvent ev) { + if (mVelocityTracker == null) { + return; + } + + mVelocityTracker.addMovement(ev); + switch (ev.getActionMasked()) { + case ACTION_DOWN: { + mDownPos.set(ev.getX(), ev.getY()); + break; + } + case ACTION_MOVE: { + if (!mInterceptedTouch) { + float displacementX = ev.getX() - mDownPos.x; + float displacementY = ev.getY() - mDownPos.y; + if (squaredHypot(displacementX, displacementY) >= mSquaredTouchSlop) { + if (mDisableHorizontalSwipe + && Math.abs(displacementX) > Math.abs(displacementY)) { + // Horizontal gesture is not allowed in this region + endTouchTracking(); + break; + } + + mInterceptedTouch = true; + + if (mInputMonitor != null) { + mInputMonitor.pilferPointers(); + } + } + } + break; + } + + case ACTION_CANCEL: + endTouchTracking(); + break; + + case ACTION_UP: { + finishTouchTracking(ev); + endTouchTracking(); + break; + } + } + } + + private void finishTouchTracking(MotionEvent ev) { + mVelocityTracker.computeCurrentVelocity(100); + float velocityX = mVelocityTracker.getXVelocity(); + float velocityY = mVelocityTracker.getYVelocity(); + float velocity = mNavBarPosition.isRightEdge() + ? -velocityX : (mNavBarPosition.isLeftEdge() ? velocityX : -velocityY); + + final boolean triggerQuickstep; + if (Math.abs(velocity) >= ViewConfiguration.get(mContext).getScaledMinimumFlingVelocity()) { + triggerQuickstep = velocity > 0; + } else { + float displacementX = mDisableHorizontalSwipe ? 0 : (ev.getX() - mDownPos.x); + float displacementY = ev.getY() - mDownPos.y; + triggerQuickstep = squaredHypot(displacementX, displacementY) >= mSquaredTouchSlop; + } + + if (triggerQuickstep) { + OverviewCallbacks.get(mContext).closeAllWindows(); + ActivityManagerWrapper.getInstance() + .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); + TOUCH_INTERACTION_LOG.addLog("startQuickstep"); + } else { + // ignore + } + } +} diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/NavBarPosition.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/NavBarPosition.java new file mode 100644 index 0000000000..3ce341d8cf --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/NavBarPosition.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.quickstep.util; + +import static com.android.launcher3.uioverrides.RecentsUiFactory.ROTATION_LANDSCAPE; +import static com.android.launcher3.uioverrides.RecentsUiFactory.ROTATION_SEASCAPE; +import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; + +import android.content.Context; +import android.view.Surface; +import android.view.WindowManager; + +import com.android.launcher3.graphics.RotationMode; +import com.android.quickstep.SysUINavigationMode; + +/** + * Utility class to check nav bar position + */ +public class NavBarPosition { + + private final SysUINavigationMode.Mode mMode; + private final int mDisplayRotation; + + public NavBarPosition(Context context) { + mMode = SysUINavigationMode.getMode(context); + mDisplayRotation = context.getSystemService(WindowManager.class) + .getDefaultDisplay().getRotation(); + } + + public boolean isRightEdge() { + return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_90; + } + + public boolean isLeftEdge() { + return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_270; + } + + public RotationMode getRotationMode() { + return isLeftEdge() ? ROTATION_SEASCAPE + : (isRightEdge() ? ROTATION_LANDSCAPE : RotationMode.NORMAL); + } +}