diff options
author | Android Build Merger (Role) <noreply-android-build-merger@google.com> | 2018-04-26 17:29:38 +0000 |
---|---|---|
committer | Android Build Merger (Role) <noreply-android-build-merger@google.com> | 2018-04-26 17:29:38 +0000 |
commit | 0f627e81ade12a6a6fd199f00dc602caecd62965 (patch) | |
tree | 129ab55077c162823c5e63d88051de0ca817bf00 | |
parent | f7616e84996211f65aec6a309f230cbf2e8f16a5 (diff) | |
parent | 6a9bc7dfa794a2fe2a3ac57b6039c15752d5633e (diff) | |
download | android_packages_apps_Trebuchet-0f627e81ade12a6a6fd199f00dc602caecd62965.tar.gz android_packages_apps_Trebuchet-0f627e81ade12a6a6fd199f00dc602caecd62965.tar.bz2 android_packages_apps_Trebuchet-0f627e81ade12a6a6fd199f00dc602caecd62965.zip |
[automerger] Revert "Revert "Long swipe from an app goes all the way to all-apps"" am: 6a9bc7dfa7
Change-Id: I0da466b3e14a0bb29216337d1dab03e2201f63c7
4 files changed, 394 insertions, 60 deletions
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java index ad11bd32a..88cd376a7 100644 --- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java +++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java @@ -102,6 +102,13 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> { */ boolean deferStartingActivity(int downHitTarget); + boolean supportsLongSwipe(T activity); + + /** + * Must return a non-null controller is supportsLongSwipe was true. + */ + LongSwipeHelper getLongSwipeController(T activity, RemoteAnimationTargetSet targetSet); + class LauncherActivityControllerHelper implements ActivityControlHelper<Launcher> { @Override @@ -164,11 +171,13 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> { @Override public AnimationFactory prepareRecentsUI(Launcher activity, boolean activityVisible, Consumer<AnimatorPlaybackController> callback) { - LauncherState startState = activity.getStateManager().getState(); + final LauncherState startState = activity.getStateManager().getState(); + + LauncherState resetState = startState; if (startState.disableRestore) { - startState = activity.getStateManager().getRestState(); + resetState = activity.getStateManager().getRestState(); } - activity.getStateManager().setRestState(startState); + activity.getStateManager().setRestState(resetState); if (!activityVisible) { // Since the launcher is not visible, we can safely reset the scroll position. @@ -180,11 +189,21 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> { activity.getAppsView().getContentView().setVisibility(View.GONE); } - return (transitionLength) -> - createActivityController(activity, activityVisible, transitionLength, callback); + return new AnimationFactory() { + @Override + public void createActivityController(long transitionLength) { + createActivityControllerInternal(activity, activityVisible, transitionLength, + callback); + } + + @Override + public void onTransitionCancelled() { + activity.getStateManager().goToState(startState, false /* animate */); + } + }; } - private void createActivityController(Launcher activity, boolean wasVisible, + private void createActivityControllerInternal(Launcher activity, boolean wasVisible, long transitionLength, Consumer<AnimatorPlaybackController> callback) { if (wasVisible) { DeviceProfile dp = activity.getDeviceProfile(); @@ -272,6 +291,20 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> { public boolean shouldMinimizeSplitScreen() { return true; } + + @Override + public boolean supportsLongSwipe(Launcher activity) { + return !activity.getDeviceProfile().isVerticalBarLayout(); + } + + @Override + public LongSwipeHelper getLongSwipeController(Launcher activity, + RemoteAnimationTargetSet targetSet) { + if (activity.getDeviceProfile().isVerticalBarLayout()) { + return null; + } + return new LongSwipeHelper(activity, targetSet); + } } class FallbackActivityControllerHelper implements ActivityControlHelper<RecentsActivity> { @@ -419,6 +452,17 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> { // TODO: Remove this once b/77875376 is fixed return false; } + + @Override + public boolean supportsLongSwipe(RecentsActivity activity) { + return false; + } + + @Override + public LongSwipeHelper getLongSwipeController(RecentsActivity activity, + RemoteAnimationTargetSet targetSet) { + return null; + } } interface LayoutListener { @@ -445,5 +489,7 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> { default void onRemoteAnimationReceived(RemoteAnimationTargetSet targets) { } void createActivityController(long transitionLength); + + default void onTransitionCancelled() { } } } diff --git a/quickstep/src/com/android/quickstep/LongSwipeHelper.java b/quickstep/src/com/android/quickstep/LongSwipeHelper.java new file mode 100644 index 000000000..4ce18b31f --- /dev/null +++ b/quickstep/src/com/android/quickstep/LongSwipeHelper.java @@ -0,0 +1,162 @@ +/* + * 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.quickstep; + +import static com.android.launcher3.LauncherState.ALL_APPS; +import static com.android.launcher3.LauncherState.OVERVIEW; +import static com.android.launcher3.anim.Interpolators.DEACCEL; +import static com.android.quickstep.WindowTransformSwipeHandler.MAX_SWIPE_DURATION; +import static com.android.systemui.shared.recents.utilities.Utilities.getNextFrameNumber; +import static com.android.systemui.shared.recents.utilities.Utilities.getSurface; + +import android.animation.ValueAnimator; +import android.view.Surface; + +import com.android.launcher3.Launcher; +import com.android.launcher3.R; +import com.android.launcher3.allapps.AllAppsTransitionController; +import com.android.launcher3.allapps.DiscoveryBounce; +import com.android.launcher3.anim.AnimatorPlaybackController; +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.ContainerType; +import com.android.quickstep.util.RemoteAnimationTargetSet; +import com.android.systemui.shared.system.RemoteAnimationTargetCompat; +import com.android.systemui.shared.system.TransactionCompat; + +/** + * Utility class to handle long swipe from an app. + * This assumes the presence of Launcher activity as long swipe is not supported on the + * fallback activity. + */ +public class LongSwipeHelper { + + private static final float MIN_PROGRESS_TO_ALL_APPS = 0.35f; + private static final float SWIPE_DURATION_MULTIPLIER = + Math.min(1 / MIN_PROGRESS_TO_ALL_APPS, 1 / (1 - MIN_PROGRESS_TO_ALL_APPS)); + + private final Launcher mLauncher; + private final RemoteAnimationTargetSet mTargetSet; + + private float mMaxSwipeDistance = 1; + private AnimatorPlaybackController mAnimator; + + LongSwipeHelper(Launcher launcher, RemoteAnimationTargetSet targetSet) { + mLauncher = launcher; + mTargetSet = targetSet; + init(); + } + + private void init() { + setTargetAlpha(0, true); + + // Init animations + AllAppsTransitionController controller = mLauncher.getAllAppsController(); + // TODO: Scale it down so that we can reach all-apps in screen space + mMaxSwipeDistance = Math.max(1, controller.getProgress() * controller.getShiftRange()); + mAnimator = mLauncher.getStateManager() + .createAnimationToNewWorkspace(ALL_APPS, Math.round(2 * mMaxSwipeDistance)); + mAnimator.dispatchOnStart(); + } + + public void onMove(float displacement) { + mAnimator.setPlayFraction(displacement / mMaxSwipeDistance); + } + + public void destroy() { + // TODO: We can probably also hide the task view + setTargetAlpha(1, false); + + mLauncher.getStateManager().goToState(OVERVIEW, false); + } + + public void end(float velocity, boolean isFling, Runnable callback) { + long duration = MAX_SWIPE_DURATION; + + final float currentFraction = mAnimator.getProgressFraction(); + final boolean toAllApps; + float endProgress; + + if (!isFling) { + toAllApps = currentFraction > MIN_PROGRESS_TO_ALL_APPS; + endProgress = toAllApps ? 1 : 0; + + long expectedDuration = Math.abs(Math.round((endProgress - currentFraction) + * MAX_SWIPE_DURATION * SWIPE_DURATION_MULTIPLIER)); + duration = Math.min(MAX_SWIPE_DURATION, expectedDuration); + } else { + toAllApps = velocity < 0; + endProgress = toAllApps ? 1 : 0; + + float minFlingVelocity = mLauncher.getResources() + .getDimension(R.dimen.quickstep_fling_min_velocity); + if (Math.abs(velocity) > minFlingVelocity && mMaxSwipeDistance > 0) { + float distanceToTravel = (endProgress - currentFraction) * mMaxSwipeDistance; + + // we want the page's snap velocity to approximately match the velocity at + // which the user flings, so we scale the duration by a value near to the + // derivative of the scroll interpolator at zero, ie. 2. + long baseDuration = Math.round(1000 * Math.abs(distanceToTravel / velocity)); + duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration); + } + } + + mAnimator.setEndAction(() -> onSwipeAnimationComplete(toAllApps, isFling, callback)); + ValueAnimator animator = mAnimator.getAnimationPlayer(); + animator.setDuration(duration).setInterpolator(DEACCEL); + animator.setFloatValues(currentFraction, endProgress); + animator.start(); + } + + private void setTargetAlpha(float alpha, boolean defer) { + final Surface surface = getSurface(mLauncher.getDragLayer()); + final long frameNumber = defer && surface != null ? getNextFrameNumber(surface) : -1; + if (defer) { + if (frameNumber == -1) { + defer = false; + } else { + mLauncher.getDragLayer().invalidate(); + } + } + + TransactionCompat transaction = new TransactionCompat(); + for (RemoteAnimationTargetCompat app : mTargetSet.apps) { + if (!(app.isNotInRecents + || app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME)) { + transaction.setAlpha(app.leash, alpha); + if (defer) { + transaction.deferTransactionUntil(app.leash, surface, frameNumber); + } + } + } + transaction.apply(); + } + + private void onSwipeAnimationComplete(boolean toAllApps, boolean isFling, Runnable callback) { + mLauncher.getStateManager().goToState(toAllApps ? ALL_APPS : OVERVIEW, false); + if (!toAllApps) { + DiscoveryBounce.showForOverviewIfNeeded(mLauncher); + } + + mLauncher.getUserEventDispatcher().logStateChangeAction( + isFling ? Touch.FLING : Touch.SWIPE, Direction.UP, + ContainerType.NAVBAR, ContainerType.APP, + toAllApps ? ContainerType.ALLAPPS : ContainerType.TASKSWITCHER, + 0); + + callback.run(); + } +} diff --git a/quickstep/src/com/android/quickstep/MultiStateCallback.java b/quickstep/src/com/android/quickstep/MultiStateCallback.java index 7a741764f..bda3d06aa 100644 --- a/quickstep/src/com/android/quickstep/MultiStateCallback.java +++ b/quickstep/src/com/android/quickstep/MultiStateCallback.java @@ -59,4 +59,8 @@ public class MultiStateCallback { public int getState() { return mState; } + + public boolean hasStates(int stateMask) { + return (mState & stateMask) == stateMask; + } } diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index b8be6b81a..881b09b1d 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -31,7 +31,6 @@ import android.animation.ObjectAnimator; import android.annotation.TargetApi; import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; -import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Point; import android.graphics.Rect; @@ -52,9 +51,7 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; -import com.android.launcher3.MainThreadExecutor; import com.android.launcher3.R; -import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.logging.UserEventDispatcher; @@ -103,16 +100,28 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { private static final int STATE_HANDLER_INVALIDATED = 1 << 7; private static final int STATE_GESTURE_STARTED = 1 << 8; private static final int STATE_GESTURE_CANCELLED = 1 << 9; + private static final int STATE_GESTURE_COMPLETED = 1 << 10; // States for quick switch/scrub - private static final int STATE_SWITCH_TO_SCREENSHOT_COMPLETE = 1 << 10; - private static final int STATE_QUICK_SCRUB_START = 1 << 11; - private static final int STATE_QUICK_SCRUB_END = 1 << 12; + private static final int STATE_CURRENT_TASK_FINISHED = 1 << 11; + private static final int STATE_QUICK_SCRUB_START = 1 << 12; + private static final int STATE_QUICK_SCRUB_END = 1 << 13; + + private static final int STATE_CAPTURE_SCREENSHOT = 1 << 14; + private static final int STATE_SCREENSHOT_CAPTURED = 1 << 15; private static final int LAUNCHER_UI_STATES = STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_LAUNCHER_STARTED; + private static final int LONG_SWIPE_ENTER_STATE = + STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_LAUNCHER_STARTED + | STATE_APP_CONTROLLER_RECEIVED; + + private static final int LONG_SWIPE_START_STATE = + STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_LAUNCHER_STARTED + | STATE_APP_CONTROLLER_RECEIVED | STATE_SCREENSHOT_CAPTURED; + // For debugging, keep in sync with above states private static final String[] STATES = new String[] { "STATE_LAUNCHER_PRESENT", @@ -125,14 +134,16 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { "STATE_HANDLER_INVALIDATED", "STATE_GESTURE_STARTED", "STATE_GESTURE_CANCELLED", - "STATE_SWITCH_TO_SCREENSHOT_COMPLETE", - "STATE_QUICK_SWITCH", + "STATE_GESTURE_COMPLETED", + "STATE_CURRENT_TASK_FINISHED", "STATE_QUICK_SCRUB_START", - "STATE_QUICK_SCRUB_END" + "STATE_QUICK_SCRUB_END", + "STATE_CAPTURE_SCREENSHOT", + "STATE_SCREENSHOT_CAPTURED", }; - private static final long MAX_SWIPE_DURATION = 350; - private static final long MIN_SWIPE_DURATION = 80; + public static final long MAX_SWIPE_DURATION = 350; + public static final long MIN_SWIPE_DURATION = 80; private static final float MIN_PROGRESS_FOR_OVERVIEW = 0.5f; private static final float SWIPE_DURATION_MULTIPLIER = @@ -151,7 +162,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { // visible. private final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift); - private final MainThreadExecutor mMainExecutor = new MainThreadExecutor(); + private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); private final Context mContext; private final int mRunningTaskId; @@ -171,7 +182,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { private boolean mWasLauncherAlreadyVisible; - private float mCurrentDisplacement; private boolean mGestureStarted; private int mLogAction = Touch.SWIPE; private float mCurrentQuickScrubProgress; @@ -185,6 +195,11 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { private final long mTouchTimeMs; private long mLauncherFrameDrawnTime; + private boolean mBgLongSwipeMode = false; + private boolean mUiLongSwipeMode = false; + private float mLongSwipeDisplacement = 0; + private LongSwipeHelper mLongSwipeController; + WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs, ActivityControlHelper<T> controller) { mContext = context; @@ -194,10 +209,10 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { mActivityInitListener = mActivityControlHelper .createActivityInitListener(this::onActivityInit); + initStateCallbacks(); // Register the input consumer on the UI thread, to ensure that it runs after any pending // unregister calls - mMainExecutor.execute(mInputConsumer::registerInputConsumer); - initStateCallbacks(); + executeOnUiThread(mInputConsumer::registerInputConsumer); } private void initStateCallbacks() { @@ -226,12 +241,18 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { this::resumeLastTask); mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED | STATE_ACTIVITY_MULTIPLIER_COMPLETE - | STATE_SCALED_CONTROLLER_RECENTS, + | STATE_CAPTURE_SCREENSHOT, this::switchToScreenshot); + + mStateCallback.addCallback(STATE_SCREENSHOT_CAPTURED | STATE_GESTURE_COMPLETED + | STATE_SCALED_CONTROLLER_RECENTS, + this::finishCurrentTransitionToHome); + mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED | STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_SCALED_CONTROLLER_RECENTS - | STATE_SWITCH_TO_SCREENSHOT_COMPLETE, + | STATE_CURRENT_TASK_FINISHED + | STATE_GESTURE_COMPLETED, this::setupLauncherUiAfterSwipeUpAnimation); mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_SCALED_CONTROLLER_APP, @@ -240,21 +261,34 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { mStateCallback.addCallback(STATE_HANDLER_INVALIDATED, this::invalidateHandler); mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED, this::invalidateHandlerWithLauncher); + mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED + | STATE_SCALED_CONTROLLER_APP, + this::notifyTransitionCancelled); mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_QUICK_SCRUB_START, this::onQuickScrubStart); mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_QUICK_SCRUB_START | STATE_SCALED_CONTROLLER_RECENTS, this::onFinishedTransitionToQuickScrub); - mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_SWITCH_TO_SCREENSHOT_COMPLETE + mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_CURRENT_TASK_FINISHED | STATE_QUICK_SCRUB_END, this::switchToFinalAppAfterQuickScrub); + + mStateCallback.addCallback(LONG_SWIPE_ENTER_STATE, this::checkLongSwipeCanEnter); + mStateCallback.addCallback(LONG_SWIPE_START_STATE, this::checkLongSwipeCanStart); + } + + private void executeOnUiThread(Runnable action) { + if (Looper.myLooper() == mMainThreadHandler.getLooper()) { + action.run(); + } else { + postAsyncCallback(mMainThreadHandler, action); + } } private void setStateOnUiThread(int stateFlag) { - Handler handler = mMainExecutor.getHandler(); - if (Looper.myLooper() == handler.getLooper()) { + if (Looper.myLooper() == mMainThreadHandler.getLooper()) { mStateCallback.setState(stateFlag); } else { - postAsyncCallback(handler, () -> mStateCallback.setState(stateFlag)); + postAsyncCallback(mMainThreadHandler, () -> mStateCallback.setState(stateFlag)); } } @@ -321,7 +355,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { if (mActivity != activity) { return; } - if ((mStateCallback.getState() & STATE_HANDLER_INVALIDATED) != 0) { + if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) { return; } @@ -416,11 +450,26 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { @WorkerThread public void updateDisplacement(float displacement) { - mCurrentDisplacement = displacement; - - float translation = Utilities.boundToRange(-mCurrentDisplacement, 0, mTransitionDragLength); - float shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength; - mCurrentShift.updateValue(shift); + // We are moving in the negative x/y direction + displacement = -displacement; + if (displacement > mTransitionDragLength) { + mCurrentShift.updateValue(1); + + if (!mBgLongSwipeMode) { + mBgLongSwipeMode = true; + executeOnUiThread(this::onLongSwipeEnabledUi); + } + mLongSwipeDisplacement = displacement - mTransitionDragLength; + executeOnUiThread(this::onLongSwipeDisplacementUpdated); + } else { + if (mBgLongSwipeMode) { + mBgLongSwipeMode = false; + executeOnUiThread(this::onLongSwipeDisabledUi); + } + float translation = Math.max(displacement, 0); + float shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength; + mCurrentShift.updateValue(shift); + } } /** @@ -448,20 +497,18 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { float interpolated = interpolator.getInterpolation(shift); mClipAnimationHelper.applyTransform( mRecentsAnimationWrapper.targetSet, interpolated); - } - } - if (mRecentsAnimationWrapper.controller != null) { - // TODO: This logic is spartanic! - boolean passedThreshold = shift > 0.12f; - mRecentsAnimationWrapper.setAnimationTargetsBehindSystemBars(!passedThreshold); - if (mActivityControlHelper.shouldMinimizeSplitScreen()) { - mRecentsAnimationWrapper - .setSplitScreenMinimizedForTransaction(passedThreshold); + // TODO: This logic is spartanic! + boolean passedThreshold = shift > 0.12f; + mRecentsAnimationWrapper.setAnimationTargetsBehindSystemBars(!passedThreshold); + if (mActivityControlHelper.shouldMinimizeSplitScreen()) { + mRecentsAnimationWrapper + .setSplitScreenMinimizedForTransaction(passedThreshold); + } } } - mMainExecutor.execute(this::updateFinalShiftUi); + executeOnUiThread(this::updateFinalShiftUi); } private void updateFinalShiftUi() { @@ -539,10 +586,21 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { @WorkerThread public void onGestureEnded(float endVelocity) { - Resources res = mContext.getResources(); - float flingThreshold = res.getDimension(R.dimen.quickstep_fling_threshold_velocity); + float flingThreshold = mContext.getResources() + .getDimension(R.dimen.quickstep_fling_threshold_velocity); boolean isFling = mGestureStarted && Math.abs(endVelocity) > flingThreshold; + setStateOnUiThread(STATE_GESTURE_COMPLETED); + + mLogAction = isFling ? Touch.FLING : Touch.SWIPE; + + if (mBgLongSwipeMode) { + executeOnUiThread(() -> onLongSwipeGestureFinishUi(endVelocity, isFling)); + } else { + handleNormalGestureEnd(endVelocity, isFling); + } + } + private void handleNormalGestureEnd(float endVelocity, boolean isFling) { long duration = MAX_SWIPE_DURATION; final float endShift; if (!isFling) { @@ -550,10 +608,10 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { long expectedDuration = Math.abs(Math.round((endShift - mCurrentShift.value) * MAX_SWIPE_DURATION * SWIPE_DURATION_MULTIPLIER)); duration = Math.min(MAX_SWIPE_DURATION, expectedDuration); - mLogAction = Touch.SWIPE; } else { endShift = endVelocity < 0 ? 1 : 0; - float minFlingVelocity = res.getDimension(R.dimen.quickstep_fling_min_velocity); + float minFlingVelocity = mContext.getResources() + .getDimension(R.dimen.quickstep_fling_min_velocity); if (Math.abs(endVelocity) > minFlingVelocity && mTransitionDragLength > 0) { float distanceToTravel = (endShift - mCurrentShift.value) * mTransitionDragLength; @@ -563,7 +621,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { long baseDuration = Math.round(1000 * Math.abs(distanceToTravel / endVelocity)); duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration); } - mLogAction = Touch.FLING; } animateToProgress(endShift, duration, DEACCEL); @@ -593,8 +650,9 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { anim.addListener(new AnimationSuccessListener() { @Override public void onAnimationSuccess(Animator animator) { - setStateOnUiThread(mIsGoingToHome ? - STATE_SCALED_CONTROLLER_RECENTS : STATE_SCALED_CONTROLLER_APP); + setStateOnUiThread(mIsGoingToHome + ? (STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT) + : STATE_SCALED_CONTROLLER_APP); } }); anim.start(); @@ -633,6 +691,10 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { mRecentsView.setFirstTaskIconScaledDown(false /* isScaledDown */, false /* animate */); } + private void notifyTransitionCancelled() { + mAnimationFactory.onTransitionCancelled(); + } + private void resetStateForAnimationCancel() { boolean wasVisible = mWasLauncherAlreadyVisible || mGestureStarted; mActivityControlHelper.onTransitionCancelled(mActivity, wasVisible); @@ -646,13 +708,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { private void switchToScreenshot() { boolean finishTransitionPosted = false; - final Runnable finishTransitionRunnable = () -> { - synchronized (mRecentsAnimationWrapper) { - mRecentsAnimationWrapper.finish(true /* toHome */, - () -> setStateOnUiThread(STATE_SWITCH_TO_SCREENSHOT_COMPLETE)); - } - }; - synchronized (mRecentsAnimationWrapper) { if (mRecentsAnimationWrapper.controller != null) { // Update the screenshot of the task @@ -667,7 +722,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { @Override public void onPostDraw(Canvas canvas) { - finishTransitionRunnable.run(); + setStateOnUiThread(STATE_SCREENSHOT_CAPTURED); detach(); } }.attach(); @@ -675,8 +730,15 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { } } if (!finishTransitionPosted) { - // If we haven't posted the transition end runnable, run it now - finishTransitionRunnable.run(); + // If we haven't posted a draw callback, set the state immediately. + setStateOnUiThread(STATE_SCREENSHOT_CAPTURED); + } + } + + private void finishCurrentTransitionToHome() { + synchronized (mRecentsAnimationWrapper) { + mRecentsAnimationWrapper.finish(true /* toHome */, + () -> setStateOnUiThread(STATE_CURRENT_TASK_FINISHED)); } } @@ -773,4 +835,64 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> { public void setGestureEndCallback(Runnable gestureEndCallback) { mGestureEndCallback = gestureEndCallback; } + + // Handling long swipe + private void onLongSwipeEnabledUi() { + mUiLongSwipeMode = true; + checkLongSwipeCanEnter(); + checkLongSwipeCanStart(); + } + + private void onLongSwipeDisabledUi() { + mUiLongSwipeMode = false; + + if (mLongSwipeController != null) { + mLongSwipeController.destroy(); + + // Rebuild animations + buildAnimationController(); + } + } + + private void onLongSwipeDisplacementUpdated() { + if (!mUiLongSwipeMode || mLongSwipeController == null) { + return; + } + + mLongSwipeController.onMove(mLongSwipeDisplacement); + } + + private void checkLongSwipeCanEnter() { + if (!mUiLongSwipeMode || !mStateCallback.hasStates(LONG_SWIPE_ENTER_STATE) + || !mActivityControlHelper.supportsLongSwipe(mActivity)) { + return; + } + + // We are entering long swipe mode, make sure the screen shot is captured. + mStateCallback.setState(STATE_CAPTURE_SCREENSHOT); + + } + + private void checkLongSwipeCanStart() { + if (!mUiLongSwipeMode || !mStateCallback.hasStates(LONG_SWIPE_START_STATE) + || !mActivityControlHelper.supportsLongSwipe(mActivity)) { + return; + } + + mLongSwipeController = mActivityControlHelper.getLongSwipeController( + mActivity, mRecentsAnimationWrapper.targetSet); + onLongSwipeDisplacementUpdated(); + } + + private void onLongSwipeGestureFinishUi(float velocity, boolean isFling) { + if (!mUiLongSwipeMode || mLongSwipeController == null) { + handleNormalGestureEnd(velocity, isFling); + return; + } + + finishCurrentTransitionToHome(); + mLongSwipeController.end(velocity, isFling, + () -> setStateOnUiThread(STATE_HANDLER_INVALIDATED)); + + } } |