Merge "Update animations for TM-QPR: Overview > OverviewSplitSelect transition" into tm-qpr-dev am: cf03d04469

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/19464657

Change-Id: I7d9f934c423d33ece6b5603097828765109552ff
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Jeremy Sim
2022-08-15 21:39:03 +00:00
committed by Automerger Merge Worker
11 changed files with 175 additions and 33 deletions

View File

@@ -188,6 +188,9 @@ public class QuickstepAtomicAnimationFactory extends
AllAppsSwipeController.applyAllAppsToNormalConfig(mActivity, config);
} else if (fromState == NORMAL && toState == ALL_APPS) {
AllAppsSwipeController.applyNormalToAllAppsAnimConfig(mActivity, config);
} else if (fromState == OVERVIEW && toState == OVERVIEW_SPLIT_SELECT) {
config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE,
clampToProgress(LINEAR, 0, 0.167f));
}
}
}

View File

@@ -16,6 +16,8 @@
package com.android.launcher3.uioverrides.states;
import android.content.Context;
import com.android.launcher3.Launcher;
import com.android.quickstep.views.RecentsView;
@@ -24,6 +26,8 @@ import com.android.quickstep.views.RecentsView;
* pinned and user is selecting the second one
*/
public class SplitScreenSelectState extends OverviewState {
private static final int OVERVIEW_SPLIT_SELECT_SLIDE_IN_DURATION = 500;
public SplitScreenSelectState(int id) {
super(id);
}
@@ -38,4 +42,9 @@ public class SplitScreenSelectState extends OverviewState {
RecentsView recentsView = launcher.getOverviewPanel();
return recentsView.getSplitSelectTranslation();
}
@Override
public int getTransitionDuration(Context context, boolean isToState) {
return OVERVIEW_SPLIT_SELECT_SLIDE_IN_DURATION;
}
}

View File

@@ -2,8 +2,9 @@ package com.android.quickstep.views;
import static com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
import static com.android.launcher3.anim.Interpolators.FASTER_OUT_SLOWER_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.clampToProgress;
import android.animation.ValueAnimator;
import android.content.Context;
@@ -200,10 +201,16 @@ public class FloatingTaskView extends FrameLayout {
RectF floatingTaskViewBounds = new RectF();
if (fadeWithThumbnail) {
animation.addFloat(mSplitPlaceholderView, SplitPlaceholderView.ALPHA_FLOAT,
0, 1, ACCEL);
// FloatingTaskThumbnailView: thumbnail fades out to transparent
animation.addFloat(mThumbnailView, LauncherAnimUtils.VIEW_ALPHA,
1, 0, DEACCEL_3);
1, 0, clampToProgress(LINEAR, 0, 0.267f));
// SplitPlaceholderView: gray background fades in at the same time, then new icon fades
// in
animation.addFloat(mSplitPlaceholderView, SplitPlaceholderView.ALPHA_FLOAT,
0, 1, clampToProgress(LINEAR, 0, 0.267f));
animation.addFloat(mSplitPlaceholderView, SplitPlaceholderView.ICON_ALPHA,
0, 1, clampToProgress(LINEAR, 0.333f, 0.5f));
} else if (isStagedTask) {
// Fade in the placeholder view when split is initiated from homescreen / all apps
// icons.
@@ -214,12 +221,15 @@ public class FloatingTaskView extends FrameLayout {
}
MultiValueUpdateListener listener = new MultiValueUpdateListener() {
final FloatProp mDx = new FloatProp(0, prop.dX, 0, animDuration, LINEAR);
final FloatProp mDy = new FloatProp(0, prop.dY, 0, animDuration, LINEAR);
// SplitPlaceholderView: rectangle translates and stretches to new position
final FloatProp mDx = new FloatProp(0, prop.dX, 0, animDuration,
clampToProgress(FASTER_OUT_SLOWER_IN, 0, 0.833f));
final FloatProp mDy = new FloatProp(0, prop.dY, 0, animDuration,
clampToProgress(FASTER_OUT_SLOWER_IN, 0, 0.833f));
final FloatProp mTaskViewScaleX = new FloatProp(1f, prop.finalTaskViewScaleX, 0,
animDuration, LINEAR);
animDuration, clampToProgress(FASTER_OUT_SLOWER_IN, 0, 0.833f));
final FloatProp mTaskViewScaleY = new FloatProp(1f, prop.finalTaskViewScaleY, 0,
animDuration, LINEAR);
animDuration, clampToProgress(FASTER_OUT_SLOWER_IN, 0, 0.833f));
@Override
public void onUpdate(float percent, boolean initOnly) {
// Calculate the icon position.

View File

@@ -35,6 +35,7 @@ import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.ACCEL_0_75;
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.anim.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
import static com.android.launcher3.anim.Interpolators.LINEAR;
@@ -113,6 +114,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.core.graphics.ColorUtils;
import androidx.dynamicanimation.animation.SpringForce;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseActivity.MultiWindowModeChangedListener;
@@ -125,6 +127,7 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.launcher3.anim.SpringProperty;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
@@ -442,6 +445,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
private static final float ANIMATION_DISMISS_PROGRESS_MIDPOINT = 0.5f;
private static final float END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET = 0.75f;
private static final float INITIAL_SPRING_DISMISS_TRANSLATION_INTERPOLATION_OFFSET = 0.133f;
private static final float ADDITIONAL_SPRING_DISMISS_TRANSLATION_INTERPOLATION_OFFSET = 0.033f;
private static final float SIGNIFICANT_MOVE_SCREEN_WIDTH_PERCENTAGE = 0.15f;
protected final RecentsOrientedState mOrientationState;
@@ -2825,7 +2831,20 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
RectF startingTaskRect = new RectF();
if (mSplitHiddenTaskView != null) {
mSplitHiddenTaskView.setVisibility(INVISIBLE);
// Split staging is initiated, hide the original TaskView except for the icon (which
// needs to animate out over time)
// If needed, visibility should be toggled back on in resetFromSplitSelectionState().
for (int i = 0; i < mSplitHiddenTaskView.getChildCount(); i++) {
View child = mSplitHiddenTaskView.getChildAt(i);
if (child != mSplitHiddenTaskView.mIconView) {
child.setVisibility(INVISIBLE);
}
}
// Icon animates out over time
anim.addFloat(mSplitHiddenTaskView, TaskView.ICON_ALPHA, 1, 0,
clampToProgress(LINEAR, 0, 0.167f));
mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
mSplitHiddenTaskView.getThumbnail(),
mSplitHiddenTaskView.getThumbnail().getThumbnail(),
@@ -2842,9 +2861,15 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
false /* fadeWithThumbnail */, true /* isStagedTask */);
}
// SplitInstructionsView: animate in
mSplitInstructionsView = SplitInstructionsView.getSplitInstructionsView(mActivity);
mSplitInstructionsView.setAlpha(0);
anim.addFloat(mSplitInstructionsView, SplitInstructionsView.ALPHA_FLOAT, 0, 1, ACCEL);
anim.addFloat(mSplitInstructionsView, SplitInstructionsView.CONTAINER_ALPHA, 0, 1,
clampToProgress(LINEAR, 0, 0.167f));
anim.addFloat(mSplitInstructionsView, SplitInstructionsView.TEXT_ALPHA, 0, 1,
clampToProgress(LINEAR, 0.1f, 0.267f));
anim.addFloat(mSplitInstructionsView, mSplitInstructionsView.UNFOLD, 0.1f, 1,
clampToProgress(EMPHASIZED_DECELERATE, 0, 0.667f));
InteractionJankMonitorWrapper.begin(this,
InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER, "First tile selected");
@@ -3124,11 +3149,22 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
// Animate task with index >= dismissed index and in the same row as the
// dismissed index or next focused index. Offset successive task dismissal
// durations for a staggered effect.
float animationStartProgress = Utilities.boundToRange(
INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
+ ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
* ++distanceFromDismissedTask, 0f,
dismissTranslationInterpolationEnd);
distanceFromDismissedTask++;
// If user is initiating splitscreen from the focused (large) task, we use a
// spring-based animation and timings. For other, smaller, repositions, we currently
// fall back on a less complicated linear animation and timings.
float animationStartProgress = isFocusedTaskDismissed && nextFocusedTaskView == null
? Utilities.boundToRange(
INITIAL_SPRING_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
+ ADDITIONAL_SPRING_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
* (int) Math.ceil(distanceFromDismissedTask / 2f), 0f,
dismissTranslationInterpolationEnd)
: Utilities.boundToRange(
INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
+ ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
* distanceFromDismissedTask, 0f,
dismissTranslationInterpolationEnd);
if (taskView == nextFocusedTaskView) {
// Enlarge the task to be focused next, and translate into focus position.
float scale = mTaskWidth / (float) mLastComputedGridTaskSize.width();
@@ -3163,12 +3199,36 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
primaryTranslation +=
mIsRtl ? -mSplitPlaceholderSize : mSplitPlaceholderSize;
}
}
anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(),
mIsRtl ? primaryTranslation : -primaryTranslation,
clampToProgress(LINEAR, animationStartProgress,
dismissTranslationInterpolationEnd));
// Transitioning to split select -- set up staggered spring animation for
// other TaskViews.
Animator taskSlideIn = new SpringAnimationBuilder(taskView.mActivity)
.setDampingRatio(0.85f)
.setStiffness(SpringForce.STIFFNESS_LOW)
.setEndValue(mIsRtl ? primaryTranslation : -primaryTranslation)
.setStartValue(
taskView.getPrimaryDismissTranslationProperty()
.get(taskView)
)
.build(taskView, taskView.getPrimaryDismissTranslationProperty());
long taskSlideInDuration = taskSlideIn.getDuration();
anim.add(taskSlideIn);
taskSlideIn
.setDuration(taskSlideInDuration)
.setStartDelay(
Math.round(animationStartProgress * anim.getDuration()));
} else {
// Task was dismissed individually -- translate other TaskViews to fill the
// vacant space.
// TODO (b/242075836): This dismiss animation uses a linear transition.
// When the above bug is fixed, it can use the same (nicer) spring
// transition as the focused task split case above.
anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(),
mIsRtl ? primaryTranslation : -primaryTranslation,
clampToProgress(LINEAR, animationStartProgress,
dismissTranslationInterpolationEnd));
}
}
}
}
@@ -3189,7 +3249,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
final boolean finalCloseGapBetweenClearAll = closeGapBetweenClearAll;
final boolean finalSnapToLastTask = snapToLastTask;
final boolean finalIsFocusedTaskDismissed = isFocusedTaskDismissed;
mPendingAnimation.addEndListener(new Consumer<Boolean>() {
Consumer endConsumer = new Consumer<Boolean>() {
@Override
public void accept(Boolean success) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile
@@ -3399,7 +3460,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
onDismissAnimationEnds();
mPendingAnimation = null;
}
});
};
mPendingAnimation.addListener(AnimatorListeners.forEndCallback(endConsumer));
return anim;
}
@@ -4220,7 +4283,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
resetTaskVisuals();
mSplitHiddenTaskViewIndex = -1;
if (mSplitHiddenTaskView != null) {
mSplitHiddenTaskView.setVisibility(VISIBLE);
mSplitHiddenTaskView = null;
}
}

View File

@@ -25,6 +25,7 @@ import android.view.ViewGroup;
import android.widget.FrameLayout;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
@@ -40,9 +41,10 @@ import com.android.launcher3.util.DisplayController;
*/
public class SplitInstructionsView extends FrameLayout {
private final StatefulActivity mLauncher;
private AppCompatTextView mTextView;
public static final FloatProperty<SplitInstructionsView> ALPHA_FLOAT =
new FloatProperty<SplitInstructionsView>("SplitInstructionsAlpha") {
public static final FloatProperty<SplitInstructionsView> CONTAINER_ALPHA =
new FloatProperty<SplitInstructionsView>("SplitInstructionsContainerAlpha") {
@Override
public void setValue(SplitInstructionsView splitInstructionsView, float v) {
splitInstructionsView.setVisibility(v != 0 ? VISIBLE : GONE);
@@ -55,6 +57,32 @@ public class SplitInstructionsView extends FrameLayout {
}
};
public static final FloatProperty<SplitInstructionsView> UNFOLD =
new FloatProperty<SplitInstructionsView>("SplitInstructionsUnfold") {
@Override
public void setValue(SplitInstructionsView splitInstructionsView, float v) {
splitInstructionsView.setScaleY(v);
}
@Override
public Float get(SplitInstructionsView splitInstructionsView) {
return splitInstructionsView.getScaleY();
}
};
public static final FloatProperty<SplitInstructionsView> TEXT_ALPHA =
new FloatProperty<SplitInstructionsView>("SplitInstructionsTextAlpha") {
@Override
public void setValue(SplitInstructionsView splitInstructionsView, float v) {
splitInstructionsView.mTextView.setAlpha(v);
}
@Override
public Float get(SplitInstructionsView splitInstructionsView) {
return splitInstructionsView.mTextView.getAlpha();
}
};
public SplitInstructionsView(Context context) {
this(context, null);
}
@@ -77,6 +105,9 @@ public class SplitInstructionsView extends FrameLayout {
false
);
splitInstructionsView.mTextView = splitInstructionsView.findViewById(
R.id.split_instructions_text);
dragLayer.addView(splitInstructionsView);
return splitInstructionsView;
}

View File

@@ -47,6 +47,19 @@ public class SplitPlaceholderView extends FrameLayout {
}
};
public static final FloatProperty<SplitPlaceholderView> ICON_ALPHA =
new FloatProperty<SplitPlaceholderView>("SplitViewIconAlpha") {
@Override
public void setValue(SplitPlaceholderView splitPlaceholderView, float v) {
splitPlaceholderView.mIconView.setAlpha(v);
}
@Override
public Float get(SplitPlaceholderView splitPlaceholderView) {
return splitPlaceholderView.mIconView.getAlpha();
}
};
@Nullable
private IconView mIconView;

View File

@@ -323,6 +323,19 @@ public class TaskView extends FrameLayout implements Reusable {
}
};
public static final FloatProperty<TaskView> ICON_ALPHA =
new FloatProperty<TaskView>("iconAlpha") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.mIconView.setAlpha(v);
}
@Override
public Float get(TaskView taskView) {
return taskView.mIconView.getAlpha();
}
};
@Nullable
protected Task mTask;
protected TaskThumbnailView mSnapshotView;

View File

@@ -50,6 +50,8 @@ public class Interpolators {
public static final Interpolator ACCEL_DEACCEL = new AccelerateDecelerateInterpolator();
public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
public static final Interpolator FASTER_OUT_SLOWER_IN =
new PathInterpolator(0.3f, 0f, 0.1f, 1f);
public static final Interpolator AGGRESSIVE_EASE = new PathInterpolator(0.2f, 0f, 0f, 1f);
public static final Interpolator AGGRESSIVE_EASE_IN_OUT = new PathInterpolator(0.6f,0, 0.4f, 1);

View File

@@ -440,7 +440,7 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
public void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
int splitInstructionsWidth, int threeButtonNavShift) {
out.setPivotX(0);
out.setPivotY(0);
out.setPivotY(splitInstructionsHeight);
out.setRotation(getDegreesRotated());
int distanceToEdge = out.getResources().getDimensionPixelSize(
R.dimen.split_instructions_bottom_margin_phone_landscape);
@@ -448,8 +448,8 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
int insetCorrectionX = dp.getInsets().left;
// Center the view in case of unbalanced insets on top or bottom of screen
int insetCorrectionY = (dp.getInsets().bottom - dp.getInsets().top) / 2;
out.setTranslationX(splitInstructionsHeight + distanceToEdge - insetCorrectionX);
out.setTranslationY(((splitInstructionsHeight - splitInstructionsWidth) / 2f)
out.setTranslationX(distanceToEdge - insetCorrectionX);
out.setTranslationY(((-splitInstructionsHeight - splitInstructionsWidth) / 2f)
+ insetCorrectionY);
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) out.getLayoutParams();
// Setting gravity to LEFT instead of the lint-recommended START because we always want this

View File

@@ -500,7 +500,7 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
public void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
int splitInstructionsWidth, int threeButtonNavShift) {
out.setPivotX(0);
out.setPivotY(0);
out.setPivotY(splitInstructionsHeight);
out.setRotation(getDegreesRotated());
int distanceToEdge;
if ((DisplayController.getNavigationMode(out.getContext()) == THREE_BUTTONS)

View File

@@ -190,7 +190,7 @@ public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
public void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
int splitInstructionsWidth, int threeButtonNavShift) {
out.setPivotX(0);
out.setPivotY(0);
out.setPivotY(splitInstructionsHeight);
out.setRotation(getDegreesRotated());
int distanceToEdge = out.getResources().getDimensionPixelSize(
R.dimen.split_instructions_bottom_margin_phone_landscape);
@@ -198,9 +198,8 @@ public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
int insetCorrectionX = dp.getInsets().right;
// Center the view in case of unbalanced insets on top or bottom of screen
int insetCorrectionY = (dp.getInsets().bottom - dp.getInsets().top) / 2;
out.setTranslationX(splitInstructionsWidth - splitInstructionsHeight - distanceToEdge
+ insetCorrectionX);
out.setTranslationY(((splitInstructionsHeight + splitInstructionsWidth) / 2f)
out.setTranslationX(splitInstructionsWidth - distanceToEdge + insetCorrectionX);
out.setTranslationY(((-splitInstructionsHeight + splitInstructionsWidth) / 2f)
+ insetCorrectionY);
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) out.getLayoutParams();
// Setting gravity to RIGHT instead of the lint-recommended END because we always want this