Merge "Split PortraitOverviewStateTouchHelper for Go" into ub-launcher3-master
diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/PortraitOverviewStateTouchHelper.java b/go/quickstep/src/com/android/launcher3/uioverrides/PortraitOverviewStateTouchHelper.java
new file mode 100644
index 0000000..a3b41b0
--- /dev/null
+++ b/go/quickstep/src/com/android/launcher3/uioverrides/PortraitOverviewStateTouchHelper.java
@@ -0,0 +1,65 @@
+/*
+ * 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.launcher3.uioverrides;
+
+import android.view.MotionEvent;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.util.PendingAnimation;
+
+/**
+ * Helper class for {@link PortraitStatesTouchController} that determines swipeable regions and
+ * animations on the overview state that depend on the recents implementation.
+ */
+public final class PortraitOverviewStateTouchHelper {
+
+    public PortraitOverviewStateTouchHelper(Launcher launcher) {}
+
+    /**
+     * Whether or not {@link PortraitStatesTouchController} should intercept the touch when on the
+     * overview state.
+     *
+     * @param ev the motion event
+     * @return true if we should intercept the motion event
+     */
+    boolean canInterceptTouch(MotionEvent ev) {
+        // Go does not support swiping to all-apps from recents.
+        return false;
+    }
+
+    /**
+     * Whether or not swiping down to leave overview state should return to the currently running
+     * task app.
+     *
+     * @return true if going back should take the user to the currently running task
+     */
+    boolean shouldSwipeDownReturnToApp() {
+        // Go does not support swiping tasks down to launch tasks from recents.
+        return false;
+    }
+
+    /**
+     * Create the animation for going from overview to the task app via swiping.
+     *
+     * @param duration how long the animation should be
+     * @return the animation
+     */
+    PendingAnimation createSwipeDownToTaskAppAnimation(long duration) {
+        // Go does not support swiping tasks down to launch tasks from recents.
+        return null;
+    }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PortraitOverviewStateTouchHelper.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PortraitOverviewStateTouchHelper.java
new file mode 100644
index 0000000..eead4c8
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PortraitOverviewStateTouchHelper.java
@@ -0,0 +1,84 @@
+/*
+ * 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.launcher3.uioverrides;
+
+import static com.android.launcher3.uioverrides.PortraitStatesTouchController.isTouchOverHotseat;
+
+import android.view.MotionEvent;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.util.PendingAnimation;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
+
+/**
+ * Helper class for {@link PortraitStatesTouchController} that determines swipeable regions and
+ * animations on the overview state that depend on the recents implementation.
+ */
+public final class PortraitOverviewStateTouchHelper {
+
+    RecentsView mRecentsView;
+    Launcher mLauncher;
+
+    public PortraitOverviewStateTouchHelper(Launcher launcher) {
+        mLauncher = launcher;
+        mRecentsView = launcher.getOverviewPanel();
+    }
+
+    /**
+     * Whether or not {@link PortraitStatesTouchController} should intercept the touch when on the
+     * overview state.
+     *
+     * @param ev the motion event
+     * @return true if we should intercept the motion event
+     */
+    boolean canInterceptTouch(MotionEvent ev) {
+        if (mRecentsView.getChildCount() > 0) {
+            // Allow swiping up in the gap between the hotseat and overview.
+            return ev.getY() >= mRecentsView.getChildAt(0).getBottom();
+        } else {
+            // If there are no tasks, we only intercept if we're below the hotseat height.
+            return isTouchOverHotseat(mLauncher, ev);
+        }
+    }
+
+    /**
+     * Whether or not swiping down to leave overview state should return to the currently running
+     * task app.
+     *
+     * @return true if going back should take the user to the currently running task
+     */
+    boolean shouldSwipeDownReturnToApp() {
+        TaskView taskView = mRecentsView.getTaskViewAt(mRecentsView.getNextPage());
+        return taskView != null && mRecentsView.shouldSwipeDownLaunchApp();
+    }
+
+    /**
+     * Create the animation for going from overview to the task app via swiping. Should only be
+     * called when {@link #shouldSwipeDownReturnToApp()} returns true.
+     *
+     * @param duration how long the animation should be
+     * @return the animation
+     */
+    PendingAnimation createSwipeDownToTaskAppAnimation(long duration) {
+        TaskView taskView = mRecentsView.getTaskViewAt(mRecentsView.getNextPage());
+        if (taskView == null) {
+            throw new IllegalStateException("There is no task view to animate to.");
+        }
+        return mRecentsView.createTaskLauncherAnimation(taskView, duration);
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
index 330dc87..ea0e552 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
@@ -47,8 +47,6 @@
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.TouchInteractionService;
 import com.android.quickstep.util.LayoutUtils;
-import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.TaskView;
 
 /**
  * Touch controller for handling various state transitions in portrait UI.
@@ -67,14 +65,16 @@
      */
     private static final float RECENTS_FADE_THRESHOLD = 0.88f;
 
+    private final PortraitOverviewStateTouchHelper mOverviewPortraitStateTouchHelper;
+
     private InterpolatorWrapper mAllAppsInterpolatorWrapper = new InterpolatorWrapper();
 
     // If true, we will finish the current animation instantly on second touch.
     private boolean mFinishFastOnSecondTouch;
 
-
     public PortraitStatesTouchController(Launcher l) {
         super(l, SwipeDetector.VERTICAL);
+        mOverviewPortraitStateTouchHelper = new PortraitOverviewStateTouchHelper(l);
     }
 
     @Override
@@ -98,22 +98,18 @@
             }
             return false;
         }
-        RecentsView recentsView = mLauncher.getOverviewPanel();
         if (mLauncher.isInState(ALL_APPS)) {
             // In all-apps only listen if the container cannot scroll itself
             if (!mLauncher.getAppsView().shouldContainerScroll(ev)) {
                 return false;
             }
-        } else if (mLauncher.isInState(OVERVIEW) && recentsView.getChildCount() > 0) {
-            // Allow swiping up in the gap between the hotseat and overview.
-            if (ev.getY() < recentsView.getChildAt(0).getBottom()) {
+        } else if (mLauncher.isInState(OVERVIEW)) {
+            if (!mOverviewPortraitStateTouchHelper.canInterceptTouch(ev)) {
                 return false;
             }
         } else {
             // For all other states, only listen if the event originated below the hotseat height
-            DeviceProfile dp = mLauncher.getDeviceProfile();
-            int hotseatHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
-            if (ev.getY() < (mLauncher.getDragLayer().getHeight() - hotseatHeight)) {
+            if (!isTouchOverHotseat(mLauncher, ev)) {
                 return false;
             }
         }
@@ -197,13 +193,12 @@
 
         cancelPendingAnim();
 
-        RecentsView recentsView = mLauncher.getOverviewPanel();
-        TaskView taskView = recentsView.getTaskViewAt(recentsView.getNextPage());
-        if (recentsView.shouldSwipeDownLaunchApp() && mFromState == OVERVIEW && mToState == NORMAL
-                && taskView != null) {
+        if (mFromState == OVERVIEW && mToState == NORMAL
+                && mOverviewPortraitStateTouchHelper.shouldSwipeDownReturnToApp()) {
             // Reset the state manager, when changing the interaction mode
             mLauncher.getStateManager().goToState(OVERVIEW, false /* animate */);
-            mPendingAnimation = recentsView.createTaskLauncherAnimation(taskView, maxAccuracy);
+            mPendingAnimation = mOverviewPortraitStateTouchHelper
+                    .createSwipeDownToTaskAppAnimation(maxAccuracy);
             mPendingAnimation.anim.setInterpolator(Interpolators.LINEAR);
 
             Runnable onCancelRunnable = () -> {
@@ -269,6 +264,19 @@
         }
     }
 
+    /**
+     * Whether the motion event is over the hotseat.
+     *
+     * @param launcher the launcher activity
+     * @param ev the event to check
+     * @return true if the event is over the hotseat
+     */
+    static boolean isTouchOverHotseat(Launcher launcher, MotionEvent ev) {
+        DeviceProfile dp = launcher.getDeviceProfile();
+        int hotseatHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
+        return (ev.getY() >= (launcher.getDragLayer().getHeight() - hotseatHeight));
+    }
+
     private static class InterpolatorWrapper implements Interpolator {
 
         public TimeInterpolator baseInterpolator = LINEAR;