Loading quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java +18 −21 Original line number Original line Diff line number Diff line Loading @@ -21,16 +21,17 @@ import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelo import android.animation.Animator; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.animation.ValueAnimator; import android.util.Log; import android.view.MotionEvent; import android.view.MotionEvent; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.Utilities; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.touch.SwipeDetector; import com.android.launcher3.touch.SwipeDetector; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.util.FlingBlockCheck; import com.android.launcher3.util.PendingAnimation; import com.android.launcher3.util.PendingAnimation; import com.android.launcher3.util.TouchController; import com.android.launcher3.util.TouchController; import com.android.launcher3.views.BaseDragLayer; import com.android.launcher3.views.BaseDragLayer; Loading @@ -46,8 +47,6 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> private static final String TAG = "OverviewSwipeController"; private static final String TAG = "OverviewSwipeController"; private static final float ALLOWED_FLING_DIRECTION_CHANGE_PROGRESS = 0.1f; // Progress after which the transition is assumed to be a success in case user does not fling // 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 static final float SUCCESS_TRANSITION_PROGRESS = 0.5f; Loading @@ -65,6 +64,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> private float mDisplacementShift; private float mDisplacementShift; private float mProgressMultiplier; private float mProgressMultiplier; private float mEndDisplacement; private float mEndDisplacement; private FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck(); private TaskView mTaskBeingDragged; private TaskView mTaskBeingDragged; Loading Loading @@ -93,7 +93,6 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> @Override @Override public void onAnimationCancel(Animator animation) { public void onAnimationCancel(Animator animation) { if (mCurrentAnimation != null && animation == mCurrentAnimation.getTarget()) { if (mCurrentAnimation != null && animation == mCurrentAnimation.getTarget()) { Log.e(TAG, "Who dare cancel the animation when I am in control", new Exception()); clearState(); clearState(); } } } } Loading Loading @@ -158,16 +157,16 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> return mDetector.onTouchEvent(ev); return mDetector.onTouchEvent(ev); } } private boolean reInitAnimationController(boolean goingUp) { private void reInitAnimationController(boolean goingUp) { if (mCurrentAnimation != null && mCurrentAnimationIsGoingUp == goingUp) { if (mCurrentAnimation != null && mCurrentAnimationIsGoingUp == goingUp) { // No need to init // No need to init return false; return; } } int scrollDirections = mDetector.getScrollDirections(); int scrollDirections = mDetector.getScrollDirections(); if (goingUp && ((scrollDirections & SwipeDetector.DIRECTION_POSITIVE) == 0) if (goingUp && ((scrollDirections & SwipeDetector.DIRECTION_POSITIVE) == 0) || !goingUp && ((scrollDirections & SwipeDetector.DIRECTION_NEGATIVE) == 0)) { || !goingUp && ((scrollDirections & SwipeDetector.DIRECTION_NEGATIVE) == 0)) { // Trying to re-init in an unsupported direction. // Trying to re-init in an unsupported direction. return false; return; } } if (mCurrentAnimation != null) { if (mCurrentAnimation != null) { mCurrentAnimation.setPlayFraction(0); mCurrentAnimation.setPlayFraction(0); Loading Loading @@ -205,7 +204,6 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> mCurrentAnimation.getTarget().addListener(this); mCurrentAnimation.getTarget().addListener(this); mCurrentAnimation.dispatchOnStart(); mCurrentAnimation.dispatchOnStart(); mProgressMultiplier = 1 / mEndDisplacement; mProgressMultiplier = 1 / mEndDisplacement; return true; } } @Override @Override Loading @@ -217,6 +215,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> mDisplacementShift = mCurrentAnimation.getProgressFraction() / mProgressMultiplier; mDisplacementShift = mCurrentAnimation.getProgressFraction() / mProgressMultiplier; mCurrentAnimation.pause(); mCurrentAnimation.pause(); } } mFlingBlockCheck.unblockFling(); } } @Override @Override Loading @@ -226,6 +225,9 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> totalDisplacement == 0 ? mCurrentAnimationIsGoingUp : totalDisplacement < 0; totalDisplacement == 0 ? mCurrentAnimationIsGoingUp : totalDisplacement < 0; if (isGoingUp != mCurrentAnimationIsGoingUp) { if (isGoingUp != mCurrentAnimationIsGoingUp) { reInitAnimationController(isGoingUp); reInitAnimationController(isGoingUp); mFlingBlockCheck.blockFling(); } else { mFlingBlockCheck.onEvent(); } } mCurrentAnimation.setPlayFraction(totalDisplacement * mProgressMultiplier); mCurrentAnimation.setPlayFraction(totalDisplacement * mProgressMultiplier); return true; return true; Loading @@ -235,22 +237,14 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> public void onDragEnd(float velocity, boolean fling) { public void onDragEnd(float velocity, boolean fling) { final boolean goingToEnd; final boolean goingToEnd; final int logAction; final int logAction; boolean blockedFling = fling && mFlingBlockCheck.isBlocked(); if (blockedFling) { fling = false; } if (fling) { if (fling) { logAction = Touch.FLING; logAction = Touch.FLING; boolean goingUp = velocity < 0; boolean goingUp = velocity < 0; if (goingUp != mCurrentAnimationIsGoingUp) { goingToEnd = goingUp == mCurrentAnimationIsGoingUp; // In case the fling is in opposite direction, make sure if is close enough // from the start position if (mCurrentAnimation.getProgressFraction() >= ALLOWED_FLING_DIRECTION_CHANGE_PROGRESS) { // Not allowed goingToEnd = false; } else { goingToEnd = reInitAnimationController(goingUp); } } else { goingToEnd = true; } } else { } else { logAction = Touch.SWIPE; logAction = Touch.SWIPE; goingToEnd = mCurrentAnimation.getProgressFraction() > SUCCESS_TRANSITION_PROGRESS; goingToEnd = mCurrentAnimation.getProgressFraction() > SUCCESS_TRANSITION_PROGRESS; Loading @@ -259,6 +253,9 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> float progress = mCurrentAnimation.getProgressFraction(); float progress = mCurrentAnimation.getProgressFraction(); long animationDuration = SwipeDetector.calculateDuration( long animationDuration = SwipeDetector.calculateDuration( velocity, goingToEnd ? (1 - progress) : progress); velocity, goingToEnd ? (1 - progress) : progress); if (blockedFling && !goingToEnd) { animationDuration *= LauncherAnimUtils.blockedFlingDurationFactor(velocity); } float nextFrameProgress = Utilities.boundToRange( float nextFrameProgress = Utilities.boundToRange( progress + velocity * SINGLE_FRAME_MS / Math.abs(mEndDisplacement), 0f, 1f); progress + velocity * SINGLE_FRAME_MS / Math.abs(mEndDisplacement), 0f, 1f); Loading quickstep/src/com/android/quickstep/LongSwipeHelper.java +18 −2 Original line number Original line Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ */ package com.android.quickstep; package com.android.quickstep; import static com.android.launcher3.LauncherAnimUtils.MIN_PROGRESS_TO_ALL_APPS; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL; Loading @@ -26,6 +27,7 @@ import android.animation.ValueAnimator; import android.view.Surface; import android.view.Surface; import com.android.launcher3.Launcher; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.R; import com.android.launcher3.R; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.allapps.DiscoveryBounce; Loading @@ -33,7 +35,9 @@ import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; 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.Action.Touch; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.util.FlingBlockCheck; import com.android.quickstep.util.RemoteAnimationTargetSet; import com.android.quickstep.util.RemoteAnimationTargetSet; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.TransactionCompat; import com.android.systemui.shared.system.TransactionCompat; Loading @@ -44,7 +48,6 @@ import com.android.systemui.shared.system.TransactionCompat; */ */ public class LongSwipeHelper { public class LongSwipeHelper { private static final float MIN_PROGRESS_TO_ALL_APPS = 0.35f; private static final float SWIPE_DURATION_MULTIPLIER = private static final float SWIPE_DURATION_MULTIPLIER = Math.min(1 / MIN_PROGRESS_TO_ALL_APPS, 1 / (1 - MIN_PROGRESS_TO_ALL_APPS)); Math.min(1 / MIN_PROGRESS_TO_ALL_APPS, 1 / (1 - MIN_PROGRESS_TO_ALL_APPS)); Loading @@ -53,6 +56,7 @@ public class LongSwipeHelper { private float mMaxSwipeDistance = 1; private float mMaxSwipeDistance = 1; private AnimatorPlaybackController mAnimator; private AnimatorPlaybackController mAnimator; private FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck(); LongSwipeHelper(Launcher launcher, RemoteAnimationTargetSet targetSet) { LongSwipeHelper(Launcher launcher, RemoteAnimationTargetSet targetSet) { mLauncher = launcher; mLauncher = launcher; Loading @@ -62,6 +66,7 @@ public class LongSwipeHelper { private void init() { private void init() { setTargetAlpha(0, true); setTargetAlpha(0, true); mFlingBlockCheck.blockFling(); // Init animations // Init animations AllAppsTransitionController controller = mLauncher.getAllAppsController(); AllAppsTransitionController controller = mLauncher.getAllAppsController(); Loading @@ -74,6 +79,7 @@ public class LongSwipeHelper { public void onMove(float displacement) { public void onMove(float displacement) { mAnimator.setPlayFraction(displacement / mMaxSwipeDistance); mAnimator.setPlayFraction(displacement / mMaxSwipeDistance); mFlingBlockCheck.onEvent(); } } public void destroy() { public void destroy() { Loading @@ -90,6 +96,11 @@ public class LongSwipeHelper { final boolean toAllApps; final boolean toAllApps; float endProgress; float endProgress; boolean blockedFling = isFling && mFlingBlockCheck.isBlocked(); if (blockedFling) { isFling = false; } if (!isFling) { if (!isFling) { toAllApps = currentFraction > MIN_PROGRESS_TO_ALL_APPS; toAllApps = currentFraction > MIN_PROGRESS_TO_ALL_APPS; endProgress = toAllApps ? 1 : 0; endProgress = toAllApps ? 1 : 0; Loading @@ -114,7 +125,11 @@ public class LongSwipeHelper { } } } } mAnimator.setEndAction(() -> onSwipeAnimationComplete(toAllApps, isFling, callback)); if (blockedFling && !toAllApps) { duration *= LauncherAnimUtils.blockedFlingDurationFactor(0); } final boolean finalIsFling = isFling; mAnimator.setEndAction(() -> onSwipeAnimationComplete(toAllApps, finalIsFling, callback)); ValueAnimator animator = mAnimator.getAnimationPlayer(); ValueAnimator animator = mAnimator.getAnimationPlayer(); animator.setDuration(duration).setInterpolator(DEACCEL); animator.setDuration(duration).setInterpolator(DEACCEL); animator.setFloatValues(currentFraction, endProgress); animator.setFloatValues(currentFraction, endProgress); Loading Loading @@ -150,6 +165,7 @@ public class LongSwipeHelper { mLauncher.getStateManager().goToState(toAllApps ? ALL_APPS : OVERVIEW, false); mLauncher.getStateManager().goToState(toAllApps ? ALL_APPS : OVERVIEW, false); if (!toAllApps) { if (!toAllApps) { DiscoveryBounce.showForOverviewIfNeeded(mLauncher); DiscoveryBounce.showForOverviewIfNeeded(mLauncher); mLauncher.<RecentsView>getOverviewPanel().setSwipeDownShouldLaunchApp(true); } } mLauncher.getUserEventDispatcher().logStateChangeAction( mLauncher.getUserEventDispatcher().logStateChangeAction( Loading src/com/android/launcher3/LauncherAnimUtils.java +7 −12 Original line number Original line Diff line number Diff line Loading @@ -39,6 +39,9 @@ public class LauncherAnimUtils { public static final int SPRING_LOADED_TRANSITION_MS = 150; public static final int SPRING_LOADED_TRANSITION_MS = 150; public static final int SPRING_LOADED_EXIT_DELAY = 500; public static final int SPRING_LOADED_EXIT_DELAY = 500; // The progress of an animation to all apps must be at least this far along to snap to all apps. public static final float MIN_PROGRESS_TO_ALL_APPS = 0.5f; static WeakHashMap<Animator, Object> sAnimators = new WeakHashMap<Animator, Object>(); static WeakHashMap<Animator, Object> sAnimators = new WeakHashMap<Animator, Object>(); static Animator.AnimatorListener sEndAnimListener = new Animator.AnimatorListener() { static Animator.AnimatorListener sEndAnimListener = new Animator.AnimatorListener() { public void onAnimationStart(Animator animation) { public void onAnimationStart(Animator animation) { Loading Loading @@ -165,16 +168,8 @@ public class LauncherAnimUtils { } } }; }; public static final Property<View, Float> ELEVATION = /** Increase the duration if we prevented the fling, as we are going against a high velocity. */ new Property<View, Float>(Float.class, "elevation") { public static int blockedFlingDurationFactor(float velocity) { @Override return (int) Utilities.boundToRange(Math.abs(velocity) / 2, 2f, 6f); public Float get(View view) { return view.getElevation(); } } @Override public void set(View view, Float elevation) { view.setElevation(elevation); } }; } } src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +19 −10 Original line number Original line Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ */ package com.android.launcher3.touch; package com.android.launcher3.touch; import static com.android.launcher3.LauncherAnimUtils.MIN_PROGRESS_TO_ALL_APPS; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherState.OVERVIEW; Loading @@ -32,6 +33,7 @@ import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.MotionEvent; import com.android.launcher3.Launcher; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager.AnimationComponents; import com.android.launcher3.LauncherStateManager.AnimationComponents; import com.android.launcher3.LauncherStateManager.AnimationConfig; import com.android.launcher3.LauncherStateManager.AnimationConfig; Loading @@ -43,6 +45,7 @@ import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; 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.Action.Touch; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.util.FlingBlockCheck; import com.android.launcher3.util.PendingAnimation; import com.android.launcher3.util.PendingAnimation; import com.android.launcher3.util.TouchController; import com.android.launcher3.util.TouchController; Loading Loading @@ -80,7 +83,7 @@ public abstract class AbstractStateChangeTouchController private float mProgressMultiplier; private float mProgressMultiplier; private float mDisplacementShift; private float mDisplacementShift; private boolean mCanBlockFling; private boolean mCanBlockFling; private boolean mBlockFling; private FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck(); private AnimatorSet mAtomicAnim; private AnimatorSet mAtomicAnim; private boolean mPassedOverviewAtomicThreshold; private boolean mPassedOverviewAtomicThreshold; Loading Loading @@ -241,7 +244,7 @@ public abstract class AbstractStateChangeTouchController mStartProgress = mCurrentAnimation.getProgressFraction(); mStartProgress = mCurrentAnimation.getProgressFraction(); } } mCanBlockFling = mFromState == NORMAL; mCanBlockFling = mFromState == NORMAL; mBlockFling = false; mFlingBlockCheck.unblockFling(); } } @Override @Override Loading @@ -253,16 +256,19 @@ public abstract class AbstractStateChangeTouchController if (progress <= 0) { if (progress <= 0) { if (reinitCurrentAnimation(false, isDragTowardPositive)) { if (reinitCurrentAnimation(false, isDragTowardPositive)) { mDisplacementShift = displacement; mDisplacementShift = displacement; mBlockFling = mCanBlockFling; if (mCanBlockFling) { mFlingBlockCheck.blockFling(); } } } } else if (progress >= 1) { } else if (progress >= 1) { if (reinitCurrentAnimation(true, isDragTowardPositive)) { if (reinitCurrentAnimation(true, isDragTowardPositive)) { mDisplacementShift = displacement; mDisplacementShift = displacement; mBlockFling = mCanBlockFling; if (mCanBlockFling) { mFlingBlockCheck.blockFling(); } } } } else if (Math.abs(velocity) < SwipeDetector.RELEASE_VELOCITY_PX_MS) { } else { // We prevent flinging after passing a state, but allow it if the user pauses briefly. mFlingBlockCheck.onEvent(); mBlockFling = false; } } return true; return true; Loading Loading @@ -325,7 +331,7 @@ public abstract class AbstractStateChangeTouchController final LauncherState targetState; final LauncherState targetState; final float progress = mCurrentAnimation.getProgressFraction(); final float progress = mCurrentAnimation.getProgressFraction(); boolean blockedFling = fling && mBlockFling; boolean blockedFling = fling && mFlingBlockCheck.isBlocked(); if (blockedFling) { if (blockedFling) { fling = false; fling = false; } } Loading @@ -338,14 +344,17 @@ public abstract class AbstractStateChangeTouchController // snap to top or bottom using the release velocity // snap to top or bottom using the release velocity } else { } else { logAction = Touch.SWIPE; logAction = Touch.SWIPE; targetState = (progress > SUCCESS_TRANSITION_PROGRESS) ? mToState : mFromState; float successProgress = mToState == ALL_APPS ? MIN_PROGRESS_TO_ALL_APPS : SUCCESS_TRANSITION_PROGRESS; targetState = (progress > successProgress) ? mToState : mFromState; } } final float endProgress; final float endProgress; final float startProgress; final float startProgress; final long duration; final long duration; // Increase the duration if we prevented the fling, as we are going against a high velocity. // Increase the duration if we prevented the fling, as we are going against a high velocity. final long durationMultiplier = blockedFling && targetState == mFromState ? 6 : 1; final int durationMultiplier = blockedFling && targetState == mFromState ? LauncherAnimUtils.blockedFlingDurationFactor(velocity) : 1; if (targetState == mToState) { if (targetState == mToState) { endProgress = 1; endProgress = 1; Loading src/com/android/launcher3/util/FlingBlockCheck.java 0 → 100644 +52 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2018 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.util; import android.os.SystemClock; /** * Determines whether a fling should be blocked. Currently we block flings when crossing thresholds * to new states, and unblock after a short duration. */ public class FlingBlockCheck { // Allow flinging to a new state after waiting this many milliseconds. private static final long UNBLOCK_FLING_PAUSE_DURATION = 200; private boolean mBlockFling; private long mBlockFlingTime; public void blockFling() { mBlockFling = true; mBlockFlingTime = SystemClock.uptimeMillis(); } public void unblockFling() { mBlockFling = false; mBlockFlingTime = 0; } public void onEvent() { // We prevent flinging after passing a state, but allow it if the user pauses briefly. if (SystemClock.uptimeMillis() - mBlockFlingTime >= UNBLOCK_FLING_PAUSE_DURATION) { mBlockFling = false; } } public boolean isBlocked() { return mBlockFling; } } Loading
quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java +18 −21 Original line number Original line Diff line number Diff line Loading @@ -21,16 +21,17 @@ import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelo import android.animation.Animator; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.animation.ValueAnimator; import android.util.Log; import android.view.MotionEvent; import android.view.MotionEvent; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.Utilities; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.touch.SwipeDetector; import com.android.launcher3.touch.SwipeDetector; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.util.FlingBlockCheck; import com.android.launcher3.util.PendingAnimation; import com.android.launcher3.util.PendingAnimation; import com.android.launcher3.util.TouchController; import com.android.launcher3.util.TouchController; import com.android.launcher3.views.BaseDragLayer; import com.android.launcher3.views.BaseDragLayer; Loading @@ -46,8 +47,6 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> private static final String TAG = "OverviewSwipeController"; private static final String TAG = "OverviewSwipeController"; private static final float ALLOWED_FLING_DIRECTION_CHANGE_PROGRESS = 0.1f; // Progress after which the transition is assumed to be a success in case user does not fling // 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 static final float SUCCESS_TRANSITION_PROGRESS = 0.5f; Loading @@ -65,6 +64,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> private float mDisplacementShift; private float mDisplacementShift; private float mProgressMultiplier; private float mProgressMultiplier; private float mEndDisplacement; private float mEndDisplacement; private FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck(); private TaskView mTaskBeingDragged; private TaskView mTaskBeingDragged; Loading Loading @@ -93,7 +93,6 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> @Override @Override public void onAnimationCancel(Animator animation) { public void onAnimationCancel(Animator animation) { if (mCurrentAnimation != null && animation == mCurrentAnimation.getTarget()) { if (mCurrentAnimation != null && animation == mCurrentAnimation.getTarget()) { Log.e(TAG, "Who dare cancel the animation when I am in control", new Exception()); clearState(); clearState(); } } } } Loading Loading @@ -158,16 +157,16 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> return mDetector.onTouchEvent(ev); return mDetector.onTouchEvent(ev); } } private boolean reInitAnimationController(boolean goingUp) { private void reInitAnimationController(boolean goingUp) { if (mCurrentAnimation != null && mCurrentAnimationIsGoingUp == goingUp) { if (mCurrentAnimation != null && mCurrentAnimationIsGoingUp == goingUp) { // No need to init // No need to init return false; return; } } int scrollDirections = mDetector.getScrollDirections(); int scrollDirections = mDetector.getScrollDirections(); if (goingUp && ((scrollDirections & SwipeDetector.DIRECTION_POSITIVE) == 0) if (goingUp && ((scrollDirections & SwipeDetector.DIRECTION_POSITIVE) == 0) || !goingUp && ((scrollDirections & SwipeDetector.DIRECTION_NEGATIVE) == 0)) { || !goingUp && ((scrollDirections & SwipeDetector.DIRECTION_NEGATIVE) == 0)) { // Trying to re-init in an unsupported direction. // Trying to re-init in an unsupported direction. return false; return; } } if (mCurrentAnimation != null) { if (mCurrentAnimation != null) { mCurrentAnimation.setPlayFraction(0); mCurrentAnimation.setPlayFraction(0); Loading Loading @@ -205,7 +204,6 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> mCurrentAnimation.getTarget().addListener(this); mCurrentAnimation.getTarget().addListener(this); mCurrentAnimation.dispatchOnStart(); mCurrentAnimation.dispatchOnStart(); mProgressMultiplier = 1 / mEndDisplacement; mProgressMultiplier = 1 / mEndDisplacement; return true; } } @Override @Override Loading @@ -217,6 +215,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> mDisplacementShift = mCurrentAnimation.getProgressFraction() / mProgressMultiplier; mDisplacementShift = mCurrentAnimation.getProgressFraction() / mProgressMultiplier; mCurrentAnimation.pause(); mCurrentAnimation.pause(); } } mFlingBlockCheck.unblockFling(); } } @Override @Override Loading @@ -226,6 +225,9 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> totalDisplacement == 0 ? mCurrentAnimationIsGoingUp : totalDisplacement < 0; totalDisplacement == 0 ? mCurrentAnimationIsGoingUp : totalDisplacement < 0; if (isGoingUp != mCurrentAnimationIsGoingUp) { if (isGoingUp != mCurrentAnimationIsGoingUp) { reInitAnimationController(isGoingUp); reInitAnimationController(isGoingUp); mFlingBlockCheck.blockFling(); } else { mFlingBlockCheck.onEvent(); } } mCurrentAnimation.setPlayFraction(totalDisplacement * mProgressMultiplier); mCurrentAnimation.setPlayFraction(totalDisplacement * mProgressMultiplier); return true; return true; Loading @@ -235,22 +237,14 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> public void onDragEnd(float velocity, boolean fling) { public void onDragEnd(float velocity, boolean fling) { final boolean goingToEnd; final boolean goingToEnd; final int logAction; final int logAction; boolean blockedFling = fling && mFlingBlockCheck.isBlocked(); if (blockedFling) { fling = false; } if (fling) { if (fling) { logAction = Touch.FLING; logAction = Touch.FLING; boolean goingUp = velocity < 0; boolean goingUp = velocity < 0; if (goingUp != mCurrentAnimationIsGoingUp) { goingToEnd = goingUp == mCurrentAnimationIsGoingUp; // In case the fling is in opposite direction, make sure if is close enough // from the start position if (mCurrentAnimation.getProgressFraction() >= ALLOWED_FLING_DIRECTION_CHANGE_PROGRESS) { // Not allowed goingToEnd = false; } else { goingToEnd = reInitAnimationController(goingUp); } } else { goingToEnd = true; } } else { } else { logAction = Touch.SWIPE; logAction = Touch.SWIPE; goingToEnd = mCurrentAnimation.getProgressFraction() > SUCCESS_TRANSITION_PROGRESS; goingToEnd = mCurrentAnimation.getProgressFraction() > SUCCESS_TRANSITION_PROGRESS; Loading @@ -259,6 +253,9 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> float progress = mCurrentAnimation.getProgressFraction(); float progress = mCurrentAnimation.getProgressFraction(); long animationDuration = SwipeDetector.calculateDuration( long animationDuration = SwipeDetector.calculateDuration( velocity, goingToEnd ? (1 - progress) : progress); velocity, goingToEnd ? (1 - progress) : progress); if (blockedFling && !goingToEnd) { animationDuration *= LauncherAnimUtils.blockedFlingDurationFactor(velocity); } float nextFrameProgress = Utilities.boundToRange( float nextFrameProgress = Utilities.boundToRange( progress + velocity * SINGLE_FRAME_MS / Math.abs(mEndDisplacement), 0f, 1f); progress + velocity * SINGLE_FRAME_MS / Math.abs(mEndDisplacement), 0f, 1f); Loading
quickstep/src/com/android/quickstep/LongSwipeHelper.java +18 −2 Original line number Original line Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ */ package com.android.quickstep; package com.android.quickstep; import static com.android.launcher3.LauncherAnimUtils.MIN_PROGRESS_TO_ALL_APPS; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL; Loading @@ -26,6 +27,7 @@ import android.animation.ValueAnimator; import android.view.Surface; import android.view.Surface; import com.android.launcher3.Launcher; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.R; import com.android.launcher3.R; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.allapps.DiscoveryBounce; Loading @@ -33,7 +35,9 @@ import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; 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.Action.Touch; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.util.FlingBlockCheck; import com.android.quickstep.util.RemoteAnimationTargetSet; import com.android.quickstep.util.RemoteAnimationTargetSet; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.TransactionCompat; import com.android.systemui.shared.system.TransactionCompat; Loading @@ -44,7 +48,6 @@ import com.android.systemui.shared.system.TransactionCompat; */ */ public class LongSwipeHelper { public class LongSwipeHelper { private static final float MIN_PROGRESS_TO_ALL_APPS = 0.35f; private static final float SWIPE_DURATION_MULTIPLIER = private static final float SWIPE_DURATION_MULTIPLIER = Math.min(1 / MIN_PROGRESS_TO_ALL_APPS, 1 / (1 - MIN_PROGRESS_TO_ALL_APPS)); Math.min(1 / MIN_PROGRESS_TO_ALL_APPS, 1 / (1 - MIN_PROGRESS_TO_ALL_APPS)); Loading @@ -53,6 +56,7 @@ public class LongSwipeHelper { private float mMaxSwipeDistance = 1; private float mMaxSwipeDistance = 1; private AnimatorPlaybackController mAnimator; private AnimatorPlaybackController mAnimator; private FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck(); LongSwipeHelper(Launcher launcher, RemoteAnimationTargetSet targetSet) { LongSwipeHelper(Launcher launcher, RemoteAnimationTargetSet targetSet) { mLauncher = launcher; mLauncher = launcher; Loading @@ -62,6 +66,7 @@ public class LongSwipeHelper { private void init() { private void init() { setTargetAlpha(0, true); setTargetAlpha(0, true); mFlingBlockCheck.blockFling(); // Init animations // Init animations AllAppsTransitionController controller = mLauncher.getAllAppsController(); AllAppsTransitionController controller = mLauncher.getAllAppsController(); Loading @@ -74,6 +79,7 @@ public class LongSwipeHelper { public void onMove(float displacement) { public void onMove(float displacement) { mAnimator.setPlayFraction(displacement / mMaxSwipeDistance); mAnimator.setPlayFraction(displacement / mMaxSwipeDistance); mFlingBlockCheck.onEvent(); } } public void destroy() { public void destroy() { Loading @@ -90,6 +96,11 @@ public class LongSwipeHelper { final boolean toAllApps; final boolean toAllApps; float endProgress; float endProgress; boolean blockedFling = isFling && mFlingBlockCheck.isBlocked(); if (blockedFling) { isFling = false; } if (!isFling) { if (!isFling) { toAllApps = currentFraction > MIN_PROGRESS_TO_ALL_APPS; toAllApps = currentFraction > MIN_PROGRESS_TO_ALL_APPS; endProgress = toAllApps ? 1 : 0; endProgress = toAllApps ? 1 : 0; Loading @@ -114,7 +125,11 @@ public class LongSwipeHelper { } } } } mAnimator.setEndAction(() -> onSwipeAnimationComplete(toAllApps, isFling, callback)); if (blockedFling && !toAllApps) { duration *= LauncherAnimUtils.blockedFlingDurationFactor(0); } final boolean finalIsFling = isFling; mAnimator.setEndAction(() -> onSwipeAnimationComplete(toAllApps, finalIsFling, callback)); ValueAnimator animator = mAnimator.getAnimationPlayer(); ValueAnimator animator = mAnimator.getAnimationPlayer(); animator.setDuration(duration).setInterpolator(DEACCEL); animator.setDuration(duration).setInterpolator(DEACCEL); animator.setFloatValues(currentFraction, endProgress); animator.setFloatValues(currentFraction, endProgress); Loading Loading @@ -150,6 +165,7 @@ public class LongSwipeHelper { mLauncher.getStateManager().goToState(toAllApps ? ALL_APPS : OVERVIEW, false); mLauncher.getStateManager().goToState(toAllApps ? ALL_APPS : OVERVIEW, false); if (!toAllApps) { if (!toAllApps) { DiscoveryBounce.showForOverviewIfNeeded(mLauncher); DiscoveryBounce.showForOverviewIfNeeded(mLauncher); mLauncher.<RecentsView>getOverviewPanel().setSwipeDownShouldLaunchApp(true); } } mLauncher.getUserEventDispatcher().logStateChangeAction( mLauncher.getUserEventDispatcher().logStateChangeAction( Loading
src/com/android/launcher3/LauncherAnimUtils.java +7 −12 Original line number Original line Diff line number Diff line Loading @@ -39,6 +39,9 @@ public class LauncherAnimUtils { public static final int SPRING_LOADED_TRANSITION_MS = 150; public static final int SPRING_LOADED_TRANSITION_MS = 150; public static final int SPRING_LOADED_EXIT_DELAY = 500; public static final int SPRING_LOADED_EXIT_DELAY = 500; // The progress of an animation to all apps must be at least this far along to snap to all apps. public static final float MIN_PROGRESS_TO_ALL_APPS = 0.5f; static WeakHashMap<Animator, Object> sAnimators = new WeakHashMap<Animator, Object>(); static WeakHashMap<Animator, Object> sAnimators = new WeakHashMap<Animator, Object>(); static Animator.AnimatorListener sEndAnimListener = new Animator.AnimatorListener() { static Animator.AnimatorListener sEndAnimListener = new Animator.AnimatorListener() { public void onAnimationStart(Animator animation) { public void onAnimationStart(Animator animation) { Loading Loading @@ -165,16 +168,8 @@ public class LauncherAnimUtils { } } }; }; public static final Property<View, Float> ELEVATION = /** Increase the duration if we prevented the fling, as we are going against a high velocity. */ new Property<View, Float>(Float.class, "elevation") { public static int blockedFlingDurationFactor(float velocity) { @Override return (int) Utilities.boundToRange(Math.abs(velocity) / 2, 2f, 6f); public Float get(View view) { return view.getElevation(); } } @Override public void set(View view, Float elevation) { view.setElevation(elevation); } }; } }
src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +19 −10 Original line number Original line Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ */ package com.android.launcher3.touch; package com.android.launcher3.touch; import static com.android.launcher3.LauncherAnimUtils.MIN_PROGRESS_TO_ALL_APPS; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherState.OVERVIEW; Loading @@ -32,6 +33,7 @@ import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.MotionEvent; import com.android.launcher3.Launcher; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager.AnimationComponents; import com.android.launcher3.LauncherStateManager.AnimationComponents; import com.android.launcher3.LauncherStateManager.AnimationConfig; import com.android.launcher3.LauncherStateManager.AnimationConfig; Loading @@ -43,6 +45,7 @@ import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; 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.Action.Touch; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.util.FlingBlockCheck; import com.android.launcher3.util.PendingAnimation; import com.android.launcher3.util.PendingAnimation; import com.android.launcher3.util.TouchController; import com.android.launcher3.util.TouchController; Loading Loading @@ -80,7 +83,7 @@ public abstract class AbstractStateChangeTouchController private float mProgressMultiplier; private float mProgressMultiplier; private float mDisplacementShift; private float mDisplacementShift; private boolean mCanBlockFling; private boolean mCanBlockFling; private boolean mBlockFling; private FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck(); private AnimatorSet mAtomicAnim; private AnimatorSet mAtomicAnim; private boolean mPassedOverviewAtomicThreshold; private boolean mPassedOverviewAtomicThreshold; Loading Loading @@ -241,7 +244,7 @@ public abstract class AbstractStateChangeTouchController mStartProgress = mCurrentAnimation.getProgressFraction(); mStartProgress = mCurrentAnimation.getProgressFraction(); } } mCanBlockFling = mFromState == NORMAL; mCanBlockFling = mFromState == NORMAL; mBlockFling = false; mFlingBlockCheck.unblockFling(); } } @Override @Override Loading @@ -253,16 +256,19 @@ public abstract class AbstractStateChangeTouchController if (progress <= 0) { if (progress <= 0) { if (reinitCurrentAnimation(false, isDragTowardPositive)) { if (reinitCurrentAnimation(false, isDragTowardPositive)) { mDisplacementShift = displacement; mDisplacementShift = displacement; mBlockFling = mCanBlockFling; if (mCanBlockFling) { mFlingBlockCheck.blockFling(); } } } } else if (progress >= 1) { } else if (progress >= 1) { if (reinitCurrentAnimation(true, isDragTowardPositive)) { if (reinitCurrentAnimation(true, isDragTowardPositive)) { mDisplacementShift = displacement; mDisplacementShift = displacement; mBlockFling = mCanBlockFling; if (mCanBlockFling) { mFlingBlockCheck.blockFling(); } } } } else if (Math.abs(velocity) < SwipeDetector.RELEASE_VELOCITY_PX_MS) { } else { // We prevent flinging after passing a state, but allow it if the user pauses briefly. mFlingBlockCheck.onEvent(); mBlockFling = false; } } return true; return true; Loading Loading @@ -325,7 +331,7 @@ public abstract class AbstractStateChangeTouchController final LauncherState targetState; final LauncherState targetState; final float progress = mCurrentAnimation.getProgressFraction(); final float progress = mCurrentAnimation.getProgressFraction(); boolean blockedFling = fling && mBlockFling; boolean blockedFling = fling && mFlingBlockCheck.isBlocked(); if (blockedFling) { if (blockedFling) { fling = false; fling = false; } } Loading @@ -338,14 +344,17 @@ public abstract class AbstractStateChangeTouchController // snap to top or bottom using the release velocity // snap to top or bottom using the release velocity } else { } else { logAction = Touch.SWIPE; logAction = Touch.SWIPE; targetState = (progress > SUCCESS_TRANSITION_PROGRESS) ? mToState : mFromState; float successProgress = mToState == ALL_APPS ? MIN_PROGRESS_TO_ALL_APPS : SUCCESS_TRANSITION_PROGRESS; targetState = (progress > successProgress) ? mToState : mFromState; } } final float endProgress; final float endProgress; final float startProgress; final float startProgress; final long duration; final long duration; // Increase the duration if we prevented the fling, as we are going against a high velocity. // Increase the duration if we prevented the fling, as we are going against a high velocity. final long durationMultiplier = blockedFling && targetState == mFromState ? 6 : 1; final int durationMultiplier = blockedFling && targetState == mFromState ? LauncherAnimUtils.blockedFlingDurationFactor(velocity) : 1; if (targetState == mToState) { if (targetState == mToState) { endProgress = 1; endProgress = 1; Loading
src/com/android/launcher3/util/FlingBlockCheck.java 0 → 100644 +52 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2018 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.util; import android.os.SystemClock; /** * Determines whether a fling should be blocked. Currently we block flings when crossing thresholds * to new states, and unblock after a short duration. */ public class FlingBlockCheck { // Allow flinging to a new state after waiting this many milliseconds. private static final long UNBLOCK_FLING_PAUSE_DURATION = 200; private boolean mBlockFling; private long mBlockFlingTime; public void blockFling() { mBlockFling = true; mBlockFlingTime = SystemClock.uptimeMillis(); } public void unblockFling() { mBlockFling = false; mBlockFlingTime = 0; } public void onEvent() { // We prevent flinging after passing a state, but allow it if the user pauses briefly. if (SystemClock.uptimeMillis() - mBlockFlingTime >= UNBLOCK_FLING_PAUSE_DURATION) { mBlockFling = false; } } public boolean isBlocked() { return mBlockFling; } }