Merge changes from topic "polish-app-recents-anim" into ub-launcher3-qt-dev
* changes: Polish app => recents animation (5/5) Polish app => recents animation (4/5) Polish app => recents animation (3/N) Polish app => recents animation (2/N) Polish app => recents animation (1/N)
This commit is contained in:
committed by
Android (Google) Code Review
commit
f079b277cf
@@ -15,30 +15,20 @@
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.quickstep.util.RemoteAnimationProvider.getLayer;
|
||||
import static com.android.quickstep.views.IconRecentsView.REMOTE_APP_TO_OVERVIEW_DURATION;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
|
||||
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.quickstep.util.MultiValueUpdateListener;
|
||||
import com.android.quickstep.util.RemoteAnimationProvider;
|
||||
import com.android.quickstep.util.RemoteAnimationTargetSet;
|
||||
import com.android.quickstep.views.IconRecentsView;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
|
||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
|
||||
|
||||
/**
|
||||
* Provider for the atomic remote window animation from the app to the overview.
|
||||
@@ -47,9 +37,6 @@ import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.
|
||||
*/
|
||||
final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> implements
|
||||
RemoteAnimationProvider {
|
||||
|
||||
private static final long APP_TO_THUMBNAIL_FADE_DURATION = 50;
|
||||
private static final long APP_SCALE_DOWN_DURATION = 400;
|
||||
private static final String TAG = "AppToOverviewAnimationProvider";
|
||||
|
||||
private final ActivityControlHelper<T> mHelper;
|
||||
@@ -131,106 +118,17 @@ final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> imple
|
||||
return anim;
|
||||
}
|
||||
|
||||
View thumbnailView = mRecentsView.getBottomThumbnailView();
|
||||
if (thumbnailView == null) {
|
||||
// This can be null if there were previously 0 tasks and the recycler view has not had
|
||||
// enough time to take in the data change, bind a new view, and lay out the new view.
|
||||
// TODO: Have a fallback to animate to
|
||||
if (Log.isLoggable(TAG, Log.WARN)) {
|
||||
Log.w(TAG, "No thumbnail view for running task. Using stub animation.");
|
||||
}
|
||||
anim.play(ValueAnimator.ofInt(0, 1).setDuration(getRecentsLaunchDuration()));
|
||||
return anim;
|
||||
}
|
||||
|
||||
playAppScaleDownAnim(anim, closingAppTarget, recentsTarget, thumbnailView);
|
||||
mRecentsView.playRemoteAppToRecentsAnimation(anim, closingAppTarget, recentsTarget);
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Animate a closing app to scale down to the location of the thumbnail view in recents.
|
||||
*
|
||||
* @param anim animator set
|
||||
* @param appTarget the app surface thats closing
|
||||
* @param recentsTarget the surface containing recents
|
||||
* @param thumbnailView the thumbnail view to animate to
|
||||
*/
|
||||
private void playAppScaleDownAnim(@NonNull AnimatorSet anim,
|
||||
@NonNull RemoteAnimationTargetCompat appTarget,
|
||||
@NonNull RemoteAnimationTargetCompat recentsTarget, @NonNull View thumbnailView) {
|
||||
|
||||
// Identify where the entering remote app should animate to.
|
||||
Rect endRect = new Rect();
|
||||
thumbnailView.getGlobalVisibleRect(endRect);
|
||||
|
||||
Rect appBounds = appTarget.sourceContainerBounds;
|
||||
|
||||
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 1);
|
||||
valueAnimator.setDuration(APP_SCALE_DOWN_DURATION);
|
||||
|
||||
SyncRtSurfaceTransactionApplierCompat surfaceApplier =
|
||||
new SyncRtSurfaceTransactionApplierCompat(thumbnailView);
|
||||
|
||||
// Keep recents visible throughout the animation.
|
||||
SurfaceParams[] params = new SurfaceParams[2];
|
||||
// Closing app should stay on top.
|
||||
int boostedMode = MODE_CLOSING;
|
||||
params[0] = new SurfaceParams(recentsTarget.leash, 1f, null /* matrix */,
|
||||
null /* windowCrop */, getLayer(recentsTarget, boostedMode), 0 /* cornerRadius */);
|
||||
|
||||
valueAnimator.addUpdateListener(new MultiValueUpdateListener() {
|
||||
private final FloatProp mScaleX;
|
||||
private final FloatProp mScaleY;
|
||||
private final FloatProp mTranslationX;
|
||||
private final FloatProp mTranslationY;
|
||||
private final FloatProp mAlpha;
|
||||
|
||||
{
|
||||
// Scale down and move to view location.
|
||||
float endScaleX = ((float) endRect.width()) / appBounds.width();
|
||||
mScaleX = new FloatProp(1f, endScaleX, 0, APP_SCALE_DOWN_DURATION,
|
||||
ACCEL_DEACCEL);
|
||||
float endScaleY = ((float) endRect.height()) / appBounds.height();
|
||||
mScaleY = new FloatProp(1f, endScaleY, 0, APP_SCALE_DOWN_DURATION,
|
||||
ACCEL_DEACCEL);
|
||||
float endTranslationX = endRect.left -
|
||||
(appBounds.width() - thumbnailView.getWidth()) / 2.0f;
|
||||
mTranslationX = new FloatProp(0, endTranslationX, 0, APP_SCALE_DOWN_DURATION,
|
||||
ACCEL_DEACCEL);
|
||||
float endTranslationY = endRect.top -
|
||||
(appBounds.height() - thumbnailView.getHeight()) / 2.0f;
|
||||
mTranslationY = new FloatProp(0, endTranslationY, 0, APP_SCALE_DOWN_DURATION,
|
||||
ACCEL_DEACCEL);
|
||||
|
||||
// Fade out quietly near the end to be replaced by the real view.
|
||||
mAlpha = new FloatProp(1.0f, 0,
|
||||
APP_SCALE_DOWN_DURATION - APP_TO_THUMBNAIL_FADE_DURATION,
|
||||
APP_TO_THUMBNAIL_FADE_DURATION, ACCEL_2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(float percent) {
|
||||
Matrix m = new Matrix();
|
||||
m.setScale(mScaleX.value, mScaleY.value,
|
||||
appBounds.width() / 2.0f, appBounds.height() / 2.0f);
|
||||
m.postTranslate(mTranslationX.value, mTranslationY.value);
|
||||
|
||||
params[1] = new SurfaceParams(appTarget.leash, mAlpha.value, m,
|
||||
null /* windowCrop */, getLayer(appTarget, boostedMode),
|
||||
0 /* cornerRadius */);
|
||||
surfaceApplier.scheduleApply(params);
|
||||
}
|
||||
});
|
||||
anim.play(valueAnimator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get duration of animation from app to overview.
|
||||
*
|
||||
* @return duration of animation
|
||||
*/
|
||||
long getRecentsLaunchDuration() {
|
||||
return APP_SCALE_DOWN_DURATION;
|
||||
return REMOTE_APP_TO_OVERVIEW_DURATION;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ public final class FallbackActivityControllerHelper extends
|
||||
@Override
|
||||
public AnimationFactory prepareRecentsUI(RecentsActivity activity, boolean activityVisible,
|
||||
boolean animateActivity, Consumer<AnimatorPlaybackController> callback) {
|
||||
// TODO: Logic for setting remote animation
|
||||
if (activityVisible) {
|
||||
return (transitionLength) -> { };
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ public final class LauncherActivityControllerHelper extends GoActivityControlHel
|
||||
boolean activityVisible, boolean animateActivity,
|
||||
Consumer<AnimatorPlaybackController> callback) {
|
||||
LauncherState fromState = activity.getStateManager().getState();
|
||||
activity.<IconRecentsView>getOverviewPanel().setUsingRemoteAnimation(true);
|
||||
//TODO: Implement this based off where the recents view needs to be for app => recents anim.
|
||||
return new AnimationFactory() {
|
||||
@Override
|
||||
@@ -87,6 +88,7 @@ public final class LauncherActivityControllerHelper extends GoActivityControlHel
|
||||
if (launcher == null) {
|
||||
return false;
|
||||
}
|
||||
launcher.<IconRecentsView>getOverviewPanel().setUsingRemoteAnimation(false);
|
||||
launcher.getUserEventDispatcher().logActionCommand(
|
||||
LauncherLogProto.Action.Command.RECENTS_BUTTON,
|
||||
getContainerType(),
|
||||
|
||||
@@ -19,10 +19,14 @@ import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
|
||||
|
||||
import static androidx.recyclerview.widget.LinearLayoutManager.VERTICAL;
|
||||
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
|
||||
import static com.android.quickstep.TaskAdapter.CHANGE_EVENT_TYPE_EMPTY_TO_CONTENT;
|
||||
import static com.android.quickstep.TaskAdapter.ITEM_TYPE_CLEAR_ALL;
|
||||
import static com.android.quickstep.TaskAdapter.ITEM_TYPE_TASK;
|
||||
import static com.android.quickstep.TaskAdapter.MAX_TASKS_TO_DISPLAY;
|
||||
import static com.android.quickstep.TaskAdapter.TASKS_START_POSITION;
|
||||
import static com.android.quickstep.util.RemoteAnimationProvider.getLayer;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -32,6 +36,7 @@ import android.animation.PropertyValuesHolder;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.ArraySet;
|
||||
@@ -40,10 +45,12 @@ import android.util.FloatProperty;
|
||||
import android.view.View;
|
||||
import android.view.ViewDebug;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.animation.PathInterpolator;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator;
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
@@ -64,7 +71,11 @@ import com.android.quickstep.TaskAdapter;
|
||||
import com.android.quickstep.TaskHolder;
|
||||
import com.android.quickstep.TaskListLoader;
|
||||
import com.android.quickstep.TaskSwipeCallback;
|
||||
import com.android.quickstep.util.MultiValueUpdateListener;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
|
||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -102,6 +113,22 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
|
||||
private static final float ITEM_ANIMATE_OUT_TRANSLATION_X_RATIO = .25f;
|
||||
private static final long CLEAR_ALL_FADE_DELAY = 120;
|
||||
|
||||
private static final long REMOTE_TO_RECENTS_APP_SCALE_DOWN_DURATION = 300;
|
||||
private static final long REMOTE_TO_RECENTS_VERTICAL_EASE_IN_DURATION = 400;
|
||||
private static final long REMOTE_TO_RECENTS_ITEM_FADE_START_DELAY = 200;
|
||||
private static final long REMOTE_TO_RECENTS_ITEM_FADE_DURATION = 217;
|
||||
private static final long REMOTE_TO_RECENTS_ITEM_FADE_BETWEEN_DELAY = 33;
|
||||
|
||||
private static final PathInterpolator FAST_OUT_SLOW_IN_1 =
|
||||
new PathInterpolator(.4f, 0f, 0f, 1f);
|
||||
private static final PathInterpolator FAST_OUT_SLOW_IN_2 =
|
||||
new PathInterpolator(.5f, 0f, 0f, 1f);
|
||||
private static final LinearOutSlowInInterpolator OUT_SLOW_IN =
|
||||
new LinearOutSlowInInterpolator();
|
||||
|
||||
public static final long REMOTE_APP_TO_OVERVIEW_DURATION =
|
||||
REMOTE_TO_RECENTS_VERTICAL_EASE_IN_DURATION;
|
||||
|
||||
/**
|
||||
* A ratio representing the view's relative placement within its padded space. For example, 0
|
||||
* is top aligned and 0.5 is centered vertically.
|
||||
@@ -125,6 +152,7 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
|
||||
private View mEmptyView;
|
||||
private View mContentView;
|
||||
private boolean mTransitionedFromApp;
|
||||
private boolean mUsingRemoteAnimation;
|
||||
private AnimatorSet mLayoutAnimation;
|
||||
private final ArraySet<View> mLayingOutViews = new ArraySet<>();
|
||||
private Rect mInsets;
|
||||
@@ -276,7 +304,9 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
|
||||
// not be scrollable.
|
||||
mTaskLayoutManager.scrollToPositionWithOffset(TASKS_START_POSITION, 0 /* offset */);
|
||||
}
|
||||
scheduleFadeInLayoutAnimation();
|
||||
if (!mUsingRemoteAnimation) {
|
||||
scheduleFadeInLayoutAnimation();
|
||||
}
|
||||
// Load any task changes
|
||||
if (!mTaskLoader.needsToLoad()) {
|
||||
return;
|
||||
@@ -314,6 +344,17 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
|
||||
mTransitionedFromApp = transitionedFromApp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether we're using a custom remote animation. If so, we will not do the default layout
|
||||
* animation when entering recents and instead wait for the remote app surface to be ready to
|
||||
* use.
|
||||
*
|
||||
* @param usingRemoteAnimation true if doing a remote animation, false o/w
|
||||
*/
|
||||
public void setUsingRemoteAnimation(boolean usingRemoteAnimation) {
|
||||
mUsingRemoteAnimation = usingRemoteAnimation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles input from the overview button. Launch the most recent task unless we just came from
|
||||
* the app. In that case, we launch the next most recent.
|
||||
@@ -365,17 +406,19 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bottom most thumbnail view to animate to.
|
||||
* Get the bottom most task view to animate to.
|
||||
*
|
||||
* @return the thumbnail view if laid out
|
||||
* @return the task view
|
||||
*/
|
||||
public @Nullable View getBottomThumbnailView() {
|
||||
ArrayList<TaskItemView> taskViews = getTaskViews();
|
||||
if (taskViews.isEmpty()) {
|
||||
return null;
|
||||
private @Nullable TaskItemView getBottomTaskView() {
|
||||
int childCount = mTaskRecyclerView.getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
View view = mTaskRecyclerView.getChildAt(i);
|
||||
if (mTaskRecyclerView.getChildViewHolder(view).getItemViewType() == ITEM_TYPE_TASK) {
|
||||
return (TaskItemView) view;
|
||||
}
|
||||
}
|
||||
TaskItemView view = taskViews.get(0);
|
||||
return view.getThumbnailView();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -581,6 +624,205 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
|
||||
mLayoutAnimation.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Play remote animation from app to recents. This should scale the currently closing app down
|
||||
* to the recents thumbnail.
|
||||
*
|
||||
* @param anim animator set
|
||||
* @param appTarget the app surface thats closing
|
||||
* @param recentsTarget the surface containing recents
|
||||
*/
|
||||
public void playRemoteAppToRecentsAnimation(@NonNull AnimatorSet anim,
|
||||
@NonNull RemoteAnimationTargetCompat appTarget,
|
||||
@NonNull RemoteAnimationTargetCompat recentsTarget) {
|
||||
TaskItemView bottomView = getBottomTaskView();
|
||||
if (bottomView == null) {
|
||||
// This can be null if there were previously 0 tasks and the recycler view has not had
|
||||
// enough time to take in the data change, bind a new view, and lay out the new view.
|
||||
// TODO: Have a fallback to animate to
|
||||
anim.play(ValueAnimator.ofInt(0, 1).setDuration(REMOTE_APP_TO_OVERVIEW_DURATION));
|
||||
}
|
||||
final Matrix appMatrix = new Matrix();
|
||||
playRemoteTransYAnim(anim, appMatrix);
|
||||
playRemoteAppScaleDownAnim(anim, appMatrix, appTarget, recentsTarget,
|
||||
bottomView.getThumbnailView());
|
||||
playRemoteTaskListFadeIn(anim, bottomView);
|
||||
}
|
||||
|
||||
/**
|
||||
* Play translation Y animation for the remote app to recents animation. Animates over all task
|
||||
* views as well as the closing app, easing them into their final vertical positions.
|
||||
*
|
||||
* @param anim animator set to play on
|
||||
* @param appMatrix transformation matrix for the closing app surface
|
||||
*/
|
||||
private void playRemoteTransYAnim(@NonNull AnimatorSet anim, @NonNull Matrix appMatrix) {
|
||||
final ArrayList<TaskItemView> views = getTaskViews();
|
||||
|
||||
// Start Y translation from about halfway through the tasks list to the bottom thumbnail.
|
||||
float taskHeight = getResources().getDimension(R.dimen.task_item_height);
|
||||
float totalTransY = -(MAX_TASKS_TO_DISPLAY / 2.0f - 1) * taskHeight;
|
||||
for (int i = 0, size = views.size(); i < size; i++) {
|
||||
views.get(i).setTranslationY(totalTransY);
|
||||
}
|
||||
|
||||
ValueAnimator transYAnim = ValueAnimator.ofFloat(totalTransY, 0);
|
||||
transYAnim.setDuration(REMOTE_TO_RECENTS_VERTICAL_EASE_IN_DURATION);
|
||||
transYAnim.setInterpolator(FAST_OUT_SLOW_IN_2);
|
||||
transYAnim.addUpdateListener(valueAnimator -> {
|
||||
float transY = (float) valueAnimator.getAnimatedValue();
|
||||
for (int i = 0, size = views.size(); i < size; i++) {
|
||||
views.get(i).setTranslationY(transY);
|
||||
}
|
||||
appMatrix.postTranslate(0, transY - totalTransY);
|
||||
});
|
||||
transYAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
for (int i = 0, size = views.size(); i < size; i++) {
|
||||
views.get(i).setTranslationY(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
anim.play(transYAnim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Play the scale down animation for the remote app to recents animation where the app surface
|
||||
* scales down to where the thumbnail is.
|
||||
*
|
||||
* @param anim animator set to play on
|
||||
* @param appMatrix transformation matrix for the app surface
|
||||
* @param appTarget closing app target
|
||||
* @param recentsTarget opening recents target
|
||||
* @param thumbnailView thumbnail view to animate to
|
||||
*/
|
||||
private void playRemoteAppScaleDownAnim(@NonNull AnimatorSet anim, @NonNull Matrix appMatrix,
|
||||
@NonNull RemoteAnimationTargetCompat appTarget,
|
||||
@NonNull RemoteAnimationTargetCompat recentsTarget,
|
||||
@NonNull View thumbnailView) {
|
||||
// Identify where the entering remote app should animate to.
|
||||
Rect endRect = new Rect();
|
||||
thumbnailView.getGlobalVisibleRect(endRect);
|
||||
Rect appBounds = appTarget.sourceContainerBounds;
|
||||
|
||||
SyncRtSurfaceTransactionApplierCompat surfaceApplier =
|
||||
new SyncRtSurfaceTransactionApplierCompat(this);
|
||||
|
||||
// Keep recents visible throughout the animation.
|
||||
SurfaceParams[] params = new SurfaceParams[2];
|
||||
// Closing app should stay on top.
|
||||
int boostedMode = MODE_CLOSING;
|
||||
params[0] = new SurfaceParams(recentsTarget.leash, 1f, null /* matrix */,
|
||||
null /* windowCrop */, getLayer(recentsTarget, boostedMode), 0 /* cornerRadius */);
|
||||
|
||||
ValueAnimator remoteAppAnim = ValueAnimator.ofInt(0, 1);
|
||||
remoteAppAnim.setDuration(REMOTE_TO_RECENTS_VERTICAL_EASE_IN_DURATION);
|
||||
remoteAppAnim.addUpdateListener(new MultiValueUpdateListener() {
|
||||
private final FloatProp mScaleX;
|
||||
private final FloatProp mScaleY;
|
||||
private final FloatProp mTranslationX;
|
||||
private final FloatProp mTranslationY;
|
||||
private final FloatProp mAlpha;
|
||||
|
||||
{
|
||||
// Scale down and move to view location.
|
||||
float endScaleX = ((float) endRect.width()) / appBounds.width();
|
||||
mScaleX = new FloatProp(1f, endScaleX, 0, REMOTE_TO_RECENTS_APP_SCALE_DOWN_DURATION,
|
||||
FAST_OUT_SLOW_IN_1);
|
||||
float endScaleY = ((float) endRect.height()) / appBounds.height();
|
||||
mScaleY = new FloatProp(1f, endScaleY, 0, REMOTE_TO_RECENTS_APP_SCALE_DOWN_DURATION,
|
||||
FAST_OUT_SLOW_IN_1);
|
||||
float endTranslationX = endRect.left -
|
||||
(appBounds.width() - thumbnailView.getWidth()) / 2.0f;
|
||||
mTranslationX = new FloatProp(0, endTranslationX, 0,
|
||||
REMOTE_TO_RECENTS_APP_SCALE_DOWN_DURATION, FAST_OUT_SLOW_IN_1);
|
||||
float endTranslationY = endRect.top -
|
||||
(appBounds.height() - thumbnailView.getHeight()) / 2.0f;
|
||||
mTranslationY = new FloatProp(0, endTranslationY, 0,
|
||||
REMOTE_TO_RECENTS_APP_SCALE_DOWN_DURATION, FAST_OUT_SLOW_IN_2);
|
||||
mAlpha = new FloatProp(1.0f, 0, 0, REMOTE_TO_RECENTS_APP_SCALE_DOWN_DURATION,
|
||||
ACCEL_2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(float percent) {
|
||||
appMatrix.preScale(mScaleX.value, mScaleY.value,
|
||||
appBounds.width() / 2.0f, appBounds.height() / 2.0f);
|
||||
appMatrix.postTranslate(mTranslationX.value, mTranslationY.value);
|
||||
|
||||
params[1] = new SurfaceParams(appTarget.leash, mAlpha.value, appMatrix,
|
||||
null /* windowCrop */, getLayer(appTarget, boostedMode),
|
||||
0 /* cornerRadius */);
|
||||
surfaceApplier.scheduleApply(params);
|
||||
appMatrix.reset();
|
||||
}
|
||||
});
|
||||
anim.play(remoteAppAnim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Play task list fade in animation as part of remote app to recents animation. This animation
|
||||
* ensures that the task views in the recents list fade in from bottom to top.
|
||||
*
|
||||
* @param anim animator set to play on
|
||||
* @param appTaskView the task view associated with the remote app closing
|
||||
*/
|
||||
private void playRemoteTaskListFadeIn(@NonNull AnimatorSet anim,
|
||||
@NonNull TaskItemView appTaskView) {
|
||||
long delay = REMOTE_TO_RECENTS_ITEM_FADE_START_DELAY;
|
||||
int childCount = mTaskRecyclerView.getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
ValueAnimator fadeAnim = ValueAnimator.ofFloat(0, 1.0f);
|
||||
fadeAnim.setDuration(REMOTE_TO_RECENTS_ITEM_FADE_DURATION).setInterpolator(OUT_SLOW_IN);
|
||||
fadeAnim.setStartDelay(delay);
|
||||
View view = mTaskRecyclerView.getChildAt(i);
|
||||
if (Objects.equals(view, appTaskView)) {
|
||||
// Only animate icon and text for the view with snapshot animating in
|
||||
final View icon = appTaskView.getIconView();
|
||||
final View label = appTaskView.getLabelView();
|
||||
|
||||
icon.setAlpha(0.0f);
|
||||
label.setAlpha(0.0f);
|
||||
|
||||
fadeAnim.addUpdateListener(alphaVal -> {
|
||||
float val = alphaVal.getAnimatedFraction();
|
||||
|
||||
icon.setAlpha(val);
|
||||
label.setAlpha(val);
|
||||
});
|
||||
fadeAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
icon.setAlpha(1.0f);
|
||||
label.setAlpha(1.0f);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Otherwise, fade in the entire view.
|
||||
view.setAlpha(0.0f);
|
||||
fadeAnim.addUpdateListener(alphaVal -> {
|
||||
float val = alphaVal.getAnimatedFraction();
|
||||
view.setAlpha(val);
|
||||
});
|
||||
fadeAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
view.setAlpha(1.0f);
|
||||
}
|
||||
});
|
||||
}
|
||||
anim.play(fadeAnim);
|
||||
|
||||
int itemType = mTaskRecyclerView.getChildViewHolder(view).getItemViewType();
|
||||
if (itemType == ITEM_TYPE_CLEAR_ALL) {
|
||||
// Don't add delay. Clear all should animate at same time as next view.
|
||||
continue;
|
||||
}
|
||||
delay += REMOTE_TO_RECENTS_ITEM_FADE_BETWEEN_DELAY;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInsets(Rect insets) {
|
||||
mInsets = insets;
|
||||
|
||||
@@ -137,6 +137,14 @@ public final class TaskItemView extends LinearLayout {
|
||||
return mThumbnailView;
|
||||
}
|
||||
|
||||
public View getIconView() {
|
||||
return mIconView;
|
||||
}
|
||||
|
||||
public View getLabelView() {
|
||||
return mLabelView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a new animation from the current task content to the specified new content. The caller
|
||||
* is responsible for the actual animation control via the property
|
||||
|
||||
Reference in New Issue
Block a user