diff options
author | Tony Wickham <twickham@google.com> | 2019-04-26 00:10:34 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2019-04-26 00:10:34 +0000 |
commit | 0cc53e7f6a37cd69aefe2d1b1c093f5465d84029 (patch) | |
tree | ee9edc3d9970723b6bc47b8daeaba1131d6c5131 | |
parent | 529bff9a66428ac263096d59d80b280a7d818c03 (diff) | |
parent | 5c13972e11e5eae185b141e61749415551f4857d (diff) | |
download | android_packages_apps_Trebuchet-0cc53e7f6a37cd69aefe2d1b1c093f5465d84029.tar.gz android_packages_apps_Trebuchet-0cc53e7f6a37cd69aefe2d1b1c093f5465d84029.tar.bz2 android_packages_apps_Trebuchet-0cc53e7f6a37cd69aefe2d1b1c093f5465d84029.zip |
Merge "Decouple recents view from window while swiping up" into ub-launcher3-qt-dev
4 files changed, 123 insertions, 13 deletions
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java index 35783b58a..a033402ff 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java @@ -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(); + } }; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java index bb320f2c5..5dc641fbe 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java @@ -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; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index 7ffd8d735..afc4fcb59 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -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; + } } diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java index a71b7bb85..17f88c980 100644 --- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java +++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java @@ -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 { |