Merge "Decouple recents view from window while swiping up" into ub-launcher3-qt-dev
This commit is contained in:
+26
-1
@@ -16,14 +16,15 @@
|
||||
package com.android.quickstep;
|
||||
|
||||
import static android.view.View.TRANSLATION_Y;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.allapps.AllAppsTransitionController.SPRING_DAMPING_RATIO;
|
||||
import static com.android.launcher3.allapps.AllAppsTransitionController.SPRING_STIFFNESS;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.quickstep.WindowTransformSwipeHandler.RECENTS_ATTACH_DURATION;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -177,6 +178,8 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
return new AnimationFactory() {
|
||||
private Animator mShelfAnim;
|
||||
private ShelfAnimState mShelfState;
|
||||
private Animator mAttachToWindowAnim;
|
||||
private boolean mIsAttachedToWindow;
|
||||
|
||||
@Override
|
||||
public void createActivityController(long transitionLength) {
|
||||
@@ -221,6 +224,28 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
|
||||
mShelfAnim.setDuration(duration);
|
||||
mShelfAnim.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRecentsAttachedToAppWindow(boolean attached, boolean animate) {
|
||||
if (mIsAttachedToWindow == attached && animate) {
|
||||
return;
|
||||
}
|
||||
mIsAttachedToWindow = attached;
|
||||
if (mAttachToWindowAnim != null) {
|
||||
mAttachToWindowAnim.cancel();
|
||||
}
|
||||
mAttachToWindowAnim = ObjectAnimator.ofFloat(activity.getOverviewPanel(),
|
||||
RecentsView.CONTENT_ALPHA, attached ? 1 : 0);
|
||||
mAttachToWindowAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mAttachToWindowAnim = null;
|
||||
}
|
||||
});
|
||||
mAttachToWindowAnim.setInterpolator(ACCEL_DEACCEL);
|
||||
mAttachToWindowAnim.setDuration(animate ? RECENTS_ATTACH_DURATION : 0);
|
||||
mAttachToWindowAnim.start();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -267,6 +267,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
mMotionPauseDetector.setDisallowPause(upDist < mMotionPauseMinDisplacement
|
||||
|| isLikelyToStartNewTask);
|
||||
mMotionPauseDetector.addPosition(displacement, ev.getEventTime());
|
||||
mInteractionHandler.setIsLikelyToStartNewTask(isLikelyToStartNewTask);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
+85
-8
@@ -43,6 +43,7 @@ import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.content.Context;
|
||||
@@ -111,6 +112,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
implements SwipeAnimationListener, OnApplyWindowInsetsListener {
|
||||
private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName();
|
||||
|
||||
private static final Rect TEMP_RECT = new Rect();
|
||||
|
||||
private static final String[] STATE_NAMES = DEBUG_STATES ? new String[16] : null;
|
||||
|
||||
private static int getFlagForIndex(int index, String name) {
|
||||
@@ -162,22 +165,23 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED;
|
||||
|
||||
enum GestureEndTarget {
|
||||
HOME(1, STATE_SCALED_CONTROLLER_HOME, true, false, ContainerType.WORKSPACE),
|
||||
HOME(1, STATE_SCALED_CONTROLLER_HOME, true, false, ContainerType.WORKSPACE, false),
|
||||
|
||||
RECENTS(1, STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT
|
||||
| STATE_SCREENSHOT_VIEW_SHOWN, true, false, ContainerType.TASKSWITCHER),
|
||||
| STATE_SCREENSHOT_VIEW_SHOWN, true, false, ContainerType.TASKSWITCHER, true),
|
||||
|
||||
NEW_TASK(0, STATE_START_NEW_TASK, false, true, ContainerType.APP),
|
||||
NEW_TASK(0, STATE_START_NEW_TASK, false, true, ContainerType.APP, true),
|
||||
|
||||
LAST_TASK(0, STATE_RESUME_LAST_TASK, false, true, ContainerType.APP);
|
||||
LAST_TASK(0, STATE_RESUME_LAST_TASK, false, true, ContainerType.APP, false);
|
||||
|
||||
GestureEndTarget(float endShift, int endState, boolean isLauncher, boolean canBeContinued,
|
||||
int containerType) {
|
||||
int containerType, boolean recentsAttachedToAppWindow) {
|
||||
this.endShift = endShift;
|
||||
this.endState = endState;
|
||||
this.isLauncher = isLauncher;
|
||||
this.canBeContinued = canBeContinued;
|
||||
this.containerType = containerType;
|
||||
this.recentsAttachedToAppWindow = recentsAttachedToAppWindow;
|
||||
}
|
||||
|
||||
/** 0 is app, 1 is overview */
|
||||
@@ -190,6 +194,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
public final boolean canBeContinued;
|
||||
/** Used to log where the user ended up after the gesture ends */
|
||||
public final int containerType;
|
||||
/** Whether RecentsView should be attached to the window as we animate to this target */
|
||||
public final boolean recentsAttachedToAppWindow;
|
||||
}
|
||||
|
||||
public static final long MAX_SWIPE_DURATION = 350;
|
||||
@@ -202,6 +208,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
private static final String SCREENSHOT_CAPTURED_EVT = "ScreenshotCaptured";
|
||||
|
||||
private static final long SHELF_ANIM_DURATION = 120;
|
||||
public static final long RECENTS_ATTACH_DURATION = 300;
|
||||
|
||||
/**
|
||||
* Used as the page index for logging when we return to the last task at the end of the gesture.
|
||||
@@ -254,6 +261,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
private int mLogAction = Touch.SWIPE;
|
||||
private int mLogDirection = Direction.UP;
|
||||
private PointF mDownPos;
|
||||
private boolean mIsLikelyToStartNewTask;
|
||||
|
||||
private final RecentsAnimationWrapper mRecentsAnimationWrapper;
|
||||
|
||||
@@ -437,6 +445,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
mAnimationFactory = mActivityControlHelper.prepareRecentsUI(mActivity,
|
||||
mWasLauncherAlreadyVisible, true,
|
||||
this::onAnimatorPlaybackControllerCreated);
|
||||
maybeUpdateRecentsAttachedState(false /* animate */);
|
||||
};
|
||||
if (mWasLauncherAlreadyVisible) {
|
||||
// Launcher is visible, but might be about to stop. Thus, if we prepare recents
|
||||
@@ -541,10 +550,65 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
setShelfState(isPaused ? PEEK : HIDE, FAST_OUT_SLOW_IN, SHELF_ANIM_DURATION);
|
||||
}
|
||||
|
||||
public void maybeUpdateRecentsAttachedState() {
|
||||
maybeUpdateRecentsAttachedState(true /* animate */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether to show or hide RecentsView. The window is always
|
||||
* synchronized with its corresponding TaskView in RecentsView, so if
|
||||
* RecentsView is shown, it will appear to be attached to the window.
|
||||
*
|
||||
* Note this method has no effect unless the navigation mode is NO_BUTTON.
|
||||
*/
|
||||
private void maybeUpdateRecentsAttachedState(boolean animate) {
|
||||
if (mMode != Mode.NO_BUTTON || mRecentsView == null) {
|
||||
return;
|
||||
}
|
||||
RemoteAnimationTargetCompat runningTaskTarget = mRecentsAnimationWrapper.targetSet == null
|
||||
? null
|
||||
: mRecentsAnimationWrapper.targetSet.findTask(mRunningTaskId);
|
||||
final boolean recentsAttachedToAppWindow;
|
||||
int runningTaskIndex = mRecentsView.getRunningTaskIndex();
|
||||
if (mContinuingLastGesture) {
|
||||
recentsAttachedToAppWindow = true;
|
||||
animate = false;
|
||||
} else if (runningTaskTarget != null && isNotInRecents(runningTaskTarget)) {
|
||||
// The window is going away so make sure recents is always visible in this case.
|
||||
recentsAttachedToAppWindow = true;
|
||||
animate = false;
|
||||
} else {
|
||||
if (mGestureEndTarget != null) {
|
||||
recentsAttachedToAppWindow = mGestureEndTarget.recentsAttachedToAppWindow;
|
||||
} else {
|
||||
recentsAttachedToAppWindow = mIsShelfPeeking || mIsLikelyToStartNewTask;
|
||||
}
|
||||
if (animate) {
|
||||
// Only animate if an adjacent task view is visible on screen.
|
||||
TaskView adjacentTask1 = mRecentsView.getTaskViewAt(runningTaskIndex + 1);
|
||||
TaskView adjacentTask2 = mRecentsView.getTaskViewAt(runningTaskIndex - 1);
|
||||
animate = (adjacentTask1 != null && adjacentTask1.getGlobalVisibleRect(TEMP_RECT))
|
||||
|| (adjacentTask2 != null && adjacentTask2.getGlobalVisibleRect(TEMP_RECT));
|
||||
}
|
||||
}
|
||||
mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate);
|
||||
}
|
||||
|
||||
public void setIsLikelyToStartNewTask(boolean isLikelyToStartNewTask) {
|
||||
if (mIsLikelyToStartNewTask != isLikelyToStartNewTask) {
|
||||
mIsLikelyToStartNewTask = isLikelyToStartNewTask;
|
||||
maybeUpdateRecentsAttachedState();
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void setShelfState(ShelfAnimState shelfState, Interpolator interpolator, long duration) {
|
||||
mAnimationFactory.setShelfState(shelfState, interpolator, duration);
|
||||
boolean wasShelfPeeking = mIsShelfPeeking;
|
||||
mIsShelfPeeking = shelfState == PEEK;
|
||||
if (mIsShelfPeeking != wasShelfPeeking) {
|
||||
maybeUpdateRecentsAttachedState();
|
||||
}
|
||||
if (mRecentsView != null && shelfState.shouldPreformHaptic) {
|
||||
mRecentsView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
|
||||
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
|
||||
@@ -872,6 +936,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) {
|
||||
mGestureEndTarget = target;
|
||||
|
||||
maybeUpdateRecentsAttachedState();
|
||||
|
||||
if (mGestureEndTarget == HOME) {
|
||||
HomeAnimationFactory homeAnimFactory;
|
||||
if (mActivity != null) {
|
||||
@@ -905,8 +971,15 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
windowAnim.start(velocityPxPerMs);
|
||||
mLauncherTransitionController = null;
|
||||
} else {
|
||||
Animator windowAnim = mCurrentShift.animateToValue(start, end);
|
||||
ValueAnimator windowAnim = mCurrentShift.animateToValue(start, end);
|
||||
windowAnim.setDuration(duration).setInterpolator(interpolator);
|
||||
windowAnim.addUpdateListener(valueAnimator -> {
|
||||
if (mRecentsView != null && mRecentsView.getVisibility() != View.VISIBLE) {
|
||||
// Views typically don't compute scroll when invisible as an optimization,
|
||||
// but in our case we need to since the window offset depends on the scroll.
|
||||
mRecentsView.computeScroll();
|
||||
}
|
||||
});
|
||||
windowAnim.addListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
@@ -1180,10 +1253,14 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
||||
}
|
||||
|
||||
public static float getHiddenTargetAlpha(RemoteAnimationTargetCompat app, Float expectedAlpha) {
|
||||
if (!(app.isNotInRecents
|
||||
|| app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME)) {
|
||||
if (!isNotInRecents(app)) {
|
||||
return 0;
|
||||
}
|
||||
return expectedAlpha;
|
||||
}
|
||||
|
||||
private static boolean isNotInRecents(RemoteAnimationTargetCompat app) {
|
||||
return app.isNotInRecents
|
||||
|| app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,10 @@ import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
@@ -37,10 +41,6 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
/**
|
||||
* Utility class which abstracts out the logical differences between Launcher and RecentsActivity.
|
||||
*/
|
||||
@@ -122,6 +122,13 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
|
||||
|
||||
default void setShelfState(ShelfAnimState animState, Interpolator interpolator,
|
||||
long duration) { }
|
||||
|
||||
/**
|
||||
* @param attached Whether to show RecentsView alongside the app window. If false, recents
|
||||
* will be hidden by some property we can animate, e.g. alpha.
|
||||
* @param animate Whether to animate recents to/from its new attached state.
|
||||
*/
|
||||
default void setRecentsAttachedToAppWindow(boolean attached, boolean animate) { }
|
||||
}
|
||||
|
||||
interface HomeAnimationFactory {
|
||||
|
||||
Reference in New Issue
Block a user