Merge "Play window close animation to home for most app to launcher scenarios" into sc-v2-dev
This commit is contained in:
commit
e37b51b30f
|
@ -28,17 +28,24 @@ import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
|
|||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.Utilities.mapBoundToRange;
|
||||
import static com.android.launcher3.Utilities.postAsyncCallback;
|
||||
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
|
||||
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
|
||||
import static com.android.launcher3.anim.Interpolators.EXAGGERATED_EASE;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_BACK_SWIPE_HOME_ANIMATION;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_SCRIM_FOR_APP_LAUNCH;
|
||||
import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION;
|
||||
import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
|
||||
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS;
|
||||
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
|
||||
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
|
||||
import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
|
||||
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
|
||||
import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
|
||||
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
|
||||
|
@ -50,20 +57,24 @@ import android.animation.AnimatorListenerAdapter;
|
|||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Pair;
|
||||
import android.util.Size;
|
||||
import android.view.SurfaceControl;
|
||||
|
@ -86,8 +97,11 @@ import com.android.launcher3.icons.FastBitmapDrawable;
|
|||
import com.android.launcher3.shortcuts.DeepShortcutView;
|
||||
import com.android.launcher3.statehandlers.DepthController;
|
||||
import com.android.launcher3.taskbar.LauncherTaskbarUIController;
|
||||
import com.android.launcher3.touch.PagedOrientationHandler;
|
||||
import com.android.launcher3.util.ActivityOptionsWrapper;
|
||||
import com.android.launcher3.util.DynamicResource;
|
||||
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
|
||||
import com.android.launcher3.util.ObjectWrapper;
|
||||
import com.android.launcher3.util.RunnableList;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.views.FloatingIconView;
|
||||
|
@ -96,8 +110,11 @@ import com.android.launcher3.widget.LauncherAppWidgetHostView;
|
|||
import com.android.quickstep.RemoteAnimationTargets;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.quickstep.TaskViewUtils;
|
||||
import com.android.quickstep.util.AppCloseConfig;
|
||||
import com.android.quickstep.util.MultiValueUpdateListener;
|
||||
import com.android.quickstep.util.RectFSpringAnim;
|
||||
import com.android.quickstep.util.RemoteAnimationProvider;
|
||||
import com.android.quickstep.util.StaggeredWorkspaceAnim;
|
||||
import com.android.quickstep.util.SurfaceTransactionApplier;
|
||||
import com.android.quickstep.util.WorkspaceRevealAnim;
|
||||
import com.android.quickstep.views.FloatingWidgetView;
|
||||
|
@ -1179,10 +1196,183 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
|||
}
|
||||
|
||||
/**
|
||||
* Animator that controls the transformations of the windows the targets that are closing.
|
||||
* Returns view on the workspace that corresponds to the closing app in the list of app targets
|
||||
*/
|
||||
private Animator getClosingWindowAnimators(RemoteAnimationTargetCompat[] appTargets,
|
||||
RemoteAnimationTargetCompat[] wallpaperTargets) {
|
||||
private @Nullable View findWorkspaceView(RemoteAnimationTargetCompat[] appTargets) {
|
||||
for (RemoteAnimationTargetCompat appTarget : appTargets) {
|
||||
if (appTarget.mode == MODE_CLOSING) {
|
||||
View workspaceView = findWorkspaceView(appTarget);
|
||||
if (workspaceView != null) {
|
||||
return workspaceView;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns view on the workspace that corresponds to the {@param runningTaskTarget}.
|
||||
*/
|
||||
private @Nullable View findWorkspaceView(RemoteAnimationTargetCompat runningTaskTarget) {
|
||||
if (runningTaskTarget == null || runningTaskTarget.taskInfo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final ComponentName[] taskInfoActivities = new ComponentName[] {
|
||||
runningTaskTarget.taskInfo.baseActivity,
|
||||
runningTaskTarget.taskInfo.origActivity,
|
||||
runningTaskTarget.taskInfo.realActivity,
|
||||
runningTaskTarget.taskInfo.topActivity};
|
||||
|
||||
String packageName = null;
|
||||
for (ComponentName component : taskInfoActivities) {
|
||||
if (component != null && component.getPackageName() != null) {
|
||||
packageName = component.getPackageName();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (packageName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Find the associated item info for the launch cookie (if available), note that predicted
|
||||
// apps actually have an id of -1, so use another default id here
|
||||
final ArrayList<IBinder> launchCookies = runningTaskTarget.taskInfo.launchCookies == null
|
||||
? new ArrayList<>()
|
||||
: runningTaskTarget.taskInfo.launchCookies;
|
||||
|
||||
int launchCookieItemId = NO_MATCHING_ID;
|
||||
for (IBinder cookie : launchCookies) {
|
||||
Integer itemId = ObjectWrapper.unwrap(cookie);
|
||||
if (itemId != null) {
|
||||
launchCookieItemId = itemId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return mLauncher.getWorkspace().getFirstMatchForAppClose(launchCookieItemId,
|
||||
packageName, UserHandle.of(runningTaskTarget.taskInfo.userId));
|
||||
}
|
||||
|
||||
private @NonNull RectF getDefaultWindowTargetRect() {
|
||||
RecentsView recentsView = mLauncher.getOverviewPanel();
|
||||
PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
|
||||
DeviceProfile dp = mLauncher.getDeviceProfile();
|
||||
final int halfIconSize = dp.iconSizePx / 2;
|
||||
float primaryDimension = orientationHandler
|
||||
.getPrimaryValue(dp.availableWidthPx, dp.availableHeightPx);
|
||||
float secondaryDimension = orientationHandler
|
||||
.getSecondaryValue(dp.availableWidthPx, dp.availableHeightPx);
|
||||
final float targetX = primaryDimension / 2f;
|
||||
final float targetY = secondaryDimension - dp.hotseatBarSizePx;
|
||||
return new RectF(targetX - halfIconSize, targetY - halfIconSize,
|
||||
targetX + halfIconSize, targetY + halfIconSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closing animator that animates the window into its final location on the workspace.
|
||||
*/
|
||||
private void getClosingWindowAnimators(AnimatorSet animation,
|
||||
RemoteAnimationTargetCompat[] targets, View workspaceView) {
|
||||
FloatingIconView floatingIconView = null;
|
||||
FloatingWidgetView floatingWidget = null;
|
||||
RectF targetRect = new RectF();
|
||||
|
||||
RemoteAnimationTargetCompat runningTaskTarget = null;
|
||||
boolean isTransluscent = false;
|
||||
for (RemoteAnimationTargetCompat target : targets) {
|
||||
if (target.mode == MODE_CLOSING) {
|
||||
runningTaskTarget = target;
|
||||
isTransluscent = runningTaskTarget.isTranslucent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get floating view and target rect.
|
||||
if (workspaceView instanceof LauncherAppWidgetHostView) {
|
||||
Size windowSize = new Size(mDeviceProfile.availableWidthPx,
|
||||
mDeviceProfile.availableHeightPx);
|
||||
int fallbackBackgroundColor =
|
||||
FloatingWidgetView.getDefaultBackgroundColor(mLauncher, runningTaskTarget);
|
||||
floatingWidget = FloatingWidgetView.getFloatingWidgetView(mLauncher,
|
||||
(LauncherAppWidgetHostView) workspaceView, targetRect, windowSize,
|
||||
mDeviceProfile.isMultiWindowMode ? 0 : getWindowCornerRadius(mLauncher),
|
||||
isTransluscent, fallbackBackgroundColor);
|
||||
} else if (workspaceView != null) {
|
||||
floatingIconView = getFloatingIconView(mLauncher, workspaceView,
|
||||
true /* hideOriginal */, targetRect, false /* isOpening */);
|
||||
} else {
|
||||
targetRect.set(getDefaultWindowTargetRect());
|
||||
}
|
||||
|
||||
final RectF startRect = new RectF(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx);
|
||||
RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mLauncher);
|
||||
|
||||
// Hook up floating views to the closing window animators.
|
||||
if (floatingIconView != null) {
|
||||
anim.addAnimatorListener(floatingIconView);
|
||||
floatingIconView.setOnTargetChangeListener(anim::onTargetPositionChanged);
|
||||
floatingIconView.setFastFinishRunnable(anim::end);
|
||||
FloatingIconView finalFloatingIconView = floatingIconView;
|
||||
|
||||
// We want the window alpha to be 0 once this threshold is met, so that the
|
||||
// FolderIconView can be seen morphing into the icon shape.
|
||||
final float windowAlphaThreshold = 1f - SHAPE_PROGRESS_DURATION;
|
||||
|
||||
RectFSpringAnim.OnUpdateListener runner = new SpringAnimRunner(targets, targetRect) {
|
||||
@Override
|
||||
public void onUpdate(@Nullable AppCloseConfig values, RectF currentRectF,
|
||||
float progress) {
|
||||
finalFloatingIconView.update(1f, 255 /* fgAlpha */, currentRectF, progress,
|
||||
windowAlphaThreshold, getCornerRadius(progress), false);
|
||||
|
||||
super.onUpdate(values, currentRectF, progress);
|
||||
}
|
||||
};
|
||||
anim.addOnUpdateListener(runner);
|
||||
} else if (floatingWidget != null) {
|
||||
anim.addAnimatorListener(floatingWidget);
|
||||
floatingWidget.setOnTargetChangeListener(anim::onTargetPositionChanged);
|
||||
floatingWidget.setFastFinishRunnable(anim::end);
|
||||
|
||||
final float floatingWidgetAlpha = isTransluscent ? 0 : 1;
|
||||
FloatingWidgetView finalFloatingWidget = floatingWidget;
|
||||
RectFSpringAnim.OnUpdateListener runner = new SpringAnimRunner(targets, targetRect) {
|
||||
@Override
|
||||
public void onUpdate(@Nullable AppCloseConfig values, RectF currentRectF,
|
||||
float progress) {
|
||||
final float fallbackBackgroundAlpha =
|
||||
1 - mapBoundToRange(progress, 0.8f, 1, 0, 1, EXAGGERATED_EASE);
|
||||
final float foregroundAlpha =
|
||||
mapBoundToRange(progress, 0.5f, 1, 0, 1, EXAGGERATED_EASE);
|
||||
finalFloatingWidget.update(currentRectF, floatingWidgetAlpha, foregroundAlpha,
|
||||
fallbackBackgroundAlpha, 1 - progress);
|
||||
|
||||
super.onUpdate(values, currentRectF, progress);
|
||||
}
|
||||
};
|
||||
anim.addOnUpdateListener(runner);
|
||||
}
|
||||
|
||||
// Use a fixed velocity to start the animation.
|
||||
float velocityPxPerS = DynamicResource.provider(mLauncher)
|
||||
.getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
|
||||
PointF velocity = new PointF(0, -velocityPxPerS);
|
||||
animation.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
|
||||
true /* animateOverviewScrim */, workspaceView).getAnimators());
|
||||
animation.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
anim.start(mLauncher, velocity);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Closing window animator that moves the window down and offscreen.
|
||||
*/
|
||||
private Animator getFallbackClosingWindowAnimators(RemoteAnimationTargetCompat[] appTargets) {
|
||||
final int rotationChange = getRotationChange(appTargets);
|
||||
SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(mDragLayer);
|
||||
Matrix matrix = new Matrix();
|
||||
|
@ -1321,7 +1511,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
|||
LauncherAnimationRunner.AnimationResult result) {
|
||||
if (mLauncher.isDestroyed()) {
|
||||
AnimatorSet anim = new AnimatorSet();
|
||||
anim.play(getClosingWindowAnimators(appTargets, wallpaperTargets));
|
||||
anim.play(getFallbackClosingWindowAnimators(appTargets));
|
||||
result.setAnimation(anim, mLauncher.getApplicationContext());
|
||||
return;
|
||||
}
|
||||
|
@ -1348,9 +1538,23 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
|||
|
||||
if (anim == null) {
|
||||
anim = new AnimatorSet();
|
||||
anim.play(mFromUnlock
|
||||
? getUnlockWindowAnimator(appTargets, wallpaperTargets)
|
||||
: getClosingWindowAnimators(appTargets, wallpaperTargets));
|
||||
|
||||
boolean playFallBackAnimation = mLauncher.isInState(LauncherState.ALL_APPS)
|
||||
&& (launcherIsATargetWithMode(appTargets, MODE_OPENING)
|
||||
|| mLauncher.isForceInvisible());
|
||||
|
||||
View workspaceView = findWorkspaceView(appTargets);
|
||||
boolean playWorkspaceReveal = true;
|
||||
if (mFromUnlock) {
|
||||
anim.play(getUnlockWindowAnimator(appTargets, wallpaperTargets));
|
||||
} else if (ENABLE_BACK_SWIPE_HOME_ANIMATION.get()
|
||||
&& !playFallBackAnimation) {
|
||||
getClosingWindowAnimators(anim, appTargets, workspaceView);
|
||||
// We play StaggeredWorkspaceAnim as a part of the closing window animation.
|
||||
playWorkspaceReveal = false;
|
||||
} else {
|
||||
anim.play(getFallbackClosingWindowAnimators(appTargets));
|
||||
}
|
||||
|
||||
// Normally, we run the launcher content animation when we are transitioning
|
||||
// home, but if home is already visible, then we don't want to animate the
|
||||
|
@ -1378,7 +1582,9 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
|||
}
|
||||
});
|
||||
} else {
|
||||
anim.play(new WorkspaceRevealAnim(mLauncher, false).getAnimators());
|
||||
if (playWorkspaceReveal) {
|
||||
anim.play(new WorkspaceRevealAnim(mLauncher, false).getAnimators());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1527,4 +1733,73 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
|||
mTransitionManager.mTaskStartParams.put(taskId, Pair.create(supportedType, color));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RectFSpringAnim update listener to be used for app to home animation.
|
||||
*/
|
||||
private class SpringAnimRunner implements RectFSpringAnim.OnUpdateListener {
|
||||
private final RemoteAnimationTargetCompat[] mAppTargets;
|
||||
private final Matrix mMatrix = new Matrix();
|
||||
private final Point mTmpPos = new Point();
|
||||
private final Rect mCurrentRect = new Rect();
|
||||
private final float mStartRadius;
|
||||
private final float mEndRadius;
|
||||
private final SurfaceTransactionApplier mSurfaceApplier;
|
||||
|
||||
SpringAnimRunner(RemoteAnimationTargetCompat[] appTargets, RectF targetRect) {
|
||||
mAppTargets = appTargets;
|
||||
mStartRadius = QuickStepContract.getWindowCornerRadius(mLauncher);
|
||||
mEndRadius = Math.max(1, targetRect.width()) / 2f;
|
||||
mSurfaceApplier = new SurfaceTransactionApplier(mDragLayer);
|
||||
}
|
||||
|
||||
public float getCornerRadius(float progress) {
|
||||
return Utilities.mapRange(progress, mStartRadius, mEndRadius);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(@Nullable AppCloseConfig values, RectF currentRectF, float progress) {
|
||||
SurfaceParams[] params = new SurfaceParams[mAppTargets.length];
|
||||
for (int i = mAppTargets.length - 1; i >= 0; i--) {
|
||||
RemoteAnimationTargetCompat target = mAppTargets[i];
|
||||
SurfaceParams.Builder builder = new SurfaceParams.Builder(target.leash);
|
||||
|
||||
if (target.localBounds != null) {
|
||||
mTmpPos.set(target.localBounds.left, target.localBounds.top);
|
||||
} else {
|
||||
mTmpPos.set(target.position.x, target.position.y);
|
||||
}
|
||||
|
||||
if (target.mode == MODE_CLOSING) {
|
||||
float alpha = getWindowAlpha(progress);
|
||||
currentRectF.round(mCurrentRect);
|
||||
|
||||
builder.withMatrix(mMatrix)
|
||||
.withWindowCrop(mCurrentRect)
|
||||
.withAlpha(alpha)
|
||||
.withCornerRadius(getCornerRadius(progress));
|
||||
} else if (target.mode == MODE_OPENING) {
|
||||
mMatrix.setTranslate(mTmpPos.x, mTmpPos.y);
|
||||
builder.withMatrix(mMatrix)
|
||||
.withAlpha(1f);
|
||||
}
|
||||
params[i] = builder.build();
|
||||
}
|
||||
mSurfaceApplier.scheduleApply(params);
|
||||
}
|
||||
|
||||
protected float getWindowAlpha(float progress) {
|
||||
// Alpha interpolates between [1, 0] between progress values [start, end]
|
||||
final float start = 0f;
|
||||
final float end = 0.85f;
|
||||
|
||||
if (progress <= start) {
|
||||
return 1f;
|
||||
}
|
||||
if (progress >= end) {
|
||||
return 0f;
|
||||
}
|
||||
return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -176,7 +176,7 @@
|
|||
|
||||
<item name="staggered_damping_ratio" type="dimen" format="float">0.7</item>
|
||||
<item name="staggered_stiffness" type="dimen" format="float">150</item>
|
||||
<dimen name="unlock_staggered_velocity_dp_per_s">4dp</dimen>
|
||||
<dimen name="unlock_staggered_velocity_dp_per_s">2dp</dimen>
|
||||
|
||||
<item name="hint_scale_damping_ratio" type="dimen" format="float">0.7</item>
|
||||
<item name="hint_scale_stiffness" type="dimen" format="float">200</item>
|
||||
|
|
|
@ -271,6 +271,10 @@ public final class FeatureFlags {
|
|||
"QUICK_WALLPAPER_PICKER", false,
|
||||
"Shows quick wallpaper picker in long-press menu");
|
||||
|
||||
public static final BooleanFlag ENABLE_BACK_SWIPE_HOME_ANIMATION = getDebugFlag(
|
||||
"ENABLE_BACK_SWIPE_HOME_ANIMATION", true,
|
||||
"Enables home animation to icon when user swipes back.");
|
||||
|
||||
public static void initialize(Context context) {
|
||||
synchronized (sDebugFlags) {
|
||||
for (DebugFlag flag : sDebugFlags) {
|
||||
|
|
Loading…
Reference in New Issue