mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-03-01 16:26:47 +00:00
This reverts commit a75f576890.
Reason for revert: b/187887269
Bug: 187887269
Change-Id: I8a56ff7054e71cf30b113fdaa213397dae0c53cb
263 lines
11 KiB
Java
263 lines
11 KiB
Java
/*
|
|
* Copyright (C) 2020 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.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
|
|
import static com.android.launcher3.LauncherAnimUtils.newCancelListener;
|
|
import static com.android.launcher3.LauncherState.HINT_STATE;
|
|
import static com.android.launcher3.LauncherState.NORMAL;
|
|
import static com.android.launcher3.LauncherState.OVERVIEW;
|
|
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
|
|
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
|
|
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
|
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
|
|
|
|
import android.animation.ObjectAnimator;
|
|
import android.animation.ValueAnimator;
|
|
import android.graphics.PointF;
|
|
import android.view.MotionEvent;
|
|
import android.view.ViewConfiguration;
|
|
|
|
import com.android.launcher3.Launcher;
|
|
import com.android.launcher3.LauncherState;
|
|
import com.android.launcher3.Utilities;
|
|
import com.android.launcher3.anim.AnimatorPlaybackController;
|
|
import com.android.launcher3.states.StateAnimationConfig;
|
|
import com.android.launcher3.util.VibratorWrapper;
|
|
import com.android.quickstep.SystemUiProxy;
|
|
import com.android.quickstep.util.AnimatorControllerWithResistance;
|
|
import com.android.quickstep.util.MotionPauseDetector;
|
|
import com.android.quickstep.util.OverviewToHomeAnim;
|
|
import com.android.quickstep.views.RecentsView;
|
|
|
|
/**
|
|
* Touch controller which handles swipe and hold from the nav bar to go to Overview. Swiping above
|
|
* the nav bar falls back to go to All Apps. Swiping from the nav bar without holding goes to the
|
|
* first home screen instead of to Overview.
|
|
*/
|
|
public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouchController {
|
|
|
|
|
|
// How much of the movement to use for translating overview after swipe and hold.
|
|
private static final float OVERVIEW_MOVEMENT_FACTOR = 0.25f;
|
|
private static final long TRANSLATION_ANIM_MIN_DURATION_MS = 80;
|
|
private static final float TRANSLATION_ANIM_VELOCITY_DP_PER_MS = 0.8f;
|
|
|
|
private final RecentsView mRecentsView;
|
|
private final MotionPauseDetector mMotionPauseDetector;
|
|
private final float mMotionPauseMinDisplacement;
|
|
|
|
private boolean mDidTouchStartInNavBar;
|
|
private boolean mStartedOverview;
|
|
private boolean mReachedOverview;
|
|
// The last recorded displacement before we reached overview.
|
|
private PointF mStartDisplacement = new PointF();
|
|
private float mStartY;
|
|
private AnimatorPlaybackController mOverviewResistYAnim;
|
|
|
|
// Normal to Hint animation has flag SKIP_OVERVIEW, so we update this scrim with this animator.
|
|
private ObjectAnimator mNormalToHintOverviewScrimAnimator;
|
|
|
|
public NoButtonNavbarToOverviewTouchController(Launcher l) {
|
|
super(l);
|
|
mRecentsView = l.getOverviewPanel();
|
|
mMotionPauseDetector = new MotionPauseDetector(l);
|
|
mMotionPauseMinDisplacement = ViewConfiguration.get(l).getScaledTouchSlop();
|
|
}
|
|
|
|
@Override
|
|
protected boolean canInterceptTouch(MotionEvent ev) {
|
|
mDidTouchStartInNavBar = (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
|
|
return super.canInterceptTouch(ev);
|
|
}
|
|
|
|
@Override
|
|
protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
|
|
if (fromState == NORMAL && mDidTouchStartInNavBar) {
|
|
return HINT_STATE;
|
|
} else if (fromState == OVERVIEW && isDragTowardPositive) {
|
|
// Don't allow swiping up to all apps.
|
|
return OVERVIEW;
|
|
}
|
|
return super.getTargetState(fromState, isDragTowardPositive);
|
|
}
|
|
|
|
@Override
|
|
protected float initCurrentAnimation() {
|
|
float progressMultiplier = super.initCurrentAnimation();
|
|
if (mToState == HINT_STATE) {
|
|
// Track the drag across the entire height of the screen.
|
|
progressMultiplier = -1f / mLauncher.getDeviceProfile().heightPx;
|
|
}
|
|
return progressMultiplier;
|
|
}
|
|
|
|
@Override
|
|
public void onDragStart(boolean start, float startDisplacement) {
|
|
super.onDragStart(start, startDisplacement);
|
|
|
|
mMotionPauseDetector.clear();
|
|
|
|
if (handlingOverviewAnim()) {
|
|
mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseDetected);
|
|
}
|
|
|
|
if (mFromState == NORMAL && mToState == HINT_STATE) {
|
|
mNormalToHintOverviewScrimAnimator = ObjectAnimator.ofArgb(
|
|
mLauncher.getScrimView(),
|
|
VIEW_BACKGROUND_COLOR,
|
|
mFromState.getWorkspaceScrimColor(mLauncher),
|
|
mToState.getWorkspaceScrimColor(mLauncher));
|
|
}
|
|
mStartedOverview = false;
|
|
mReachedOverview = false;
|
|
mOverviewResistYAnim = null;
|
|
}
|
|
|
|
@Override
|
|
protected void updateProgress(float fraction) {
|
|
super.updateProgress(fraction);
|
|
if (mNormalToHintOverviewScrimAnimator != null) {
|
|
mNormalToHintOverviewScrimAnimator.setCurrentFraction(fraction);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onDragEnd(float velocity) {
|
|
if (mStartedOverview) {
|
|
goToOverviewOrHomeOnDragEnd(velocity);
|
|
} else {
|
|
super.onDragEnd(velocity);
|
|
}
|
|
|
|
mMotionPauseDetector.clear();
|
|
mNormalToHintOverviewScrimAnimator = null;
|
|
if (mLauncher.isInState(OVERVIEW)) {
|
|
// Normally we would cleanup the state based on mCurrentAnimation, but since we stop
|
|
// using that when we pause to go to Overview, we need to clean up ourselves.
|
|
clearState();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void updateSwipeCompleteAnimation(ValueAnimator animator, long expectedDuration,
|
|
LauncherState targetState, float velocity, boolean isFling) {
|
|
super.updateSwipeCompleteAnimation(animator, expectedDuration, targetState, velocity,
|
|
isFling);
|
|
if (targetState == HINT_STATE) {
|
|
// Normally we compute the duration based on the velocity and distance to the given
|
|
// state, but since the hint state tracks the entire screen without a clear endpoint, we
|
|
// need to manually set the duration to a reasonable value.
|
|
animator.setDuration(HINT_STATE.getTransitionDuration(mLauncher));
|
|
}
|
|
}
|
|
|
|
private void onMotionPauseDetected() {
|
|
if (mCurrentAnimation == null) {
|
|
return;
|
|
}
|
|
mNormalToHintOverviewScrimAnimator = null;
|
|
mCurrentAnimation.getTarget().addListener(newCancelListener(() ->
|
|
mLauncher.getStateManager().goToState(OVERVIEW, true, () -> {
|
|
mOverviewResistYAnim = AnimatorControllerWithResistance
|
|
.createRecentsResistanceFromOverviewAnim(mLauncher, null)
|
|
.createPlaybackController();
|
|
mReachedOverview = true;
|
|
maybeSwipeInteractionToOverviewComplete();
|
|
})));
|
|
|
|
mCurrentAnimation.getTarget().removeListener(mClearStateOnCancelListener);
|
|
mCurrentAnimation.dispatchOnCancel();
|
|
mStartedOverview = true;
|
|
VibratorWrapper.INSTANCE.get(mLauncher).vibrate(OVERVIEW_HAPTIC);
|
|
}
|
|
|
|
private void maybeSwipeInteractionToOverviewComplete() {
|
|
if (mReachedOverview && !mDetector.isDraggingState()) {
|
|
onSwipeInteractionCompleted(OVERVIEW);
|
|
}
|
|
}
|
|
|
|
private boolean handlingOverviewAnim() {
|
|
int stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags();
|
|
return mDidTouchStartInNavBar && mStartState == NORMAL
|
|
&& (stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0;
|
|
}
|
|
|
|
@Override
|
|
public boolean onDrag(float yDisplacement, float xDisplacement, MotionEvent event) {
|
|
if (mStartedOverview) {
|
|
if (!mReachedOverview) {
|
|
mStartDisplacement.set(xDisplacement, yDisplacement);
|
|
mStartY = event.getY();
|
|
} else {
|
|
mRecentsView.setTranslationX((xDisplacement - mStartDisplacement.x)
|
|
* OVERVIEW_MOVEMENT_FACTOR);
|
|
float yProgress = (mStartDisplacement.y - yDisplacement) / mStartY;
|
|
if (yProgress > 0 && mOverviewResistYAnim != null) {
|
|
mOverviewResistYAnim.setPlayFraction(yProgress);
|
|
} else {
|
|
mRecentsView.setTranslationY((yDisplacement - mStartDisplacement.y)
|
|
* OVERVIEW_MOVEMENT_FACTOR);
|
|
}
|
|
}
|
|
}
|
|
|
|
float upDisplacement = -yDisplacement;
|
|
mMotionPauseDetector.setDisallowPause(!handlingOverviewAnim()
|
|
|| upDisplacement < mMotionPauseMinDisplacement);
|
|
mMotionPauseDetector.addPosition(event);
|
|
|
|
// Stay in Overview.
|
|
return mStartedOverview || super.onDrag(yDisplacement, xDisplacement, event);
|
|
}
|
|
|
|
private void goToOverviewOrHomeOnDragEnd(float velocity) {
|
|
boolean goToHomeInsteadOfOverview = !mMotionPauseDetector.isPaused();
|
|
if (goToHomeInsteadOfOverview) {
|
|
new OverviewToHomeAnim(mLauncher, () -> onSwipeInteractionCompleted(NORMAL))
|
|
.animateWithVelocity(velocity);
|
|
}
|
|
if (mReachedOverview) {
|
|
float distanceDp = dpiFromPx(Math.max(
|
|
Math.abs(mRecentsView.getTranslationX()),
|
|
Math.abs(mRecentsView.getTranslationY())));
|
|
long duration = (long) Math.max(TRANSLATION_ANIM_MIN_DURATION_MS,
|
|
distanceDp / TRANSLATION_ANIM_VELOCITY_DP_PER_MS);
|
|
mRecentsView.animate()
|
|
.translationX(0)
|
|
.translationY(0)
|
|
.setInterpolator(ACCEL_DEACCEL)
|
|
.setDuration(duration)
|
|
.withEndAction(goToHomeInsteadOfOverview
|
|
? null
|
|
: this::maybeSwipeInteractionToOverviewComplete);
|
|
if (!goToHomeInsteadOfOverview) {
|
|
// Return to normal properties for the overview state.
|
|
StateAnimationConfig config = new StateAnimationConfig();
|
|
config.duration = duration;
|
|
LauncherState state = mLauncher.getStateManager().getState();
|
|
mLauncher.getStateManager().createAtomicAnimation(state, state, config).start();
|
|
}
|
|
}
|
|
}
|
|
|
|
private float dpiFromPx(float pixels) {
|
|
return Utilities.dpiFromPx(pixels, mLauncher.getResources().getDisplayMetrics().densityDpi);
|
|
}
|
|
}
|