diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index 275dfda607..1b8fcb3c67 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -75,7 +75,6 @@ import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.util.ActivityOptionsWrapper; -import com.android.launcher3.util.DynamicResource; import com.android.launcher3.util.MultiValueAlpha; import com.android.launcher3.util.MultiValueAlpha.AlphaProperty; import com.android.launcher3.util.RunnableList; @@ -86,8 +85,8 @@ import com.android.quickstep.SystemUiProxy; import com.android.quickstep.TaskViewUtils; import com.android.quickstep.util.MultiValueUpdateListener; 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; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.ActivityCompat; @@ -1213,10 +1212,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener } }); } else { - float velocityPxPerS = DynamicResource.provider(mLauncher) - .getDimension(R.dimen.unlock_staggered_velocity_dp_per_s); - anim.play(new StaggeredWorkspaceAnim(mLauncher, velocityPxPerS, false) - .getAnimators()); + anim.play(new WorkspaceRevealAnim(mLauncher, false).getAnimators()); } } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java index 5837a707ca..40c3e02238 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java @@ -73,7 +73,7 @@ import com.android.quickstep.SystemUiProxy; import com.android.quickstep.util.AnimatorControllerWithResistance; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.util.MotionPauseDetector; -import com.android.quickstep.util.StaggeredWorkspaceAnim; +import com.android.quickstep.util.WorkspaceRevealAnim; import com.android.quickstep.views.LauncherRecentsView; /** @@ -384,8 +384,7 @@ public class NoButtonQuickSwitchTouchController implements TouchController, updateNonOverviewAnim(targetState, config); nonOverviewAnim = mNonOverviewAnim.getAnimationPlayer(); - new StaggeredWorkspaceAnim(mLauncher, velocity.y, false /* animateOverviewScrim */) - .start(); + new WorkspaceRevealAnim(mLauncher, false /* animateOverviewScrim */).start(); } else { boolean canceled = targetState == NORMAL; if (canceled) { diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 1317b4cb24..e0f430d6cf 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -102,10 +102,10 @@ import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.util.ProtoTracer; import com.android.quickstep.util.RecentsOrientedState; import com.android.quickstep.util.RectFSpringAnim; -import com.android.quickstep.util.StaggeredWorkspaceAnim; import com.android.quickstep.util.SurfaceTransactionApplier; import com.android.quickstep.util.SwipePipToHomeAnimator; import com.android.quickstep.util.TransformParams; +import com.android.quickstep.util.WorkspaceRevealAnim; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.ThumbnailData; @@ -201,7 +201,7 @@ public abstract class AbsSwipeUpHandler, STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED; public static final long MAX_SWIPE_DURATION = 350; - public static final long HOME_DURATION = StaggeredWorkspaceAnim.DURATION_MS; + public static final long HOME_DURATION = WorkspaceRevealAnim.DURATION_MS; public static final float MIN_PROGRESS_FOR_OVERVIEW = 0.7f; private static final float SWIPE_DURATION_MULTIPLIER = @@ -1126,6 +1126,7 @@ public abstract class AbsSwipeUpHandler, windowAnim.start(mContext, velocityPxPerMs); mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim); } + homeAnimFactory.setSwipeVelocity(velocityPxPerMs.y); homeAnimFactory.playAtomicAnimation(velocityPxPerMs.y); mLauncherTransitionController = null; diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java index f1250637a8..811af7e658 100644 --- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java +++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java @@ -18,13 +18,14 @@ package com.android.quickstep; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y; import static com.android.launcher3.LauncherState.NORMAL; +import static com.android.launcher3.Utilities.boundToRange; import static com.android.launcher3.Utilities.dpToPx; -import static com.android.launcher3.Utilities.mapToRange; -import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.config.FeatureFlags.PROTOTYPE_APP_CLOSE; import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION; import static com.android.launcher3.views.FloatingIconView.getFloatingIconView; +import static java.lang.Math.round; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; @@ -52,10 +53,12 @@ import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.util.DynamicResource; import com.android.launcher3.util.ObjectWrapper; import com.android.launcher3.views.FloatingIconView; +import com.android.launcher3.views.FloatingView; import com.android.launcher3.widget.LauncherAppWidgetHostView; import com.android.quickstep.util.AppCloseConfig; import com.android.quickstep.util.RectFSpringAnim; import com.android.quickstep.util.StaggeredWorkspaceAnim; +import com.android.quickstep.util.WorkspaceRevealAnim; import com.android.quickstep.views.FloatingWidgetView; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; @@ -112,10 +115,6 @@ public class LauncherSwipeHandlerV2 extends private HomeAnimationFactory createIconHomeAnimationFactory(View workspaceView) { final ResourceProvider rp = DynamicResource.provider(mActivity); final float transY = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp)); - float dpPerSecond = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp_per_s)); - final float launcherAlphaMax = - rp.getFloat(R.dimen.swipe_up_launcher_alpha_max_progress); - RectF iconLocation = new RectF(); FloatingIconView floatingIconView = getFloatingIconView(mActivity, workspaceView, true /* hideOriginal */, iconLocation, false /* isOpening */); @@ -123,73 +122,25 @@ public class LauncherSwipeHandlerV2 extends // 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. float windowAlphaThreshold = 1f - SHAPE_PROGRESS_DURATION; - return new LauncherHomeAnimationFactory() { + + return new FloatingViewHomeAnimationFactory(floatingIconView) { // There is a delay in loading the icon, so we need to keep the window // opaque until it is ready. private boolean mIsFloatingIconReady = false; - private @Nullable ValueAnimator mBounceBackAnimator; - @Override public RectF getWindowTargetRect() { - if (PROTOTYPE_APP_CLOSE.get()) { - // We want the target rect to be at this offset position, so that all - // launcher content can spring back upwards. - floatingIconView.setPositionOffsetY(transY); - } + super.getWindowTargetRect(); return iconLocation; } @Override public void setAnimation(RectFSpringAnim anim) { + super.setAnimation(anim); anim.addAnimatorListener(floatingIconView); floatingIconView.setOnTargetChangeListener(anim::onTargetPositionChanged); floatingIconView.setFastFinishRunnable(anim::end); - if (PROTOTYPE_APP_CLOSE.get()) { - mBounceBackAnimator = bounceBackToRestingPosition(); - // Use a spring to put drag layer translation back to 0. - anim.addAnimatorListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - floatingIconView.setPositionOffsetY(0); - mBounceBackAnimator.start(); - } - }); - - Workspace workspace = mActivity.getWorkspace(); - workspace.setPivotToScaleWithSelf(mActivity.getHotseat()); - } - } - - private ValueAnimator bounceBackToRestingPosition() { - DragLayer dl = mActivity.getDragLayer(); - Workspace workspace = mActivity.getWorkspace(); - Hotseat hotseat = mActivity.getHotseat(); - - final float startValue = transY; - final float endValue = 0; - // Ensures the velocity is always aligned with the direction. - float pixelPerSecond = Math.abs(dpPerSecond) * Math.signum(endValue - transY); - - ValueAnimator springTransY = new SpringAnimationBuilder(dl.getContext()) - .setStiffness(rp.getFloat(R.dimen.swipe_up_trans_y_stiffness)) - .setDampingRatio(rp.getFloat(R.dimen.swipe_up_trans_y_damping)) - .setMinimumVisibleChange(1f) - .setStartValue(startValue) - .setEndValue(endValue) - .setStartVelocity(pixelPerSecond) - .build(dl, VIEW_TRANSLATE_Y); - springTransY.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - dl.setTranslationY(0f); - dl.setAlpha(1f); - SCALE_PROPERTY.set(workspace, 1f); - SCALE_PROPERTY.set(hotseat, 1f); - } - }); - return springTransY; } @Override @@ -204,34 +155,15 @@ public class LauncherSwipeHandlerV2 extends @Override public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress, float radius) { + super.update(config, currentRect, progress, radius); int fgAlpha = 255; if (config != null && PROTOTYPE_APP_CLOSE.get()) { - DragLayer dl = mActivity.getDragLayer(); - float translationY = config.getWorkspaceTransY(); - dl.setTranslationY(translationY); - - float alpha = mapToRange(progress, 0, launcherAlphaMax, 0, 1f, LINEAR); - dl.setAlpha(Math.min(alpha, 1f)); - - float scale = Math.min(1f, config.getWorkspaceScale()); - SCALE_PROPERTY.set(mActivity.getWorkspace(), scale); - SCALE_PROPERTY.set(mActivity.getHotseat(), scale); - SCALE_PROPERTY.set(mActivity.getAppsView(), scale); - progress = config.getInterpolatedProgress(); fgAlpha = config.getFgAlpha(); } floatingIconView.update(1f, fgAlpha, currentRect, progress, windowAlphaThreshold, radius, false); } - - @Override - public void onCancel() { - floatingIconView.fastFinish(); - if (mBounceBackAnimator != null) { - mBounceBackAnimator.cancel(); - } - } }; } @@ -246,10 +178,11 @@ public class LauncherSwipeHandlerV2 extends hostView, backgroundLocation, windowSize, mTaskViewSimulator.getCurrentCornerRadius(), isTargetTranslucent); - return new LauncherHomeAnimationFactory() { + return new FloatingViewHomeAnimationFactory(floatingWidgetView) { @Override public RectF getWindowTargetRect() { + super.getWindowTargetRect(); return backgroundLocation; } @@ -260,6 +193,8 @@ public class LauncherSwipeHandlerV2 extends @Override public void setAnimation(RectFSpringAnim anim) { + super.setAnimation(anim); + anim.addAnimatorListener(floatingWidgetView); floatingWidgetView.setOnTargetChangeListener(anim::onTargetPositionChanged); floatingWidgetView.setFastFinishRunnable(anim::end); @@ -273,15 +208,11 @@ public class LauncherSwipeHandlerV2 extends @Override public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress, float radius) { + super.update(config, currentRect, progress, radius); floatingWidgetView.update(currentRect, 1 /* floatingWidgetAlpha */, config != null ? config.getFgAlpha() : 1f /* foregroundAlpha */, 0 /* fallbackBackgroundAlpha */, 1 - progress); } - - @Override - public void onCancel() { - floatingWidgetView.fastFinish(); - } }; } @@ -323,6 +254,120 @@ public class LauncherSwipeHandlerV2 extends true /* toRecents */, callback, true /* sendUserLeaveHint */); } + private class FloatingViewHomeAnimationFactory extends LauncherHomeAnimationFactory { + + private final float mTransY; + private final FloatingView mFloatingView; + private ValueAnimator mBounceBackAnimator; + private final AnimatorSet mWorkspaceReveal; + + FloatingViewHomeAnimationFactory(FloatingView floatingView) { + mFloatingView = floatingView; + + ResourceProvider rp = DynamicResource.provider(mActivity); + mTransY = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp)); + + mWorkspaceReveal = PROTOTYPE_APP_CLOSE.get() + ? new WorkspaceRevealAnim(mActivity, true /* animateScrim */).getAnimators() + : null; + } + + @Override + public @NonNull RectF getWindowTargetRect() { + if (PROTOTYPE_APP_CLOSE.get()) { + // We want the target rect to be at this offset position, so that all + // launcher content can spring back upwards. + mFloatingView.setPositionOffsetY(mTransY); + } + return super.getWindowTargetRect(); + } + + @Override + public boolean shouldPlayAtomicWorkspaceReveal() { + return false; + } + + @Override + public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress, + float radius) { + if (config != null && PROTOTYPE_APP_CLOSE.get()) { + DragLayer dl = mActivity.getDragLayer(); + float translationY = config.getWorkspaceTransY(); + dl.setTranslationY(translationY); + + long duration = mWorkspaceReveal.getDuration(); + long playTime = boundToRange(round(duration * progress), 0, duration); + mWorkspaceReveal.setCurrentPlayTime(playTime); + } + } + + protected void bounceBackToRestingPosition() { + final float startValue = mTransY; + final float endValue = 0; + // Ensures the velocity is always aligned with the direction. + float pixelPerSecond = Math.abs(mSwipeVelocity) * Math.signum(endValue - mTransY); + + DragLayer dl = mActivity.getDragLayer(); + Workspace workspace = mActivity.getWorkspace(); + Hotseat hotseat = mActivity.getHotseat(); + + ResourceProvider rp = DynamicResource.provider(mActivity); + ValueAnimator springTransY = new SpringAnimationBuilder(dl.getContext()) + .setStiffness(rp.getFloat(R.dimen.swipe_up_trans_y_stiffness)) + .setDampingRatio(rp.getFloat(R.dimen.swipe_up_trans_y_damping)) + .setMinimumVisibleChange(1f) + .setStartValue(startValue) + .setEndValue(endValue) + .setStartVelocity(pixelPerSecond) + .build(dl, VIEW_TRANSLATE_Y); + springTransY.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + dl.setTranslationY(0f); + dl.setAlpha(1f); + SCALE_PROPERTY.set(workspace, 1f); + SCALE_PROPERTY.set(hotseat, 1f); + } + }); + + mBounceBackAnimator = springTransY; + mBounceBackAnimator.start(); + } + + @Override + public void setAnimation(RectFSpringAnim anim) { + if (PROTOTYPE_APP_CLOSE.get()) { + // Use a spring to put drag layer translation back to 0. + anim.addAnimatorListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mFloatingView.setPositionOffsetY(0); + bounceBackToRestingPosition(); + } + }); + + // Will be updated manually below so that the two animations are in sync. + mWorkspaceReveal.start(); + mWorkspaceReveal.pause(); + + anim.addAnimatorListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mWorkspaceReveal.end(); + } + }); + } + } + + @Override + public void onCancel() { + mFloatingView.fastFinish(); + if (mBounceBackAnimator != null) { + mBounceBackAnimator.cancel(); + } + } + } + private class LauncherHomeAnimationFactory extends HomeAnimationFactory { @NonNull @Override @@ -336,8 +381,12 @@ public class LauncherSwipeHandlerV2 extends @Override public void playAtomicAnimation(float velocity) { - new StaggeredWorkspaceAnim(mActivity, velocity, true /* animateOverviewScrim */, - !PROTOTYPE_APP_CLOSE.get()).start(); + if (!PROTOTYPE_APP_CLOSE.get()) { + new StaggeredWorkspaceAnim(mActivity, velocity, true /* animateOverviewScrim */) + .start(); + } else if (shouldPlayAtomicWorkspaceReveal()) { + new WorkspaceRevealAnim(mActivity, true).start(); + } } @Override diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java index 29a00d16b0..b79e9344bf 100644 --- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java +++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java @@ -129,6 +129,7 @@ public abstract class SwipeUpAnimationLogic { } protected abstract class HomeAnimationFactory { + protected float mSwipeVelocity; public @NonNull RectF getWindowTargetRect() { PagedOrientationHandler orientationHandler = getOrientationHandler(); @@ -152,10 +153,18 @@ public abstract class SwipeUpAnimationLogic { public abstract @NonNull AnimatorPlaybackController createActivityAnimationToHome(); + public void setSwipeVelocity(float velocity) { + mSwipeVelocity = velocity; + } + public void playAtomicAnimation(float velocity) { // No-op } + public boolean shouldPlayAtomicWorkspaceReveal() { + return true; + } + public void setAnimation(RectFSpringAnim anim) { } public boolean keepWindowOpaque() { return false; } diff --git a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java index 10b7662ad9..badb41a7c9 100644 --- a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java +++ b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java @@ -30,7 +30,7 @@ import com.android.launcher3.states.StateAnimationConfig; /** * Runs an animation from overview to home. Currently, this animation is just a wrapper around the - * normal state transition and may play a {@link StaggeredWorkspaceAnim} if we're starting from an + * normal state transition and may play a {@link WorkspaceRevealAnim} if we're starting from an * upward fling. */ public class OverviewToHomeAnim { @@ -51,7 +51,7 @@ public class OverviewToHomeAnim { /** * Starts the animation. If velocity < 0 (i.e. upwards), also plays a - * {@link StaggeredWorkspaceAnim}. + * {@link WorkspaceRevealAnim}. */ public void animateWithVelocity(float velocity) { StateManager stateManager = mLauncher.getStateManager(); @@ -61,18 +61,18 @@ public class OverviewToHomeAnim { } AnimatorSet anim = new AnimatorSet(); - boolean playStaggeredWorkspaceAnim = velocity < 0; - if (playStaggeredWorkspaceAnim) { - StaggeredWorkspaceAnim staggeredWorkspaceAnim = new StaggeredWorkspaceAnim( - mLauncher, velocity, false /* animateOverviewScrim */); - staggeredWorkspaceAnim.addAnimatorListener(new AnimationSuccessListener() { + boolean playWorkspaceRevealAnim = velocity < 0; + if (playWorkspaceRevealAnim) { + WorkspaceRevealAnim workspaceRevealAnim = new WorkspaceRevealAnim(mLauncher, + false /* animateOverviewScrim */); + workspaceRevealAnim.addAnimatorListener(new AnimationSuccessListener() { @Override public void onAnimationSuccess(Animator animator) { mIsHomeStaggeredAnimFinished = true; maybeOverviewToHomeAnimComplete(); } }); - anim.play(staggeredWorkspaceAnim.getAnimators()); + anim.play(workspaceRevealAnim.getAnimators()); } else { mIsHomeStaggeredAnimFinished = true; } diff --git a/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java b/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java new file mode 100644 index 0000000000..50da93b828 --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.quickstep.util; + +import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; +import static com.android.launcher3.LauncherState.BACKGROUND_APP; +import static com.android.launcher3.LauncherState.NORMAL; +import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER; +import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTROLLER; +import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW; +import static com.android.launcher3.states.StateAnimationConfig.SKIP_SCRIM; + +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.view.View; + +import com.android.launcher3.BaseQuickstepLauncher; +import com.android.launcher3.Launcher; +import com.android.launcher3.R; +import com.android.launcher3.Workspace; +import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.statehandlers.DepthController; +import com.android.launcher3.states.StateAnimationConfig; +import com.android.launcher3.util.DynamicResource; +import com.android.quickstep.views.RecentsView; +import com.android.systemui.plugins.ResourceProvider; + +/** + * Creates an animation that reveals the workspace. + * This is used in conjunction with the swipe up to home animation. + */ +public class WorkspaceRevealAnim { + + // Should be used for animations running alongside this WorkspaceRevealAnim. + public static final int DURATION_MS = 350; + + private final float mScaleStart; + private final AnimatorSet mAnimators = new AnimatorSet(); + + public WorkspaceRevealAnim(Launcher launcher, boolean animateOverviewScrim) { + prepareToAnimate(launcher, animateOverviewScrim); + + ResourceProvider rp = DynamicResource.provider(launcher); + mScaleStart = rp.getFloat(R.dimen.swipe_up_scale_start); + + Workspace workspace = launcher.getWorkspace(); + workspace.setPivotToScaleWithSelf(launcher.getHotseat()); + + // Add reveal animations. + addRevealAnimatorsForView(workspace); + addRevealAnimatorsForView(launcher.getHotseat()); + + // Add overview scrim animation. + if (animateOverviewScrim) { + PendingAnimation overviewScrimBuilder = new PendingAnimation(DURATION_MS); + launcher.getWorkspace().getStateTransitionAnimation() + .setScrim(overviewScrimBuilder, NORMAL, new StateAnimationConfig()); + mAnimators.play(overviewScrimBuilder.buildAnim()); + } + + // Add depth controller animation. + if (launcher instanceof BaseQuickstepLauncher) { + PendingAnimation depthBuilder = new PendingAnimation(DURATION_MS); + DepthController depth = ((BaseQuickstepLauncher) launcher).getDepthController(); + depth.setStateWithAnimation(NORMAL, new StateAnimationConfig(), depthBuilder); + mAnimators.play(depthBuilder.buildAnim()); + } + + // Add sysui scrim animation. + mAnimators.play(launcher.getRootView().getSysUiScrim().createSysuiMultiplierAnim(0f, 1f)); + + mAnimators.setDuration(DURATION_MS); + mAnimators.setInterpolator(Interpolators.DECELERATED_EASE); + } + + private void addRevealAnimatorsForView(View v) { + ObjectAnimator scale = ObjectAnimator.ofFloat(v, SCALE_PROPERTY, mScaleStart, 1f); + scale.setDuration(DURATION_MS); + scale.setInterpolator(Interpolators.DECELERATED_EASE); + mAnimators.play(scale); + + ObjectAnimator alpha = ObjectAnimator.ofFloat(v, View.ALPHA, 0, 1f); + alpha.setDuration(DURATION_MS); + alpha.setInterpolator(Interpolators.DECELERATED_EASE); + mAnimators.play(alpha); + } + + /** + * Setup workspace with 0 duration. + */ + private void prepareToAnimate(Launcher launcher, boolean animateOverviewScrim) { + StateAnimationConfig config = new StateAnimationConfig(); + config.animFlags = SKIP_OVERVIEW | SKIP_DEPTH_CONTROLLER | SKIP_SCRIM; + config.duration = 0; + // setRecentsAttachedToAppWindow() will animate recents out. + launcher.getStateManager().createAtomicAnimation(BACKGROUND_APP, NORMAL, config).start(); + + // Stop scrolling so that it doesn't interfere with the translation offscreen. + launcher.getOverviewPanel().getScroller().forceFinished(true); + + if (animateOverviewScrim) { + launcher.getWorkspace().getStateTransitionAnimation() + .setScrim(NO_ANIM_PROPERTY_SETTER, BACKGROUND_APP, config); + } + } + + public AnimatorSet getAnimators() { + return mAnimators; + } + + public WorkspaceRevealAnim addAnimatorListener(Animator.AnimatorListener listener) { + mAnimators.addListener(listener); + return this; + } + + /** + * Starts the animation. + */ + public void start() { + mAnimators.start(); + } +} diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java index 121e09400f..0012dd805d 100644 --- a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java +++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java @@ -34,6 +34,7 @@ import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.dragndrop.DragLayer; +import com.android.launcher3.views.FloatingView; import com.android.launcher3.views.ListenerView; import com.android.launcher3.widget.LauncherAppWidgetHostView; import com.android.launcher3.widget.RoundedCornerEnforcement; @@ -41,7 +42,7 @@ import com.android.launcher3.widget.RoundedCornerEnforcement; /** A view that mimics an App Widget through a launch animation. */ @TargetApi(Build.VERSION_CODES.S) public class FloatingWidgetView extends FrameLayout implements AnimatorListener, - OnGlobalLayoutListener { + OnGlobalLayoutListener, FloatingView { private static final Matrix sTmpMatrix = new Matrix(); private final Launcher mLauncher; @@ -59,6 +60,8 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener, private Runnable mOnTargetChangeRunnable; private boolean mAppTargetIsTranslucent; + private float mIconOffsetY; + public FloatingWidgetView(Context context) { this(context, null); } @@ -129,6 +132,7 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener, } /** Callback at the end or early exit of the animation. */ + @Override public void fastFinish() { if (isUninitialized()) return; Runnable fastFinishRunnable = mFastFinishRunnable; @@ -192,6 +196,12 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener, positionViews(); } + @Override + public void setPositionOffsetY(float y) { + mIconOffsetY = y; + onGlobalLayout(); + } + /** Sets the layout parameters of the floating view and its background view child. */ private void positionViews() { LayoutParams layoutParams = (LayoutParams) getLayoutParams(); @@ -200,7 +210,7 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener, // FloatingWidgetView layout is forced LTR mBackgroundView.setTranslationX(mBackgroundPosition.left); - mBackgroundView.setTranslationY(mBackgroundPosition.top); + mBackgroundView.setTranslationY(mBackgroundPosition.top + mIconOffsetY); LayoutParams backgroundParams = (LayoutParams) mBackgroundView.getLayoutParams(); backgroundParams.leftMargin = 0; backgroundParams.topMargin = 0; @@ -215,7 +225,8 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener, sTmpMatrix.setTranslate(-mBackgroundOffset.left - mAppWidgetView.getLeft(), -mBackgroundOffset.top - mAppWidgetView.getTop()); sTmpMatrix.postScale(foregroundScale, foregroundScale); - sTmpMatrix.postTranslate(mBackgroundPosition.left, mBackgroundPosition.top); + sTmpMatrix.postTranslate(mBackgroundPosition.left, mBackgroundPosition.top + + mIconOffsetY); mForegroundOverlayView.setMatrix(sTmpMatrix); } } @@ -240,6 +251,7 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener, } private void recycle() { + mIconOffsetY = 0; mEndRunnable = null; mFastFinishRunnable = null; mOnTargetChangeRunnable = null; diff --git a/res/values/config.xml b/res/values/config.xml index 102d4e0c37..77c7e986d5 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -126,7 +126,7 @@ 1.5 - 0.98 + 0.88 400 4.5 diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java index 81581fa80a..f973c2be1e 100644 --- a/src/com/android/launcher3/views/FloatingIconView.java +++ b/src/com/android/launcher3/views/FloatingIconView.java @@ -63,7 +63,7 @@ import com.android.launcher3.shortcuts.DeepShortcutView; */ @TargetApi(Build.VERSION_CODES.Q) public class FloatingIconView extends FrameLayout implements - Animator.AnimatorListener, OnGlobalLayoutListener { + Animator.AnimatorListener, OnGlobalLayoutListener, FloatingView { private static final String TAG = FloatingIconView.class.getSimpleName(); @@ -443,6 +443,7 @@ public class FloatingIconView extends FrameLayout implements mFastFinishRunnable = runnable; } + @Override public void fastFinish() { if (mFastFinishRunnable != null) { mFastFinishRunnable.run(); @@ -475,9 +476,7 @@ public class FloatingIconView extends FrameLayout implements @Override public void onAnimationRepeat(Animator animator) {} - /** - * Offsets and updates the position of this view by {@param y}. - */ + @Override public void setPositionOffsetY(float y) { mIconOffsetY = y; onGlobalLayout(); diff --git a/src/com/android/launcher3/views/FloatingView.java b/src/com/android/launcher3/views/FloatingView.java new file mode 100644 index 0000000000..ea4fd15f7f --- /dev/null +++ b/src/com/android/launcher3/views/FloatingView.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.views; + +/** + * Shared interface for floating views. + */ +public interface FloatingView { + + /** + * Offsets and updates the position of this view by {@param y}. + */ + void setPositionOffsetY(float y); + + /** + * Fast finish the animation. + */ + void fastFinish(); +}