Merge "Decouple recents view from window while swiping up" into ub-launcher3-qt-dev

This commit is contained in:
Tony Wickham
2019-04-26 00:10:34 +00:00
committed by Android (Google) Code Review
4 changed files with 123 additions and 13 deletions
@@ -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();
}
};
}
@@ -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;
@@ -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 {