2019-03-27 14:09:55 -05:00
|
|
|
/*
|
|
|
|
|
* 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;
|
|
|
|
|
|
2020-06-18 13:40:33 -07:00
|
|
|
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
|
|
|
|
|
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL_APPS_EDU;
|
2019-03-27 14:09:55 -05:00
|
|
|
import static com.android.launcher3.LauncherState.ALL_APPS;
|
|
|
|
|
import static com.android.launcher3.LauncherState.NORMAL;
|
2020-07-17 13:06:57 -07:00
|
|
|
import static com.android.launcher3.LauncherState.OVERVIEW;
|
2019-03-27 14:09:55 -05:00
|
|
|
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
|
|
|
|
|
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
|
2020-06-18 13:40:33 -07:00
|
|
|
import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_EDU;
|
2019-11-04 00:33:32 -08:00
|
|
|
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
2020-06-19 02:58:53 -07:00
|
|
|
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_GESTURE;
|
2019-04-05 13:52:35 -07:00
|
|
|
import static com.android.launcher3.touch.AbstractStateChangeTouchController.SUCCESS_TRANSITION_PROGRESS;
|
2019-10-17 11:59:53 -07:00
|
|
|
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
|
2019-03-27 14:09:55 -05:00
|
|
|
|
2019-04-05 13:52:35 -07:00
|
|
|
import android.animation.ValueAnimator;
|
2020-05-12 09:51:24 -07:00
|
|
|
import android.util.Log;
|
2019-03-27 14:09:55 -05:00
|
|
|
import android.view.MotionEvent;
|
|
|
|
|
import android.view.animation.Interpolator;
|
|
|
|
|
|
2019-04-05 13:52:35 -07:00
|
|
|
import com.android.launcher3.AbstractFloatingView;
|
2019-03-27 14:09:55 -05:00
|
|
|
import com.android.launcher3.Launcher;
|
|
|
|
|
import com.android.launcher3.LauncherState;
|
2019-04-05 13:52:35 -07:00
|
|
|
import com.android.launcher3.R;
|
2019-03-27 14:09:55 -05:00
|
|
|
import com.android.launcher3.Utilities;
|
|
|
|
|
import com.android.launcher3.allapps.AllAppsTransitionController;
|
2019-04-05 13:52:35 -07:00
|
|
|
import com.android.launcher3.anim.AnimationSuccessListener;
|
2019-03-27 14:09:55 -05:00
|
|
|
import com.android.launcher3.anim.AnimatorPlaybackController;
|
|
|
|
|
import com.android.launcher3.anim.Interpolators;
|
2020-03-13 13:01:33 -07:00
|
|
|
import com.android.launcher3.anim.PendingAnimation;
|
2019-04-12 11:10:20 -07:00
|
|
|
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
2019-10-17 11:59:53 -07:00
|
|
|
import com.android.launcher3.config.FeatureFlags;
|
2020-07-17 13:06:57 -07:00
|
|
|
import com.android.launcher3.graphics.OverviewScrim;
|
2020-06-19 02:58:53 -07:00
|
|
|
import com.android.launcher3.logging.StatsLogManager;
|
2020-03-13 13:01:33 -07:00
|
|
|
import com.android.launcher3.states.StateAnimationConfig;
|
2020-05-12 09:51:24 -07:00
|
|
|
import com.android.launcher3.testing.TestProtocol;
|
2019-08-15 17:24:07 -07:00
|
|
|
import com.android.launcher3.touch.SingleAxisSwipeDetector;
|
2019-03-27 14:09:55 -05:00
|
|
|
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
|
|
|
|
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
|
2019-04-05 13:52:35 -07:00
|
|
|
import com.android.launcher3.util.TouchController;
|
2020-07-17 13:06:57 -07:00
|
|
|
import com.android.quickstep.util.AnimatorControllerWithResistance;
|
2019-10-17 11:59:53 -07:00
|
|
|
import com.android.quickstep.util.AssistantUtilities;
|
2020-07-17 13:06:57 -07:00
|
|
|
import com.android.quickstep.util.OverviewToHomeAnim;
|
2019-03-27 14:09:55 -05:00
|
|
|
import com.android.quickstep.views.RecentsView;
|
2019-10-17 11:59:53 -07:00
|
|
|
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
2019-03-27 14:09:55 -05:00
|
|
|
|
|
|
|
|
/**
|
2019-04-05 13:52:35 -07:00
|
|
|
* Handles swiping up on the nav bar to go home from launcher, e.g. overview or all apps.
|
2019-03-27 14:09:55 -05:00
|
|
|
*/
|
2019-08-15 17:24:07 -07:00
|
|
|
public class NavBarToHomeTouchController implements TouchController,
|
|
|
|
|
SingleAxisSwipeDetector.Listener {
|
2019-03-27 14:09:55 -05:00
|
|
|
|
|
|
|
|
private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL_3;
|
2020-08-12 13:28:24 -07:00
|
|
|
// The min amount of overview scrim we keep during the transition.
|
|
|
|
|
private static final float OVERVIEW_TO_HOME_SCRIM_MULTIPLIER = 0.5f;
|
2019-03-27 14:09:55 -05:00
|
|
|
|
2019-04-05 13:52:35 -07:00
|
|
|
private final Launcher mLauncher;
|
2019-08-15 17:24:07 -07:00
|
|
|
private final SingleAxisSwipeDetector mSwipeDetector;
|
2019-04-05 13:52:35 -07:00
|
|
|
private final float mPullbackDistance;
|
|
|
|
|
|
|
|
|
|
private boolean mNoIntercept;
|
|
|
|
|
private LauncherState mStartState;
|
|
|
|
|
private LauncherState mEndState = NORMAL;
|
|
|
|
|
private AnimatorPlaybackController mCurrentAnimation;
|
|
|
|
|
|
2019-03-27 14:09:55 -05:00
|
|
|
public NavBarToHomeTouchController(Launcher launcher) {
|
2019-04-05 13:52:35 -07:00
|
|
|
mLauncher = launcher;
|
2019-08-15 17:24:07 -07:00
|
|
|
mSwipeDetector = new SingleAxisSwipeDetector(mLauncher, this,
|
|
|
|
|
SingleAxisSwipeDetector.VERTICAL);
|
2019-04-05 13:52:35 -07:00
|
|
|
mPullbackDistance = mLauncher.getResources().getDimension(R.dimen.home_pullback_distance);
|
2019-03-27 14:09:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2019-04-05 13:52:35 -07:00
|
|
|
public final boolean onControllerInterceptTouchEvent(MotionEvent ev) {
|
|
|
|
|
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
|
|
|
|
mStartState = mLauncher.getStateManager().getState();
|
|
|
|
|
mNoIntercept = !canInterceptTouch(ev);
|
|
|
|
|
if (mNoIntercept) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-08-15 17:24:07 -07:00
|
|
|
mSwipeDetector.setDetectableScrollConditions(SingleAxisSwipeDetector.DIRECTION_POSITIVE,
|
|
|
|
|
false /* ignoreSlop */);
|
2019-04-05 13:52:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mNoIntercept) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onControllerTouchEvent(ev);
|
|
|
|
|
return mSwipeDetector.isDraggingOrSettling();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean canInterceptTouch(MotionEvent ev) {
|
2020-05-12 09:51:24 -07:00
|
|
|
if (TestProtocol.sDebugTracing) {
|
|
|
|
|
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "NavBarToHomeTouchController.canInterceptTouch "
|
|
|
|
|
+ ev);
|
|
|
|
|
}
|
2019-03-27 14:09:55 -05:00
|
|
|
boolean cameFromNavBar = (ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) != 0;
|
2019-04-05 13:52:35 -07:00
|
|
|
if (!cameFromNavBar) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-04-27 16:26:55 -07:00
|
|
|
if (mStartState.overviewUi || mStartState == ALL_APPS) {
|
2020-05-12 09:51:24 -07:00
|
|
|
if (TestProtocol.sDebugTracing) {
|
|
|
|
|
Log.d(TestProtocol.PAUSE_NOT_DETECTED,
|
|
|
|
|
"NavBarToHomeTouchController.canInterceptTouch true 1 "
|
|
|
|
|
+ mStartState.overviewUi + " " + (mStartState == ALL_APPS));
|
|
|
|
|
}
|
2019-04-05 13:52:35 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
2020-06-18 13:40:33 -07:00
|
|
|
int typeToClose = ENABLE_ALL_APPS_EDU.get() ? TYPE_ALL & ~TYPE_ALL_APPS_EDU : TYPE_ALL;
|
|
|
|
|
if (AbstractFloatingView.getTopOpenViewWithType(mLauncher, typeToClose) != null) {
|
2020-05-12 09:51:24 -07:00
|
|
|
if (TestProtocol.sDebugTracing) {
|
|
|
|
|
Log.d(TestProtocol.PAUSE_NOT_DETECTED,
|
|
|
|
|
"NavBarToHomeTouchController.canInterceptTouch true 2 "
|
2020-06-01 09:34:50 -07:00
|
|
|
+ AbstractFloatingView.getTopOpenView(mLauncher), new Exception());
|
2020-05-12 09:51:24 -07:00
|
|
|
}
|
2019-04-05 13:52:35 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
2019-10-17 11:59:53 -07:00
|
|
|
if (FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS.get()
|
|
|
|
|
&& AssistantUtilities.isExcludedAssistantRunning()) {
|
2020-05-12 09:51:24 -07:00
|
|
|
if (TestProtocol.sDebugTracing) {
|
|
|
|
|
Log.d(TestProtocol.PAUSE_NOT_DETECTED,
|
|
|
|
|
"NavBarToHomeTouchController.canInterceptTouch true 3");
|
|
|
|
|
}
|
2019-10-17 11:59:53 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
2019-04-05 13:52:35 -07:00
|
|
|
return false;
|
2019-03-27 14:09:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2019-04-05 13:52:35 -07:00
|
|
|
public final boolean onControllerTouchEvent(MotionEvent ev) {
|
|
|
|
|
return mSwipeDetector.onTouchEvent(ev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private float getShiftRange() {
|
|
|
|
|
return mLauncher.getDeviceProfile().heightPx;
|
2019-03-27 14:09:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2019-12-19 11:50:55 -08:00
|
|
|
public void onDragStart(boolean start, float startDisplacement) {
|
2019-04-05 13:52:35 -07:00
|
|
|
initCurrentAnimation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void initCurrentAnimation() {
|
2019-03-27 14:09:55 -05:00
|
|
|
long accuracy = (long) (getShiftRange() * 2);
|
2020-03-13 13:01:33 -07:00
|
|
|
final PendingAnimation builder = new PendingAnimation(accuracy);
|
2020-04-27 16:26:55 -07:00
|
|
|
if (mStartState.overviewUi) {
|
2019-03-27 14:09:55 -05:00
|
|
|
RecentsView recentsView = mLauncher.getOverviewPanel();
|
2020-07-17 13:06:57 -07:00
|
|
|
AnimatorControllerWithResistance.createRecentsResistanceFromOverviewAnim(mLauncher,
|
|
|
|
|
builder);
|
2020-08-12 13:28:24 -07:00
|
|
|
|
2020-07-17 13:06:57 -07:00
|
|
|
builder.setFloat(mLauncher.getDragLayer().getOverviewScrim(),
|
2020-08-12 13:28:24 -07:00
|
|
|
OverviewScrim.SCRIM_MULTIPLIER, OVERVIEW_TO_HOME_SCRIM_MULTIPLIER,
|
|
|
|
|
PULLBACK_INTERPOLATOR);
|
|
|
|
|
|
2019-11-04 00:33:32 -08:00
|
|
|
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
2020-07-20 14:17:13 -07:00
|
|
|
builder.addOnFrameCallback(recentsView::redrawLiveTile);
|
2019-11-04 00:33:32 -08:00
|
|
|
}
|
2019-04-05 13:52:35 -07:00
|
|
|
} else if (mStartState == ALL_APPS) {
|
2019-03-27 14:09:55 -05:00
|
|
|
AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
|
2020-03-13 13:01:33 -07:00
|
|
|
builder.setFloat(allAppsController, ALL_APPS_PROGRESS,
|
|
|
|
|
-mPullbackDistance / allAppsController.getShiftRange(), PULLBACK_INTERPOLATOR);
|
|
|
|
|
|
2019-03-27 14:09:55 -05:00
|
|
|
// Slightly fade out all apps content to further distinguish from scrolling.
|
2020-03-13 13:01:33 -07:00
|
|
|
StateAnimationConfig config = new StateAnimationConfig();
|
2019-03-27 14:09:55 -05:00
|
|
|
config.duration = accuracy;
|
2020-03-13 13:01:33 -07:00
|
|
|
config.setInterpolator(StateAnimationConfig.ANIM_ALL_APPS_FADE, Interpolators
|
|
|
|
|
.mapToProgress(PULLBACK_INTERPOLATOR, 0, 0.5f));
|
|
|
|
|
|
|
|
|
|
allAppsController.setAlphas(mEndState, config, builder);
|
2019-04-05 13:52:35 -07:00
|
|
|
}
|
|
|
|
|
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mLauncher);
|
|
|
|
|
if (topView != null) {
|
2020-03-13 13:01:33 -07:00
|
|
|
topView.addHintCloseAnim(mPullbackDistance, PULLBACK_INTERPOLATOR, builder);
|
2019-03-27 14:09:55 -05:00
|
|
|
}
|
2020-03-13 13:01:33 -07:00
|
|
|
mCurrentAnimation = builder.createPlaybackController()
|
2020-02-25 14:37:01 -08:00
|
|
|
.setOnCancelRunnable(this::clearState);
|
2019-04-05 13:52:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void clearState() {
|
|
|
|
|
mCurrentAnimation = null;
|
|
|
|
|
mSwipeDetector.finishedScrolling();
|
|
|
|
|
mSwipeDetector.setDetectableScrollConditions(0, false);
|
2019-03-27 14:09:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2019-04-05 13:52:35 -07:00
|
|
|
public boolean onDrag(float displacement) {
|
|
|
|
|
// Only allow swipe up.
|
|
|
|
|
displacement = Math.min(0, displacement);
|
|
|
|
|
float progress = Utilities.getProgress(displacement, 0, getShiftRange());
|
|
|
|
|
mCurrentAnimation.setPlayFraction(progress);
|
|
|
|
|
return true;
|
2019-03-27 14:09:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2019-08-15 17:24:07 -07:00
|
|
|
public void onDragEnd(float velocity) {
|
|
|
|
|
boolean fling = mSwipeDetector.isFling(velocity);
|
2019-03-27 14:09:55 -05:00
|
|
|
final int logAction = fling ? Touch.FLING : Touch.SWIPE;
|
2019-04-05 13:52:35 -07:00
|
|
|
float progress = mCurrentAnimation.getProgressFraction();
|
|
|
|
|
float interpolatedProgress = PULLBACK_INTERPOLATOR.getInterpolation(progress);
|
|
|
|
|
boolean success = interpolatedProgress >= SUCCESS_TRANSITION_PROGRESS
|
|
|
|
|
|| (velocity < 0 && fling);
|
|
|
|
|
if (success) {
|
2019-11-04 00:33:32 -08:00
|
|
|
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
|
|
|
|
RecentsView recentsView = mLauncher.getOverviewPanel();
|
|
|
|
|
recentsView.switchToScreenshot(null,
|
|
|
|
|
() -> recentsView.finishRecentsAnimation(true /* toRecents */, null));
|
|
|
|
|
}
|
2020-07-17 13:06:57 -07:00
|
|
|
if (mStartState == OVERVIEW) {
|
|
|
|
|
new OverviewToHomeAnim(mLauncher, () -> onSwipeInteractionCompleted(mEndState))
|
|
|
|
|
.animateWithVelocity(velocity);
|
|
|
|
|
} else {
|
|
|
|
|
mLauncher.getStateManager().goToState(mEndState, true,
|
|
|
|
|
() -> onSwipeInteractionCompleted(mEndState));
|
|
|
|
|
}
|
2019-04-05 13:52:35 -07:00
|
|
|
if (mStartState != mEndState) {
|
|
|
|
|
logStateChange(mStartState.containerType, logAction);
|
|
|
|
|
}
|
|
|
|
|
AbstractFloatingView topOpenView = AbstractFloatingView.getTopOpenView(mLauncher);
|
|
|
|
|
if (topOpenView != null) {
|
|
|
|
|
AbstractFloatingView.closeAllOpenViews(mLauncher);
|
|
|
|
|
logStateChange(topOpenView.getLogContainerType(), logAction);
|
|
|
|
|
}
|
2019-10-17 11:59:53 -07:00
|
|
|
ActivityManagerWrapper.getInstance()
|
|
|
|
|
.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
|
2019-03-27 14:09:55 -05:00
|
|
|
} else {
|
|
|
|
|
// Quickly return to the state we came from (we didn't move far).
|
2019-04-05 13:52:35 -07:00
|
|
|
ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
|
|
|
|
|
anim.setFloatValues(progress, 0);
|
2020-03-06 15:16:22 -08:00
|
|
|
anim.addListener(AnimationSuccessListener.forRunnable(
|
|
|
|
|
() -> onSwipeInteractionCompleted(mStartState)));
|
2019-04-05 13:52:35 -07:00
|
|
|
anim.setDuration(80).start();
|
2019-03-27 14:09:55 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-05 13:52:35 -07:00
|
|
|
private void onSwipeInteractionCompleted(LauncherState targetState) {
|
|
|
|
|
clearState();
|
|
|
|
|
mLauncher.getStateManager().goToState(targetState, false /* animated */);
|
2019-04-12 11:10:20 -07:00
|
|
|
AccessibilityManagerCompat.sendStateEventToTest(mLauncher, targetState.ordinal);
|
2019-03-27 14:09:55 -05:00
|
|
|
}
|
|
|
|
|
|
2019-04-05 13:52:35 -07:00
|
|
|
private void logStateChange(int startContainerType, int logAction) {
|
|
|
|
|
mLauncher.getUserEventDispatcher().logStateChangeAction(logAction,
|
|
|
|
|
LauncherLogProto.Action.Direction.UP,
|
2019-04-24 11:32:20 -07:00
|
|
|
mSwipeDetector.getDownX(), mSwipeDetector.getDownY(),
|
2019-04-05 13:52:35 -07:00
|
|
|
LauncherLogProto.ContainerType.NAVBAR,
|
|
|
|
|
startContainerType,
|
|
|
|
|
mEndState.containerType,
|
|
|
|
|
mLauncher.getWorkspace().getCurrentPage());
|
2020-06-19 02:58:53 -07:00
|
|
|
mLauncher.getStatsLogManager().logger()
|
|
|
|
|
.withSrcState(StatsLogManager.containerTypeToAtomState(mStartState.containerType))
|
|
|
|
|
.withDstState(StatsLogManager.containerTypeToAtomState(mEndState.containerType))
|
|
|
|
|
.log(LAUNCHER_HOME_GESTURE);
|
2019-03-27 14:09:55 -05:00
|
|
|
}
|
|
|
|
|
}
|