Adding feature to support two different swipe targets from all-apps and overview
Change-Id: I7e7b4abbcebcbd6de43805c57ee40b0edd5ba5aa
diff --git a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
new file mode 100644
index 0000000..c1b26d4
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2018 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.launcher3.uioverrides;
+
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.touch.SwipeDetector.DIRECTION_NEGATIVE;
+import static com.android.launcher3.touch.SwipeDetector.DIRECTION_POSITIVE;
+import static com.android.launcher3.touch.SwipeDetector.HORIZONTAL;
+import static com.android.launcher3.touch.SwipeDetector.VERTICAL;
+import static com.android.quickstep.TouchInteractionService.EDGE_NAV_BAR;
+
+import android.graphics.Rect;
+import android.view.MotionEvent;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.anim.SpringAnimationHandler;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.util.VerticalSwipeController;
+import com.android.quickstep.RecentsView;
+
+/**
+ * Extension of {@link VerticalSwipeController} to go from NORMAL to OVERVIEW.
+ */
+public class EdgeSwipeController extends VerticalSwipeController {
+
+ private final Rect mTempRect = new Rect();
+
+ public EdgeSwipeController(Launcher l) {
+ super(l, NORMAL, OVERVIEW, l.getDeviceProfile().isVerticalBarLayout()
+ ? HORIZONTAL : VERTICAL);
+ }
+
+ @Override
+ protected boolean shouldInterceptTouch(MotionEvent ev) {
+ return mLauncher.isInState(NORMAL) && (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
+ }
+
+ @Override
+ protected int getSwipeDirection(MotionEvent ev) {
+ return isTransitionFlipped() ? DIRECTION_NEGATIVE : DIRECTION_POSITIVE;
+ }
+
+ @Override
+ protected boolean isTransitionFlipped() {
+ if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+ Rect insets = mLauncher.getDragLayer().getInsets();
+ return insets.left > insets.right;
+ }
+ return false;
+ }
+
+ @Override
+ protected void onTransitionComplete(boolean wasFling, boolean stateChanged) {
+ // TODO: Log something
+ }
+
+ @Override
+ protected void initSprings() {
+ mSpringHandlers = new SpringAnimationHandler[0];
+ }
+
+ @Override
+ protected float getShiftRange() {
+ RecentsView.getPageRect(mLauncher, mTempRect);
+ DragLayer dl = mLauncher.getDragLayer();
+ Rect insets = dl.getInsets();
+
+ if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+ if (insets.left > insets.right) {
+ return insets.left + mTempRect.left;
+ } else {
+ return dl.getWidth() - mTempRect.right + insets.right;
+ }
+ } else {
+ return dl.getHeight() - mTempRect.bottom + insets.bottom;
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
index f59f0de..bdae2d6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
import static com.android.launcher3.anim.SpringAnimationHandler.Y_DIRECTION;
+import static com.android.quickstep.TouchInteractionService.EDGE_NAV_BAR;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -42,6 +43,7 @@
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.SpringAnimationHandler;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.touch.SwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
@@ -90,6 +92,7 @@
private static final int FLAG_OVERVIEW_DISABLED_CANCEL_STATE = 1 << 2;
private static final int FLAG_RECENTS_PLAN_LOADING = 1 << 3;
private static final int FLAG_OVERVIEW_DISABLED = 1 << 4;
+ private static final int FLAG_DISABLED_TWO_TARGETS = 1 << 5;
private final Launcher mLauncher;
private final SwipeDetector mDetector;
@@ -120,18 +123,25 @@
}
private boolean canInterceptTouch(MotionEvent ev) {
- if (!mLauncher.isInState(NORMAL) && !mLauncher.isInState(ALL_APPS)) {
- // Don't listen for the swipe gesture if we are already in some other state.
- return false;
- }
- if (mAnimatingToOverview) {
- return false;
- }
if (mCurrentAnimation != null) {
// If we are already animating from a previous state, we can intercept.
return true;
}
- if (mLauncher.isInState(ALL_APPS) && !mLauncher.getAppsView().shouldContainerScroll(ev)) {
+ if (mLauncher.isInState(NORMAL)) {
+ if ((ev.getEdgeFlags() & EDGE_NAV_BAR) != 0 &&
+ !mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+ // On normal swipes ignore edge swipes
+ return false;
+ }
+ } else if (mLauncher.isInState(ALL_APPS)) {
+ if (!mLauncher.getAppsView().shouldContainerScroll(ev)) {
+ return false;
+ }
+ } else {
+ // Don't listen for the swipe gesture if we are already in some other state.
+ return false;
+ }
+ if (mAnimatingToOverview) {
return false;
}
if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
@@ -237,6 +247,10 @@
mDragPauseDetector = new DragPauseDetector(this::onDragPauseDetected);
mDragPauseDetector.addDisabledFlags(FLAG_OVERVIEW_DISABLED_OUT_OF_RANGE);
+ if (FeatureFlags.ENABLE_TWO_SWIPE_TARGETS) {
+ mDragPauseDetector.addDisabledFlags(FLAG_DISABLED_TWO_TARGETS);
+ }
+
mOverviewProgressRange = new FloatRange();
mOverviewProgressRange.start = mLauncher.isInState(NORMAL)
? MIN_PROGRESS_TO_OVERVIEW
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index 05bd171..bd443aa 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -37,9 +37,16 @@
public static final boolean USE_HARDWARE_BITMAP = false; // FeatureFlags.IS_DOGFOOD_BUILD;
public static TouchController[] createTouchControllers(Launcher launcher) {
- return new TouchController[] {
- new TwoStepSwipeController(launcher),
- new OverviewSwipeUpController(launcher)};
+ if (FeatureFlags.ENABLE_TWO_SWIPE_TARGETS) {
+ return new TouchController[]{
+ new EdgeSwipeController(launcher),
+ new TwoStepSwipeController(launcher),
+ new OverviewSwipeUpController(launcher)};
+ } else {
+ return new TouchController[]{
+ new TwoStepSwipeController(launcher),
+ new OverviewSwipeUpController(launcher)};
+ }
}
public static AccessibilityDelegate newPageIndicatorAccessibilityDelegate() {
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 4321791..c72fbf4 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -64,6 +64,8 @@
@TargetApi(Build.VERSION_CODES.O)
public class TouchInteractionService extends Service {
+ public static final int EDGE_NAV_BAR = 1 << 8;
+
private static final String TAG = "TouchInteractionService";
private final IBinder mMyBinder = new IOverviewProxy.Stub() {
@@ -381,9 +383,12 @@
}
private void sendEvent(MotionEvent ev) {
+ int flags = ev.getEdgeFlags();
+ ev.setEdgeFlags(flags | EDGE_NAV_BAR);
ev.offsetLocation(-mLocationOnScreen[0], -mLocationOnScreen[1]);
mTarget.dispatchTouchEvent(ev);
ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
+ ev.setEdgeFlags(flags);
}
}
}
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 18797a4..2d0e630 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -57,4 +57,6 @@
public static final boolean ALL_APPS_TABS_ENABLED = true;
// When enabled prediction row is rendered as it's own custom view
public static final boolean ALL_APPS_PREDICTION_ROW_VIEW = true;
+
+ public static final boolean ENABLE_TWO_SWIPE_TARGETS = true;
}
diff --git a/src/com/android/launcher3/util/VerticalSwipeController.java b/src/com/android/launcher3/util/VerticalSwipeController.java
index 7b1632c..5d47cd2 100644
--- a/src/com/android/launcher3/util/VerticalSwipeController.java
+++ b/src/com/android/launcher3/util/VerticalSwipeController.java
@@ -35,6 +35,7 @@
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.touch.SwipeDetector;
+import com.android.launcher3.touch.SwipeDetector.Direction;
import java.util.ArrayList;
@@ -56,6 +57,7 @@
protected final Launcher mLauncher;
private final SwipeDetector mDetector;
private final LauncherState mBaseState;
+ private final LauncherState mTargetState;
private boolean mNoIntercept;
@@ -66,12 +68,18 @@
// Ratio of transition process [0, 1] to drag displacement (px)
private float mProgressMultiplier;
- private SpringAnimationHandler[] mSpringHandlers;
+ protected SpringAnimationHandler[] mSpringHandlers;
public VerticalSwipeController(Launcher l, LauncherState baseState) {
+ this(l, baseState, ALL_APPS, SwipeDetector.VERTICAL);
+ }
+
+ public VerticalSwipeController(
+ Launcher l, LauncherState baseState, LauncherState targetState, Direction dir) {
mLauncher = l;
- mDetector = new SwipeDetector(l, this, SwipeDetector.VERTICAL);
+ mDetector = new SwipeDetector(l, this, dir);
mBaseState = baseState;
+ mTargetState = targetState;
}
private boolean canInterceptTouch(MotionEvent ev) {
@@ -96,7 +104,7 @@
}
}
- private void initSprings() {
+ protected void initSprings() {
AllAppsContainerView appsView = mLauncher.getAppsView();
SpringAnimationHandler handler = appsView.getSpringAnimationHandler();
@@ -178,12 +186,13 @@
long maxAccuracy = (long) (2 * range);
// Build current animation
- mToState = mLauncher.isInState(ALL_APPS) ? mBaseState : ALL_APPS;
+ mToState = mLauncher.isInState(mTargetState) ? mBaseState : mTargetState;
mCurrentAnimation = mLauncher.getStateManager()
.createAnimationToNewWorkspace(mToState, maxAccuracy);
mCurrentAnimation.getTarget().addListener(this);
mStartProgress = 0;
- mProgressMultiplier = (mLauncher.isInState(ALL_APPS) ? 1 : -1) / range;
+ mProgressMultiplier =
+ (mLauncher.isInState(mTargetState) ^ isTransitionFlipped() ? 1 : -1) / range;
mCurrentAnimation.dispatchOnStart();
} else {
mCurrentAnimation.pause();
@@ -195,7 +204,11 @@
}
}
- private float getShiftRange() {
+ protected boolean isTransitionFlipped() {
+ return false;
+ }
+
+ protected float getShiftRange() {
return mLauncher.getAllAppsController().getShiftRange();
}
@@ -213,27 +226,25 @@
final float progress = mCurrentAnimation.getProgressFraction();
if (fling) {
- if (velocity < 0) {
- targetState = ALL_APPS;
- animationDuration = SwipeDetector.calculateDuration(velocity,
- mToState == ALL_APPS ? (1 - progress) : progress);
+ if (velocity < 0 ^ isTransitionFlipped()) {
+ targetState = mTargetState;
} else {
targetState = mBaseState;
- animationDuration = SwipeDetector.calculateDuration(velocity,
- mToState == ALL_APPS ? progress : (1 - progress));
}
+ animationDuration = SwipeDetector.calculateDuration(velocity,
+ mToState == targetState ? (1 - progress) : progress);
// snap to top or bottom using the release velocity
} else {
if (progress > SUCCESS_TRANSITION_PROGRESS) {
targetState = mToState;
animationDuration = SwipeDetector.calculateDuration(velocity, 1 - progress);
} else {
- targetState = mToState == ALL_APPS ? mBaseState : ALL_APPS;
+ targetState = mToState == mTargetState ? mBaseState : mTargetState;
animationDuration = SwipeDetector.calculateDuration(velocity, progress);
}
}
- if (fling && targetState == ALL_APPS) {
+ if (fling && targetState == mTargetState) {
for (SpringAnimationHandler h : mSpringHandlers) {
// The icons are moving upwards, so we go to 0 from 1. (y-axis 1 is below 0.)
h.animateToFinalPosition(0 /* pos */, 1 /* startValue */);