Long swipe from an app goes all the way to all-apps

Bug: 76449024
Change-Id: Ie6a0c5b7fd6d497ea8ac5f0a861a84c2290f84b1
This commit is contained in:
Sunny Goyal
2018-04-25 10:17:56 -07:00
parent dcb74be7a6
commit f39e602a00
4 changed files with 394 additions and 60 deletions

View File

@@ -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() { }
}
}

View File

@@ -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();
}
}

View File

@@ -59,4 +59,8 @@ public class MultiStateCallback {
public int getState() {
return mState;
}
public boolean hasStates(int stateMask) {
return (mState & stateMask) == stateMask;
}
}

View File

@@ -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;
// We are moving in the negative x/y direction
displacement = -displacement;
if (displacement > mTransitionDragLength) {
mCurrentShift.updateValue(1);
float translation = Utilities.boundToRange(-mCurrentDisplacement, 0, mTransitionDragLength);
float shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength;
mCurrentShift.updateValue(shift);
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);
// TODO: This logic is spartanic!
boolean passedThreshold = shift > 0.12f;
mRecentsAnimationWrapper.setAnimationTargetsBehindSystemBars(!passedThreshold);
if (mActivityControlHelper.shouldMinimizeSplitScreen()) {
mRecentsAnimationWrapper
.setSplitScreenMinimizedForTransaction(passedThreshold);
}
}
}
if (mRecentsAnimationWrapper.controller != null) {
// 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));
}
}