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 0000000000..a3b41b02f2 --- /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 0000000000..eead4c8ba3 --- /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 330dc87ac3..ea0e55239e 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.launcher3.userevent.nano.LauncherLogProto.ContainerType; 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 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr */ 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 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr } 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 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr 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 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr } } + /** + * 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;