Polish app => recents animation (3/N)

This CL takes the current scale down animation and updates its
interpolators and durations to match the UX spec. In addition, we move
the core logic to a helper method as the whole remote animation will
have other animations as well in the future.

Bug: 132112131
Test: Manual
Change-Id: I68b1d623b1b2c980dc34e41bbb5460cc021b5887
This commit is contained in:
Kevin 2019-05-03 13:14:40 -07:00
parent 1b4b960ff1
commit e590014834
2 changed files with 46 additions and 35 deletions

View File

@ -23,7 +23,6 @@ import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MOD
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.util.Log;
import android.view.View;
import com.android.launcher3.BaseDraggingActivity;
import com.android.quickstep.util.RemoteAnimationProvider;
@ -119,7 +118,7 @@ final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> imple
return anim;
}
mRecentsView.playAppScaleDownAnim(anim, closingAppTarget, recentsTarget);
mRecentsView.playRemoteAppToRecentsAnimation(anim, closingAppTarget, recentsTarget);
return anim;
}

View File

@ -20,7 +20,6 @@ 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.launcher3.anim.Interpolators.ACCEL_DEACCEL;
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;
@ -45,6 +44,7 @@ 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;
@ -111,10 +111,15 @@ 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 APP_TO_THUMBNAIL_FADE_DURATION = 50;
private static final long APP_SCALE_DOWN_DURATION = 400;
private static final long REMOTE_TO_RECENTS_APP_SCALE_DOWN_DURATION = 300;
public static final long REMOTE_APP_TO_OVERVIEW_DURATION = APP_SCALE_DOWN_DURATION;
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);
public static final long REMOTE_APP_TO_OVERVIEW_DURATION =
REMOTE_TO_RECENTS_APP_SCALE_DOWN_DURATION;
/**
* A ratio representing the view's relative placement within its padded space. For example, 0
@ -397,7 +402,7 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
*
* @return the thumbnail view if laid out
*/
public @Nullable View getBottomThumbnailView() {
private @Nullable View getBottomThumbnailView() {
ArrayList<TaskItemView> taskViews = getTaskViews();
if (taskViews.isEmpty()) {
return null;
@ -580,18 +585,17 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
}
/**
* Animate a closing app to scale down to the location of the thumbnail view in recents.
* 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 playAppScaleDownAnim(@NonNull AnimatorSet anim,
public void playRemoteAppToRecentsAnimation(@NonNull AnimatorSet anim,
@NonNull RemoteAnimationTargetCompat appTarget,
@NonNull RemoteAnimationTargetCompat recentsTarget) {
View thumbnailView = 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.
@ -599,15 +603,28 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
anim.play(ValueAnimator.ofInt(0, 1).setDuration(REMOTE_APP_TO_OVERVIEW_DURATION));
}
// TODO: Play other animations in app => recents
playRemoteAppScaleDownAnim(anim, appTarget, recentsTarget, thumbnailView);
}
/**
* 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 appTarget closing app target
* @param recentsTarget opening recents target
* @param thumbnailView thumbnail view to animate to
*/
private void playRemoteAppScaleDownAnim(@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);
@ -618,7 +635,9 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
params[0] = new SurfaceParams(recentsTarget.leash, 1f, null /* matrix */,
null /* windowCrop */, getLayer(recentsTarget, boostedMode), 0 /* cornerRadius */);
valueAnimator.addUpdateListener(new MultiValueUpdateListener() {
ValueAnimator remoteAppAnim = ValueAnimator.ofInt(0, 1);
remoteAppAnim.setDuration(REMOTE_TO_RECENTS_APP_SCALE_DOWN_DURATION);
remoteAppAnim.addUpdateListener(new MultiValueUpdateListener() {
private final FloatProp mScaleX;
private final FloatProp mScaleY;
private final FloatProp mTranslationX;
@ -628,30 +647,27 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
{
// 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);
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, APP_SCALE_DOWN_DURATION,
ACCEL_DEACCEL);
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, APP_SCALE_DOWN_DURATION,
ACCEL_DEACCEL);
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, 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);
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) {
Matrix m = new Matrix();
m.setScale(mScaleX.value, mScaleY.value,
m.preScale(mScaleX.value, mScaleY.value,
appBounds.width() / 2.0f, appBounds.height() / 2.0f);
m.postTranslate(mTranslationX.value, mTranslationY.value);
@ -661,11 +677,7 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
surfaceApplier.scheduleApply(params);
}
});
anim.play(valueAnimator);
}
public long getAppToOverviewAnimationDuration() {
return APP_SCALE_DOWN_DURATION;
anim.play(remoteAppAnim);
}
@Override