mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-03-03 17:36:49 +00:00
Long swipe from an app goes all the way to all-apps
Bug: 76449024 Change-Id: Ie6a0c5b7fd6d497ea8ac5f0a861a84c2290f84b1
This commit is contained in:
@@ -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() { }
|
||||
}
|
||||
}
|
||||
|
||||
162
quickstep/src/com/android/quickstep/LongSwipeHelper.java
Normal file
162
quickstep/src/com/android/quickstep/LongSwipeHelper.java
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -59,4 +59,8 @@ public class MultiStateCallback {
|
||||
public int getState() {
|
||||
return mState;
|
||||
}
|
||||
|
||||
public boolean hasStates(int stateMask) {
|
||||
return (mState & stateMask) == stateMask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user