diff --git a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java index 1064492000..a4851ba964 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java @@ -17,6 +17,7 @@ package com.android.launcher3.uioverrides; import static com.android.launcher3.LauncherAnimUtils.ALL_APPS_TRANSITION_MS; import static com.android.launcher3.allapps.DiscoveryBounce.APPS_VIEW_SHOWN; +import static com.android.launcher3.anim.Interpolators.DEACCEL_2; import android.view.View; @@ -33,6 +34,13 @@ public class AllAppsState extends LauncherState { private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY; + private static final PageAlphaProvider PAGE_ALPHA_PROVIDER = new PageAlphaProvider(DEACCEL_2) { + @Override + public float getPageAlpha(int pageIndex) { + return 0; + } + }; + public AllAppsState(int id) { super(id, ContainerType.ALLAPPS, ALL_APPS_TRANSITION_MS, 0f, STATE_FLAGS); } @@ -65,6 +73,6 @@ public class AllAppsState extends LauncherState { @Override public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) { - return (i) -> 0; + return PAGE_ALPHA_PROVIDER; } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeUpController.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeUpController.java new file mode 100644 index 0000000000..92f89f6a1e --- /dev/null +++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeUpController.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2017 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.OVERVIEW; + +import android.view.MotionEvent; + +import com.android.launcher3.Launcher; +import com.android.launcher3.touch.SwipeDetector; +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; + +/** + * Extension of {@link VerticalSwipeController} which allows swipe up from OVERVIEW to ALL_APPS + * Note that the swipe down is handled by {@link TwoStepSwipeController}. + */ +public class OverviewSwipeUpController extends VerticalSwipeController { + + public OverviewSwipeUpController(Launcher l) { + super(l, OVERVIEW); + } + + @Override + protected boolean shouldInterceptTouch(MotionEvent ev) { + return mLauncher.isInState(OVERVIEW) && mLauncher.getDragLayer().isEventOverHotseat(ev); + } + + @Override + protected int getSwipeDirection(MotionEvent ev) { + return SwipeDetector.DIRECTION_POSITIVE; + } + + @Override + protected void onTransitionComplete(boolean wasFling, boolean stateChanged) { + if (stateChanged) { + // Transition complete. log the action + mLauncher.getUserEventDispatcher().logActionOnContainer( + wasFling ? Touch.FLING : Touch.SWIPE, + Direction.UP, + ContainerType.OVERVIEW, + mLauncher.getWorkspace().getCurrentPage()); + } + + } +} diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java index 5e280b6963..9178d8ad42 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java @@ -30,7 +30,15 @@ import com.android.launcher3.widget.WidgetsFullSheet; public class UiFactory { public static TouchController[] createTouchControllers(Launcher launcher) { - return new TouchController[] {new TwoStepSwipeController(launcher)}; + + if (launcher.getDeviceProfile().isVerticalBarLayout()) { + // TODO: Allow swipe up from overview in transposed layout + return new TouchController[] {new TwoStepSwipeController(launcher)}; + } else { + return new TouchController[] { + new TwoStepSwipeController(launcher), + new OverviewSwipeUpController(launcher)}; + } } public static AccessibilityDelegate newPageIndicatorAccessibilityDelegate() { diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java index dfb935fd43..0a0bb85136 100644 --- a/src/com/android/launcher3/LauncherState.java +++ b/src/com/android/launcher3/LauncherState.java @@ -19,7 +19,10 @@ import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO; import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; +import static com.android.launcher3.anim.Interpolators.ACCEL_2; + import android.view.View; +import android.view.animation.Interpolator; import com.android.launcher3.uioverrides.AllAppsState; import com.android.launcher3.states.SpringLoadedState; @@ -41,7 +44,13 @@ public class LauncherState { protected static final int FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED = 1 << 4; protected static final int FLAG_DISABLE_PAGE_CLIPPING = 1 << 5; - protected static final PageAlphaProvider DEFAULT_ALPHA_PROVIDER = (i) -> 1f; + protected static final PageAlphaProvider DEFAULT_ALPHA_PROVIDER = + new PageAlphaProvider(ACCEL_2) { + @Override + public float getPageAlpha(int pageIndex) { + return 1; + } + }; private static final LauncherState[] sAllStates = new LauncherState[4]; @@ -149,16 +158,27 @@ public class LauncherState { if (this != NORMAL || !launcher.getDeviceProfile().shouldFadeAdjacentWorkspaceScreens()) { return DEFAULT_ALPHA_PROVIDER; } - int centerPage = launcher.getWorkspace().getPageNearestToCenterOfScreen(); - return (childIndex) -> childIndex != centerPage ? 0 : 1f; + final int centerPage = launcher.getWorkspace().getPageNearestToCenterOfScreen(); + return new PageAlphaProvider(ACCEL_2) { + @Override + public float getPageAlpha(int pageIndex) { + return pageIndex != centerPage ? 0 : 1f; + } + }; } protected static void dispatchWindowStateChanged(Launcher launcher) { launcher.getWindow().getDecorView().sendAccessibilityEvent(TYPE_WINDOW_STATE_CHANGED); } - public interface PageAlphaProvider { + public static abstract class PageAlphaProvider { - float getPageAlpha(int pageIndex); + public final Interpolator interpolator; + + public PageAlphaProvider(Interpolator interpolator) { + this.interpolator = interpolator; + } + + public abstract float getPageAlpha(int pageIndex); } } diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java index 9f76b6f962..a8a2b38b93 100644 --- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java +++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java @@ -153,7 +153,7 @@ public class WorkspaceStateTransitionAnimation { propertySetter.setInt(cl.getScrimBackground(), DRAWABLE_ALPHA, state.hasScrim ? 255 : 0, Interpolators.ZOOM_IN); propertySetter.setFloat(cl.getShortcutsAndWidgets(), View.ALPHA, - pageAlphaProvider.getPageAlpha(childIndex), Interpolators.DEACCEL_2); + pageAlphaProvider.getPageAlpha(childIndex), pageAlphaProvider.interpolator); } public static class PropertySetter { diff --git a/src/com/android/launcher3/VerticalSwipeController.java b/src/com/android/launcher3/util/VerticalSwipeController.java similarity index 76% rename from src/com/android/launcher3/VerticalSwipeController.java rename to src/com/android/launcher3/util/VerticalSwipeController.java index b3dc176b70..7b1632c6fb 100644 --- a/src/com/android/launcher3/VerticalSwipeController.java +++ b/src/com/android/launcher3/util/VerticalSwipeController.java @@ -14,10 +14,9 @@ * limitations under the License. */ -package com.android.launcher3; +package com.android.launcher3.util; import static com.android.launcher3.LauncherState.ALL_APPS; -import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity; import static com.android.launcher3.anim.SpringAnimationHandler.Y_DIRECTION; @@ -28,21 +27,22 @@ import android.support.animation.SpringAnimation; import android.util.Log; import android.view.MotionEvent; +import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherState; +import com.android.launcher3.Utilities; import com.android.launcher3.allapps.AllAppsContainerView; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.SpringAnimationHandler; import com.android.launcher3.touch.SwipeDetector; -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.TouchController; import java.util.ArrayList; /** - * Handles vertical touch gesture on the DragLayer + * Handles vertical touch gesture on the DragLayer allowing transitioning from + * {@link #mBaseState} to {@link LauncherState#ALL_APPS} and vice-versa. */ -public class VerticalSwipeController extends AnimatorListenerAdapter +public abstract class VerticalSwipeController extends AnimatorListenerAdapter implements TouchController, SwipeDetector.Listener { private static final String TAG = "VerticalSwipeController"; @@ -53,11 +53,11 @@ public class VerticalSwipeController extends AnimatorListenerAdapter // Progress after which the transition is assumed to be a success in case user does not fling private static final float SUCCESS_TRANSITION_PROGRESS = 0.5f; - private final Launcher mLauncher; + protected final Launcher mLauncher; private final SwipeDetector mDetector; + private final LauncherState mBaseState; private boolean mNoIntercept; - private int mStartContainerType; private AnimatorPlaybackController mCurrentAnimation; private LauncherState mToState; @@ -68,30 +68,25 @@ public class VerticalSwipeController extends AnimatorListenerAdapter private SpringAnimationHandler[] mSpringHandlers; - public VerticalSwipeController(Launcher l) { + public VerticalSwipeController(Launcher l, LauncherState baseState) { mLauncher = l; mDetector = new SwipeDetector(l, this, SwipeDetector.VERTICAL); + mBaseState = baseState; } 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 (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)) { - return false; - } if (AbstractFloatingView.getTopOpenView(mLauncher) != null) { return false; } - - return true; + return shouldInterceptTouch(ev); } + protected abstract boolean shouldInterceptTouch(MotionEvent ev); + @Override public void onAnimationCancel(Animator animation) { if (mCurrentAnimation != null && animation == mCurrentAnimation.getTarget()) { @@ -147,14 +142,7 @@ public class VerticalSwipeController extends AnimatorListenerAdapter ignoreSlopWhenSettling = true; } } else { - if (mLauncher.isInState(ALL_APPS)) { - directionsToDetectScroll = SwipeDetector.DIRECTION_NEGATIVE; - mStartContainerType = ContainerType.ALLAPPS; - } else { - directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE; - mStartContainerType = mLauncher.getDragLayer().isEventOverHotseat(ev) ? - ContainerType.HOTSEAT : ContainerType.WORKSPACE; - } + directionsToDetectScroll = getSwipeDirection(ev); } mDetector.setDetectableScrollConditions( @@ -173,6 +161,8 @@ public class VerticalSwipeController extends AnimatorListenerAdapter return mDetector.isDraggingOrSettling(); } + protected abstract int getSwipeDirection(MotionEvent ev); + @Override public boolean onControllerTouchEvent(MotionEvent ev) { for (SpringAnimationHandler h : mSpringHandlers) { @@ -188,7 +178,7 @@ public class VerticalSwipeController extends AnimatorListenerAdapter long maxAccuracy = (long) (2 * range); // Build current animation - mToState = mLauncher.isInState(ALL_APPS) ? NORMAL : ALL_APPS; + mToState = mLauncher.isInState(ALL_APPS) ? mBaseState : ALL_APPS; mCurrentAnimation = mLauncher.getStateManager() .createAnimationToNewWorkspace(mToState, maxAccuracy); mCurrentAnimation.getTarget().addListener(this); @@ -206,7 +196,7 @@ public class VerticalSwipeController extends AnimatorListenerAdapter } private float getShiftRange() { - return mLauncher.mAllAppsController.getShiftRange(); + return mLauncher.getAllAppsController().getShiftRange(); } @Override @@ -219,29 +209,26 @@ public class VerticalSwipeController extends AnimatorListenerAdapter @Override public void onDragEnd(float velocity, boolean fling) { final long animationDuration; - final int logAction; final LauncherState targetState; final float progress = mCurrentAnimation.getProgressFraction(); if (fling) { - logAction = Touch.FLING; if (velocity < 0) { targetState = ALL_APPS; animationDuration = SwipeDetector.calculateDuration(velocity, mToState == ALL_APPS ? (1 - progress) : progress); } else { - targetState = NORMAL; + targetState = mBaseState; animationDuration = SwipeDetector.calculateDuration(velocity, mToState == ALL_APPS ? progress : (1 - progress)); } // snap to top or bottom using the release velocity } else { - logAction = Touch.SWIPE; if (progress > SUCCESS_TRANSITION_PROGRESS) { targetState = mToState; animationDuration = SwipeDetector.calculateDuration(velocity, 1 - progress); } else { - targetState = mToState == ALL_APPS ? NORMAL : ALL_APPS; + targetState = mToState == ALL_APPS ? mBaseState : ALL_APPS; animationDuration = SwipeDetector.calculateDuration(velocity, progress); } } @@ -253,21 +240,11 @@ public class VerticalSwipeController extends AnimatorListenerAdapter } } - mCurrentAnimation.setEndAction(new Runnable() { - @Override - public void run() { - if (targetState == mToState) { - // Transition complete. log the action - mLauncher.getUserEventDispatcher().logActionOnContainer(logAction, - mToState == ALL_APPS ? Direction.UP : Direction.DOWN, - mStartContainerType, mLauncher.getWorkspace().getCurrentPage()); - } else { - mLauncher.getStateManager().goToState( - mToState == ALL_APPS ? NORMAL : ALL_APPS, false); - } - mDetector.finishedScrolling(); - mCurrentAnimation = null; - } + mCurrentAnimation.setEndAction(() -> { + mLauncher.getStateManager().goToState(targetState, false); + onTransitionComplete(fling, targetState == mToState); + mDetector.finishedScrolling(); + mCurrentAnimation = null; }); float nextFrameProgress = Utilities.boundToRange( @@ -279,4 +256,6 @@ public class VerticalSwipeController extends AnimatorListenerAdapter anim.setInterpolator(scrollInterpolatorForVelocity(velocity)); anim.start(); } + + protected abstract void onTransitionComplete(boolean wasFling, boolean stateChanged); } diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java index bd5ddfeaf1..d67156fef1 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java @@ -17,6 +17,7 @@ package com.android.launcher3.uioverrides; import static com.android.launcher3.LauncherAnimUtils.ALL_APPS_TRANSITION_MS; import static com.android.launcher3.allapps.DiscoveryBounce.APPS_VIEW_SHOWN; +import static com.android.launcher3.anim.Interpolators.DEACCEL_2; import android.view.View; @@ -34,6 +35,13 @@ public class AllAppsState extends LauncherState { private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY; + private static final PageAlphaProvider PAGE_ALPHA_PROVIDER = new PageAlphaProvider(DEACCEL_2) { + @Override + public float getPageAlpha(int pageIndex) { + return 0; + } + }; + public AllAppsState(int id) { super(id, ContainerType.ALLAPPS, ALL_APPS_TRANSITION_MS, 0f, STATE_FLAGS); } @@ -67,6 +75,6 @@ public class AllAppsState extends LauncherState { @Override public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) { - return (i) -> 0; + return PAGE_ALPHA_PROVIDER; } } diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java new file mode 100644 index 0000000000..76b7e0d81e --- /dev/null +++ b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2017 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.ALL_APPS; +import static com.android.launcher3.LauncherState.NORMAL; + +import android.view.MotionEvent; + +import com.android.launcher3.Launcher; +import com.android.launcher3.touch.SwipeDetector; +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; + +/** + * Extension of {@link VerticalSwipeController} to switch between NORMAL and ALL_APPS state. + */ +public class AllAppsSwipeController extends VerticalSwipeController { + + private int mStartContainerType; + + public AllAppsSwipeController(Launcher l) { + super(l, NORMAL); + } + + @Override + protected boolean shouldInterceptTouch(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 (mLauncher.isInState(ALL_APPS) && !mLauncher.getAppsView().shouldContainerScroll(ev)) { + return false; + } + return true; + } + + @Override + protected int getSwipeDirection(MotionEvent ev) { + if (mLauncher.isInState(ALL_APPS)) { + mStartContainerType = ContainerType.ALLAPPS; + return SwipeDetector.DIRECTION_NEGATIVE; + } else { + mStartContainerType = mLauncher.getDragLayer().isEventOverHotseat(ev) ? + ContainerType.HOTSEAT : ContainerType.WORKSPACE; + return SwipeDetector.DIRECTION_POSITIVE; + } + } + + @Override + protected void onTransitionComplete(boolean wasFling, boolean stateChanged) { + if (stateChanged) { + // Transition complete. log the action + mLauncher.getUserEventDispatcher().logActionOnContainer( + wasFling ? Touch.FLING : Touch.SWIPE, + mLauncher.isInState(ALL_APPS) ? Direction.UP : Direction.DOWN, + mStartContainerType, + mLauncher.getWorkspace().getCurrentPage()); + } + } +} diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java index 51cf6615dd..2e2901534a 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java @@ -22,14 +22,13 @@ import android.view.View.AccessibilityDelegate; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherStateManager.StateHandler; -import com.android.launcher3.VerticalSwipeController; import com.android.launcher3.util.TouchController; public class UiFactory { public static TouchController[] createTouchControllers(Launcher launcher) { return new TouchController[] { - new VerticalSwipeController(launcher), new PinchToOverviewListener(launcher)}; + new AllAppsSwipeController(launcher), new PinchToOverviewListener(launcher)}; } public static AccessibilityDelegate newPageIndicatorAccessibilityDelegate() {