From 222a59e79a9e1c2c08972d5634d94444f15f3027 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Thu, 6 May 2021 23:15:42 -0700 Subject: [PATCH] Implement overshoot and squish motion in all apps open Bug: 187475924 Bug: 183062683 Test: manual Change-Id: I33b6c647c45ff467c6d49cf3796f92ca366ab3f1 --- res/values/dimens.xml | 2 +- src/com/android/launcher3/Launcher.java | 7 +--- .../allapps/AllAppsContainerView.java | 42 ++++++++++++++++--- .../allapps/AllAppsTransitionController.java | 10 ++--- .../AbstractStateChangeTouchController.java | 25 ++++++++--- .../launcher3/views/SpringRelativeLayout.java | 10 +++++ 6 files changed, 73 insertions(+), 23 deletions(-) diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 3267a5d246..65c4c806f3 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -84,7 +84,7 @@ -26dp - 300dp + 320dp 48dp 30dp 40dp diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 5ecdca6dfc..7b67807697 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -905,7 +905,7 @@ public class Launcher extends StatefulActivity implements Launche } else { mOverlayManager.onActivityStopped(this); } - + hideKeyboard(); logStopAndResume(false /* isResume */); mAppWidgetHost.setActivityStarted(false); NotificationListener.removeNotificationsChangedListener(); @@ -1459,7 +1459,7 @@ public class Launcher extends StatefulActivity implements Launche && AbstractFloatingView.getTopOpenView(this) == null; boolean isActionMain = Intent.ACTION_MAIN.equals(intent.getAction()); boolean internalStateHandled = ACTIVITY_TRACKER.handleNewIntent(this, intent); - + hideKeyboard(); if (isActionMain) { if (!internalStateHandled) { // In all these cases, only animate if we're already on home @@ -1481,9 +1481,6 @@ public class Launcher extends StatefulActivity implements Launche } } - // Handle HOME_INTENT - hideKeyboard(); - if (mLauncherCallbacks != null) { mLauncherCallbacks.onHomeIntent(internalStateHandled); } diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 47236b6994..d9c8c96f40 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -45,6 +45,7 @@ import android.view.WindowInsets; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; +import androidx.annotation.VisibleForTesting; import androidx.core.graphics.ColorUtils; import androidx.core.os.BuildCompat; import androidx.recyclerview.widget.DefaultItemAnimator; @@ -79,10 +80,11 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo Insettable, OnDeviceProfileChangeListener, OnActivePageChangedListener, ScrimView.ScrimDrawingController { - private static final float FLING_VELOCITY_MULTIPLIER = 1000f; + public static final float PULL_MULTIPLIER = .02f; + public static final float FLING_VELOCITY_MULTIPLIER = 2000f; // Starts the springs after at least 25% of the animation has passed. - private static final float FLING_ANIMATION_THRESHOLD = 0.25f; + public static final float FLING_ANIMATION_THRESHOLD = 0.25f; private final Paint mHeaderPaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -100,6 +102,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo private AllAppsPagedView mViewPager; protected FloatingHeaderView mHeader; + private float mHeaderTop; private WorkModeSwitch mWorkModeSwitch; @@ -530,7 +533,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo return view.getGlobalVisibleRect(new Rect()); } - // Used by tests only + @VisibleForTesting public boolean isPersonalTabVisible() { return isDescendantViewVisible(R.id.tab_personal); } @@ -582,6 +585,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo mAH[i].padding.top = padding; mAH[i].applyPadding(); } + mHeaderTop = mHeader.getTop(); } public void setLastSearchQuery(String query) { @@ -636,14 +640,42 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo public void onAnimationUpdate(ValueAnimator valueAnimator) { if (shouldSpring && valueAnimator.getAnimatedFraction() >= FLING_ANIMATION_THRESHOLD) { - absorbSwipeUpVelocity(Math.abs( - Math.round(velocity * FLING_VELOCITY_MULTIPLIER))); + absorbSwipeUpVelocity(Math.max(100, Math.abs( + Math.round(velocity * FLING_VELOCITY_MULTIPLIER)))); + // calculate the velocity of using the not user controlled interpolator + // of when the container reach the end. shouldSpring = false; } } }); } + public void onPull(float deltaDistance, float displacement) { + absorbPullDeltaDistance(PULL_MULTIPLIER * deltaDistance, + PULL_MULTIPLIER * displacement); + // ideally, this should be done using EdgeEffect.onPush to create squish effect. + // However, until such method is available, launcher to simulate the onPush method. + mHeader.setTranslationY(-.5f * mHeaderTop * deltaDistance); + getRecyclerViewContainer().setTranslationY(-mHeaderTop * deltaDistance); + } + + public void onRelease() { + ValueAnimator anim1 = ValueAnimator.ofFloat(1f, 0f); + final float floatingHeaderHeight = getFloatingHeaderView().getTranslationY(); + final float recyclerViewHeight = getRecyclerViewContainer().getTranslationY(); + anim1.setDuration(200); + anim1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + getFloatingHeaderView().setTranslationY( + ((float) valueAnimator.getAnimatedValue()) * floatingHeaderHeight); + getRecyclerViewContainer().setTranslationY( + ((float) valueAnimator.getAnimatedValue()) * recyclerViewHeight); + } + }); + anim1.start(); + super.onRelease(); + } @Override public void getDrawingRect(Rect outRect) { super.getDrawingRect(outRect); diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index 90f2d7cde5..75f3149736 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -17,10 +17,7 @@ package com.android.launcher3.allapps; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT; -import static com.android.launcher3.anim.Interpolators.ACCEL_0_75; -import static com.android.launcher3.anim.Interpolators.ACCEL_2; -import static com.android.launcher3.anim.Interpolators.DEACCEL; -import static com.android.launcher3.anim.Interpolators.DEACCEL_2; +import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER; import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE; @@ -158,9 +155,8 @@ public class AllAppsTransitionController return; } - Interpolator interpolator = toState.equals(ALL_APPS) - ? (config.userControlled ? ACCEL_2 : ACCEL_0_75) : - (config.userControlled ? DEACCEL_2 : DEACCEL); + // need to decide depending on the release velocity + Interpolator interpolator = (config.userControlled ? LINEAR : DEACCEL_1_7); Animator anim = createSpringAnimation(mProgress, targetProgress); anim.setInterpolator(config.getInterpolator(ANIM_VERTICAL_PROGRESS, interpolator)); diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java index d092f11ae5..a086635d57 100644 --- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java @@ -56,9 +56,8 @@ public abstract class AbstractStateChangeTouchController protected final AnimatorListener mClearStateOnCancelListener = newCancelListener(this::clearState); + private final FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck(); - private boolean mNoIntercept; - private boolean mIsLogContainerSet; protected int mStartContainerType; protected LauncherState mStartState; @@ -67,12 +66,14 @@ public abstract class AbstractStateChangeTouchController protected AnimatorPlaybackController mCurrentAnimation; protected boolean mGoingBetweenStates = true; + private boolean mNoIntercept; + private boolean mIsLogContainerSet; private float mStartProgress; // Ratio of transition process [0, 1] to drag displacement (px) private float mProgressMultiplier; private float mDisplacementShift; private boolean mCanBlockFling; - private final FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck(); + private boolean mAllAppsOvershootStarted; public AbstractStateChangeTouchController(Launcher l, SingleAxisSwipeDetector.Direction dir) { mLauncher = l; @@ -216,8 +217,15 @@ public abstract class AbstractStateChangeTouchController mFlingBlockCheck.blockFling(); } } + if (mToState == LauncherState.ALL_APPS && !UNSTABLE_SPRINGS.get()) { + mAllAppsOvershootStarted = true; + // 1f, value when all apps container hit the top + mLauncher.getAppsView().onPull(progress - 1f, progress - 1f); + } + } else { mFlingBlockCheck.onEvent(); + } return true; @@ -325,8 +333,15 @@ public abstract class AbstractStateChangeTouchController anim.setFloatValues(startProgress, endProgress); updateSwipeCompleteAnimation(anim, duration, targetState, velocity, fling); mCurrentAnimation.dispatchOnStart(); - if (fling && targetState == LauncherState.ALL_APPS && !UNSTABLE_SPRINGS.get()) { - mLauncher.getAppsView().addSpringFromFlingUpdateListener(anim, velocity); + if (targetState == LauncherState.ALL_APPS && !UNSTABLE_SPRINGS.get()) { + if (mAllAppsOvershootStarted) { + + mLauncher.getAppsView().onRelease(); + mAllAppsOvershootStarted = false; + + } else { + mLauncher.getAppsView().addSpringFromFlingUpdateListener(anim, velocity); + } } anim.start(); } diff --git a/src/com/android/launcher3/views/SpringRelativeLayout.java b/src/com/android/launcher3/views/SpringRelativeLayout.java index 9701389f91..8342d3e9d2 100644 --- a/src/com/android/launcher3/views/SpringRelativeLayout.java +++ b/src/com/android/launcher3/views/SpringRelativeLayout.java @@ -32,6 +32,7 @@ import com.android.launcher3.Utilities; */ public class SpringRelativeLayout extends RelativeLayout { + // fixed edge at the time force is applied private final EdgeEffect mEdgeGlowTop; private final EdgeEffect mEdgeGlowBottom; @@ -87,6 +88,15 @@ public class SpringRelativeLayout extends RelativeLayout { invalidate(); } + protected void absorbPullDeltaDistance(float deltaDistance, float displacement) { + mEdgeGlowBottom.onPull(deltaDistance, displacement); + invalidate(); + } + + protected void onRelease() { + mEdgeGlowBottom.onRelease(); + } + public EdgeEffectFactory createEdgeEffectFactory() { return new ProxyEdgeEffectFactory(); }