Polish transition between desktop mode and overview
Fixing desktop task in place along the x-axis and animating its background's alpha to more smoothly handle the transition.
Flag: com.android.launcher3.enable_desktop_task_alpha_animation
Fixes: 320307666
Test: swiped to and from desktop mode and overview
Change-Id: I38d62d0c966733f96c2f4d4ecfa4a9418039fd48
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index be8ebbb..dbcf49c 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -339,3 +339,13 @@
description: "Change fast scroller to a lettered list"
bug: "358673724"
}
+
+flag {
+ name: "enable_desktop_task_alpha_animation"
+ namespace: "launcher"
+ description: "Enables the animation of the desktop task's background view"
+ bug: "320307666"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 5392b70..3d94442 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -734,11 +734,18 @@
}
private void maybeUpdateRecentsAttachedState() {
- maybeUpdateRecentsAttachedState(true /* animate */);
+ maybeUpdateRecentsAttachedState(/* animate= */ true);
}
protected void maybeUpdateRecentsAttachedState(boolean animate) {
- maybeUpdateRecentsAttachedState(animate, false /* moveRunningTask */);
+ maybeUpdateRecentsAttachedState(animate, /* moveRunningTask= */ false);
+ }
+
+ protected void maybeUpdateRecentsAttachedState(boolean animate, boolean moveRunningTask) {
+ maybeUpdateRecentsAttachedState(
+ animate,
+ moveRunningTask,
+ mRecentsView != null && mRecentsView.shouldUpdateRunningTaskAlpha());
}
/**
@@ -749,8 +756,10 @@
* Note this method has no effect unless the navigation mode is NO_BUTTON.
* @param animate whether to animate when attaching RecentsView
* @param moveRunningTask whether to move running task to front when attaching
+ * @param updateRunningTaskAlpha Whether to update the running task's attached alpha
*/
- private void maybeUpdateRecentsAttachedState(boolean animate, boolean moveRunningTask) {
+ private void maybeUpdateRecentsAttachedState(
+ boolean animate, boolean moveRunningTask, boolean updateRunningTaskAlpha) {
if ((!mDeviceState.isFullyGesturalNavMode() && !mGestureState.isTrackpadGesture())
|| mRecentsView == null) {
return;
@@ -781,7 +790,8 @@
// TaskView jumping to new position as we move the tasks.
mRecentsView.moveRunningTaskToFront();
}
- mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate);
+ mAnimationFactory.setRecentsAttachedToAppWindow(
+ recentsAttachedToAppWindow, animate, updateRunningTaskAlpha);
// Reapply window transform throughout the attach animation, as the animation affects how
// much the window is bound by overscroll (vs moving freely).
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 293944d..8703843 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -21,11 +21,13 @@
import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
import static com.android.quickstep.AbsSwipeUpHandler.RECENTS_ATTACH_DURATION;
import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
+import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_ATTACHED_ALPHA_ANIM;
import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM;
import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_TRANSLATE_X_ANIM;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
+import static com.android.quickstep.views.RecentsView.RUNNING_TASK_ATTACH_ALPHA;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import android.animation.Animator;
@@ -187,8 +189,10 @@
* @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.
+ * @param updateRunningTaskAlpha Whether to update the running task's attached alpha
*/
- default void setRecentsAttachedToAppWindow(boolean attached, boolean animate) { }
+ default void setRecentsAttachedToAppWindow(
+ boolean attached, boolean animate, boolean updateRunningTaskAlpha) { }
default boolean isRecentsAttachedToAppWindow() {
return false;
@@ -253,12 +257,14 @@
// (because we set the animation as the current state animation), so we reapply the
// attached state here as well to ensure recents is shown/hidden appropriately.
if (DisplayController.getNavigationMode(mActivity) == NavigationMode.NO_BUTTON) {
- setRecentsAttachedToAppWindow(mIsAttachedToWindow, false);
+ setRecentsAttachedToAppWindow(
+ mIsAttachedToWindow, false, recentsView.shouldUpdateRunningTaskAlpha());
}
}
@Override
- public void setRecentsAttachedToAppWindow(boolean attached, boolean animate) {
+ public void setRecentsAttachedToAppWindow(
+ boolean attached, boolean animate, boolean updateRunningTaskAlpha) {
if (mIsAttachedToWindow == attached && animate) {
return;
}
@@ -266,6 +272,10 @@
.cancelStateElementAnimation(INDEX_RECENTS_FADE_ANIM);
mActivity.getStateManager()
.cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM);
+ if (updateRunningTaskAlpha) {
+ mActivity.getStateManager()
+ .cancelStateElementAnimation(INDEX_RECENTS_ATTACHED_ALPHA_ANIM);
+ }
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.addListener(new AnimatorListenerAdapter() {
@@ -280,19 +290,28 @@
long animationDuration = animate ? RECENTS_ATTACH_DURATION : 0;
Animator fadeAnim = mActivity.getStateManager()
- .createStateElementAnimation(INDEX_RECENTS_FADE_ANIM, attached ? 1 : 0);
+ .createStateElementAnimation(INDEX_RECENTS_FADE_ANIM, attached ? 1f : 0f);
fadeAnim.setInterpolator(attached ? INSTANT : ACCELERATE_2);
fadeAnim.setDuration(animationDuration);
animatorSet.play(fadeAnim);
float fromTranslation = ADJACENT_PAGE_HORIZONTAL_OFFSET.get(
mActivity.getOverviewPanel());
- float toTranslation = attached ? 0 : 1;
-
+ float toTranslation = attached ? 0f : 1f;
Animator translationAnimator = mActivity.getStateManager().createStateElementAnimation(
INDEX_RECENTS_TRANSLATE_X_ANIM, fromTranslation, toTranslation);
translationAnimator.setDuration(animationDuration);
animatorSet.play(translationAnimator);
+
+ if (updateRunningTaskAlpha) {
+ float fromAlpha = RUNNING_TASK_ATTACH_ALPHA.get(mActivity.getOverviewPanel());
+ float toAlpha = attached ? 1f : 0f;
+ Animator runningTaskAttachAlphaAnimator = mActivity.getStateManager()
+ .createStateElementAnimation(
+ INDEX_RECENTS_ATTACHED_ALPHA_ANIM, fromAlpha, toAlpha);
+ runningTaskAttachAlphaAnimator.setDuration(animationDuration);
+ animatorSet.play(runningTaskAttachAlphaAnimator);
+ }
animatorSet.start();
}
diff --git a/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java b/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
index 0b05c2e..63fe017 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
@@ -16,6 +16,7 @@
package com.android.quickstep.util;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
+import static com.android.quickstep.views.RecentsView.RUNNING_TASK_ATTACH_ALPHA;
import android.animation.Animator;
import android.animation.ObjectAnimator;
@@ -33,8 +34,10 @@
public static final int INDEX_RECENTS_FADE_ANIM = AtomicAnimationFactory.NEXT_INDEX + 0;
public static final int INDEX_RECENTS_TRANSLATE_X_ANIM = AtomicAnimationFactory.NEXT_INDEX + 1;
+ public static final int INDEX_RECENTS_ATTACHED_ALPHA_ANIM =
+ AtomicAnimationFactory.NEXT_INDEX + 2;
- private static final int MY_ANIM_COUNT = 2;
+ private static final int MY_ANIM_COUNT = 3;
protected final CONTAINER mContainer;
@@ -50,6 +53,7 @@
ObjectAnimator alpha = ObjectAnimator.ofFloat(mContainer.getOverviewPanel(),
RecentsView.CONTENT_ALPHA, values);
return alpha;
+ case INDEX_RECENTS_ATTACHED_ALPHA_ANIM:
case INDEX_RECENTS_TRANSLATE_X_ANIM: {
RecentsView rv = mContainer.getOverviewPanel();
return new SpringAnimationBuilder(mContainer)
@@ -57,7 +61,8 @@
.setDampingRatio(0.8f)
.setStiffness(250)
.setValues(values)
- .build(rv, ADJACENT_PAGE_HORIZONTAL_OFFSET);
+ .build(rv, index == INDEX_RECENTS_ATTACHED_ALPHA_ANIM
+ ? RUNNING_TASK_ATTACH_ALPHA : ADJACENT_PAGE_HORIZONTAL_OFFSET);
}
default:
return super.createStateElementAnimation(index, values);
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index f1ff026..69a9690 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -36,6 +36,7 @@
import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.Flags.enableAdditionalHomeAnimations;
+import static com.android.launcher3.Flags.enableDesktopTaskAlphaAnimation;
import static com.android.launcher3.Flags.enableGridOnlyOverview;
import static com.android.launcher3.Flags.enableLargeDesktopWindowingTile;
import static com.android.launcher3.Flags.enableRefactorTaskThumbnail;
@@ -320,6 +321,27 @@
}
};
+ public static final FloatProperty<RecentsView> RUNNING_TASK_ATTACH_ALPHA =
+ new FloatProperty<RecentsView>("runningTaskAttachAlpha") {
+ @Override
+ public void setValue(RecentsView recentsView, float v) {
+ TaskView runningTask = recentsView.getRunningTaskView();
+ if (runningTask == null) {
+ return;
+ }
+ runningTask.setAttachAlpha(v);
+ }
+
+ @Override
+ public Float get(RecentsView recentsView) {
+ TaskView runningTask = recentsView.getRunningTaskView();
+ if (runningTask == null) {
+ return null;
+ }
+ return runningTask.getAttachAlpha();
+ }
+ };
+
public static final int SCROLL_VIBRATION_PRIMITIVE =
Utilities.ATLEAST_S ? VibrationEffect.Composition.PRIMITIVE_LOW_TICK : -1;
public static final float SCROLL_VIBRATION_PRIMITIVE_SCALE = 0.6f;
@@ -2737,10 +2759,17 @@
showCurrentTask(mActiveGestureRunningTasks);
setEnableFreeScroll(false);
setEnableDrawingLiveTile(false);
- setRunningTaskHidden(true);
+ setRunningTaskHidden(!shouldUpdateRunningTaskAlpha());
setTaskIconScaledDown(true);
}
+ /**
+ * Returns whether the running task's attach alpha should be updated during the attach animation
+ */
+ public boolean shouldUpdateRunningTaskAlpha() {
+ return enableDesktopTaskAlphaAnimation() && getRunningTaskView() instanceof DesktopTaskView;
+ }
+
private boolean isGestureActive() {
return mActiveGestureRunningTasks != null;
}
@@ -3021,12 +3050,13 @@
public void setRunningTaskHidden(boolean isHidden) {
mRunningTaskTileHidden = isHidden;
TaskView runningTask = getRunningTaskView();
- if (runningTask != null) {
- runningTask.setStableAlpha(isHidden ? 0 : mContentAlpha);
- if (!isHidden) {
- AccessibilityManagerCompat.sendCustomAccessibilityEvent(runningTask,
- AccessibilityEvent.TYPE_VIEW_FOCUSED, null);
- }
+ if (runningTask == null) {
+ return;
+ }
+ runningTask.setStableAlpha(isHidden ? 0 : mContentAlpha);
+ if (!isHidden) {
+ AccessibilityManagerCompat.sendCustomAccessibilityEvent(
+ runningTask, AccessibilityEvent.TYPE_VIEW_FOCUSED, null);
}
}
@@ -4701,8 +4731,11 @@
: showAsGrid
? gridOffsetSize
: i < modalMidpoint ? modalLeftOffsetSize : modalRightOffsetSize;
- float totalTranslationX = translation + modalTranslation;
View child = getChildAt(i);
+ boolean skipTranslationOffset = enableDesktopTaskAlphaAnimation()
+ && i == getRunningTaskIndex()
+ && child instanceof DesktopTaskView;
+ float totalTranslationX = (skipTranslationOffset ? 0f : translation) + modalTranslation;
FloatProperty translationPropertyX = child instanceof TaskView
? ((TaskView) child).getPrimaryTaskOffsetTranslationProperty()
: getPagedOrientationHandler().getPrimaryViewTranslate();
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index e43d7b4..b18f0b1 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -65,6 +65,7 @@
import com.android.launcher3.util.Executors
import com.android.launcher3.util.MultiPropertyFactory
import com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE
+import com.android.launcher3.util.MultiValueAlpha
import com.android.launcher3.util.RunnableList
import com.android.launcher3.util.SafeCloseable
import com.android.launcher3.util.SplitConfigurationOptions
@@ -391,11 +392,19 @@
applyTranslationX()
}
- protected var stableAlpha = 1f
+ private val taskViewAlpha = MultiValueAlpha(this, NUM_ALPHA_CHANNELS)
+
+ protected var stableAlpha
set(value) {
- field = value
- alpha = stableAlpha
+ taskViewAlpha.get(ALPHA_INDEX_STABLE).value = value
}
+ get() = taskViewAlpha.get(ALPHA_INDEX_STABLE).value
+
+ protected var attachAlpha
+ set(value) {
+ taskViewAlpha.get(ALPHA_INDEX_ATTACH).value = value
+ }
+ get() = taskViewAlpha.get(ALPHA_INDEX_ATTACH).value
protected var shouldShowScreenshot = false
get() = !isRunningTask || field
@@ -1584,7 +1593,7 @@
}
dismissScale = 1f
translationZ = 0f
- alpha = stableAlpha
+ attachAlpha = 1f
setIconScaleAndDim(1f)
setColorTint(0f, 0)
}
@@ -1661,6 +1670,11 @@
const val FOCUS_TRANSITION_INDEX_SCALE_AND_DIM = 1
const val FOCUS_TRANSITION_INDEX_COUNT = 2
+ private const val ALPHA_INDEX_STABLE = 0
+ private const val ALPHA_INDEX_ATTACH = 1
+
+ private const val NUM_ALPHA_CHANNELS = 2
+
/** The maximum amount that a task view can be scrimmed, dimmed or tinted. */
const val MAX_PAGE_SCRIM_ALPHA = 0.4f
const val SCALE_ICON_DURATION: Long = 120