Swipe up from nav bar in OVERVIEW or ALL_APPS to go home

Add NavBarToHomeTouchController, which intercepts touches from the nav bar
region when in overview or all apps.

Swiping up from all apps translates it up and slightly fades out app icons,
then letting go springs towards home screen.

Swiping up from overview translates it to the right, then letting go springs
towards the left where it lives in the home state.

Both cases have a strong deceleration while swiping.

Bug: 129571305
Bug: 111926330
Change-Id: I5b7de05f15f0300233343fa2d69fcad624e070f8
This commit is contained in:
Tony 2019-03-27 14:09:55 -05:00
parent 1ac6c84bda
commit e243a9493e
3 changed files with 146 additions and 2 deletions

View File

@ -30,6 +30,7 @@ import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.uioverrides.touchcontrollers.FlingAndHoldTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.LandscapeEdgeSwipeController;
import com.android.launcher3.uioverrides.touchcontrollers.NavBarToHomeTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.OverviewToAllAppsTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.StatusBarTouchController;
@ -64,6 +65,7 @@ public abstract class RecentsUiFactory {
list.add(launcher.getDragController());
if (mode == Mode.NO_BUTTON) {
list.add(new QuickSwitchTouchController(launcher));
list.add(new NavBarToHomeTouchController(launcher));
list.add(new FlingAndHoldTouchController(launcher));
} else {
if (launcher.getDeviceProfile().isVerticalBarLayout()) {

View File

@ -0,0 +1,141 @@
/*
* 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.touchcontrollers;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.touch.AbstractStateChangeTouchController;
import com.android.launcher3.touch.SwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.quickstep.views.RecentsView;
/**
* Handles swiping up on the nav bar to go home from overview or all apps.
*/
public class NavBarToHomeTouchController extends AbstractStateChangeTouchController {
private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL_3;
public NavBarToHomeTouchController(Launcher launcher) {
super(launcher, SwipeDetector.VERTICAL);
}
@Override
protected boolean canInterceptTouch(MotionEvent ev) {
boolean cameFromNavBar = (ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) != 0;
return cameFromNavBar && (mLauncher.isInState(OVERVIEW) || mLauncher.isInState(ALL_APPS));
}
@Override
protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
return isDragTowardPositive ? NORMAL : fromState;
}
@Override
protected float initCurrentAnimation(int animComponents) {
long accuracy = (long) (getShiftRange() * 2);
final AnimatorSet anim;
if (mFromState == OVERVIEW) {
anim = new AnimatorSet();
RecentsView recentsView = mLauncher.getOverviewPanel();
float pullbackDistance = recentsView.getPaddingStart() / 2;
if (!recentsView.isRtl()) {
pullbackDistance = -pullbackDistance;
}
anim.play(ObjectAnimator.ofFloat(recentsView, View.TRANSLATION_X, pullbackDistance));
anim.setInterpolator(PULLBACK_INTERPOLATOR);
} else { // if (mFromState == ALL_APPS)
AnimatorSetBuilder builder = new AnimatorSetBuilder();
AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
final float pullbackDistance = mLauncher.getDeviceProfile().allAppsIconSizePx / 2;
Animator allAppsProgress = ObjectAnimator.ofFloat(allAppsController, ALL_APPS_PROGRESS,
-pullbackDistance / allAppsController.getShiftRange());
allAppsProgress.setInterpolator(PULLBACK_INTERPOLATOR);
builder.play(allAppsProgress);
// Slightly fade out all apps content to further distinguish from scrolling.
builder.setInterpolator(AnimatorSetBuilder.ANIM_ALL_APPS_FADE, Interpolators
.mapToProgress(PULLBACK_INTERPOLATOR, 0, 0.5f));
AnimationConfig config = new AnimationConfig();
config.duration = accuracy;
allAppsController.setAlphas(mToState.getVisibleElements(mLauncher), config, builder);
anim = builder.build();
}
anim.setDuration(accuracy);
mCurrentAnimation = AnimatorPlaybackController.wrap(anim, accuracy, this::clearState);
return -1 / getShiftRange();
}
@Override
public void onDragStart(boolean start) {
super.onDragStart(start);
mStartContainerType = LauncherLogProto.ContainerType.NAVBAR;
}
@Override
public void onDragEnd(float velocity, boolean fling) {
final int logAction = fling ? Touch.FLING : Touch.SWIPE;
float interpolatedProgress = PULLBACK_INTERPOLATOR.getInterpolation(
mCurrentAnimation.getProgressFraction());
if (interpolatedProgress >= SUCCESS_TRANSITION_PROGRESS || velocity < 0 && fling) {
mLauncher.getStateManager().goToState(mToState, true,
() -> onSwipeInteractionCompleted(mToState, logAction));
} else {
// Quickly return to the state we came from (we didn't move far).
AnimatorPlaybackController anim = mLauncher.getStateManager()
.createAnimationToNewWorkspace(mFromState, 80);
anim.setEndAction(() -> onSwipeInteractionCompleted(mFromState, logAction));
anim.start();
}
mCurrentAnimation.dispatchOnCancel();
}
@Override
protected int getDirectionForLog() {
return LauncherLogProto.Action.Direction.UP;
}
@Override
protected boolean goingBetweenNormalAndOverview(LauncherState fromState,
LauncherState toState) {
// We don't want to create an atomic animation to/from overview.
return false;
}
@Override
protected int getLogContainerTypeForNormalState() {
return LauncherLogProto.ContainerType.NAVBAR;
}
}

View File

@ -224,7 +224,8 @@ public abstract class AbstractStateChangeTouchController
return true;
}
private boolean goingBetweenNormalAndOverview(LauncherState fromState, LauncherState toState) {
protected boolean goingBetweenNormalAndOverview(LauncherState fromState,
LauncherState toState) {
return (fromState == NORMAL || fromState == OVERVIEW)
&& (toState == NORMAL || toState == OVERVIEW)
&& mPendingAnimation == null;
@ -242,7 +243,7 @@ public abstract class AbstractStateChangeTouchController
mStartContainerType = LauncherLogProto.ContainerType.ALLAPPS;
} else if (mStartState == NORMAL) {
mStartContainerType = getLogContainerTypeForNormalState();
} else if (mStartState == OVERVIEW){
} else if (mStartState == OVERVIEW){
mStartContainerType = LauncherLogProto.ContainerType.TASKSWITCHER;
}
if (mCurrentAnimation == null) {