diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index 95198b8e36..9afa862a44 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -20,15 +20,14 @@ import static com.android.launcher3.LauncherState.BACKGROUND_APP; import static com.android.launcher3.LauncherState.HOTSEAT_ICONS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; -import static com.android.launcher3.LauncherStateManager.ANIM_ALL_COMPONENTS; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_SCALE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_TRANSLATE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS; import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE; import static com.android.launcher3.anim.Interpolators.DEACCEL_3; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS; import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch; import static com.android.quickstep.TaskViewUtils.getRecentsWindowAnimator; @@ -47,9 +46,9 @@ import androidx.annotation.Nullable; import com.android.launcher3.LauncherState.ScaleAndTranslation; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.anim.AnimatorPlaybackController; -import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.SpringAnimationBuilder; +import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.PagedOrientationHandler; import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.quickstep.views.RecentsView; @@ -210,17 +209,20 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti .setValues(values) .build(mLauncher); case INDEX_PAUSE_TO_OVERVIEW_ANIM: { - AnimatorSetBuilder builder = new AnimatorSetBuilder(); - builder.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2); - builder.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_3); + StateAnimationConfig config = new StateAnimationConfig(); + config.duration = ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW; + + config.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2); + config.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_3); if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) { - builder.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2); - builder.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2); + config.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2); + config.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2); } + + LauncherStateManager stateManager = mLauncher.getStateManager(); return stateManager.createAtomicAnimation( - stateManager.getCurrentStableState(), OVERVIEW, builder, - ANIM_ALL_COMPONENTS, ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW); + stateManager.getCurrentStableState(), OVERVIEW, config); } default: diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java index 65aaf22f49..549187f9e9 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java @@ -20,7 +20,6 @@ import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA; import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS; -import android.animation.ValueAnimator; import android.annotation.TargetApi; import android.os.Build; import android.util.FloatProperty; @@ -29,10 +28,10 @@ import androidx.annotation.NonNull; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; -import com.android.launcher3.LauncherStateManager.AnimationConfig; import com.android.launcher3.anim.AnimationSuccessListener; -import com.android.launcher3.anim.AnimatorSetBuilder; +import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.PropertySetter; +import com.android.launcher3.states.StateAnimationConfig; import com.android.quickstep.views.ClearAllButton; import com.android.quickstep.views.LauncherRecentsView; import com.android.quickstep.views.RecentsView; @@ -61,25 +60,22 @@ public final class RecentsViewStateController extends } @Override - void setStateWithAnimationInternal(@NonNull final LauncherState toState, - @NonNull AnimatorSetBuilder builder, @NonNull AnimationConfig config) { - super.setStateWithAnimationInternal(toState, builder, config); + void setStateWithAnimationInternal(@NonNull LauncherState toState, + @NonNull StateAnimationConfig config, @NonNull PendingAnimation builder) { + super.setStateWithAnimationInternal(toState, config, builder); - ValueAnimator updateAnim = ValueAnimator.ofFloat(0, 1).setDuration(config.duration); if (toState.overviewUi) { // While animating into recents, update the visible task data as needed - updateAnim.addUpdateListener(valueAnimator -> mRecentsView.loadVisibleTaskData()); + builder.addOnFrameCallback(mRecentsView::loadVisibleTaskData); mRecentsView.updateEmptyMessage(); } else { - updateAnim.addListener( + builder.getAnim().addListener( AnimationSuccessListener.forRunnable(mRecentsView::resetTaskVisuals)); } - builder.play(updateAnim); - PropertySetter propertySetter = config.getPropertySetter(builder); - setAlphas(propertySetter, toState.getVisibleElements(mLauncher)); - float fullscreenProgress = toState.getOverviewFullscreenProgress(); - propertySetter.setFloat(mRecentsView, FULLSCREEN_PROGRESS, fullscreenProgress, LINEAR); + setAlphas(builder, toState.getVisibleElements(mLauncher)); + builder.setFloat(mRecentsView, FULLSCREEN_PROGRESS, + toState.getOverviewFullscreenProgress(), LINEAR); } private void setAlphas(PropertySetter propertySetter, int visibleElements) { diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java index 427206a65b..8087611633 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java @@ -14,17 +14,18 @@ * limitations under the License. */ package com.android.launcher3.uioverrides.states; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCRIM_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X; + import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.INSTANT; import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCRIM_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.R; -import com.android.launcher3.anim.AnimatorSetBuilder; +import com.android.launcher3.states.StateAnimationConfig; public class OverviewPeekState extends OverviewState { public OverviewPeekState(int id) { @@ -41,11 +42,11 @@ public class OverviewPeekState extends OverviewState { @Override public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState, - AnimatorSetBuilder builder) { + StateAnimationConfig config) { if (this == OVERVIEW_PEEK && fromState == NORMAL) { - builder.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT); - builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_7); - builder.setInterpolator(ANIM_OVERVIEW_SCRIM_FADE, FAST_OUT_SLOW_IN); + config.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT); + config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_7); + config.setInterpolator(ANIM_OVERVIEW_SCRIM_FADE, FAST_OUT_SLOW_IN); } } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java index bfbb6305b9..6a34917a26 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java @@ -18,13 +18,6 @@ package com.android.launcher3.uioverrides.states; import static android.view.View.VISIBLE; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_Y; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE; import static com.android.launcher3.anim.Interpolators.ACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL_2; import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2; @@ -32,6 +25,13 @@ import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7; import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS; import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE; import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview; @@ -48,8 +48,8 @@ import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.Workspace; import com.android.launcher3.allapps.DiscoveryBounce; -import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.compat.AccessibilityManagerCompat; +import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.quickstep.SysUINavigationMode; @@ -225,14 +225,14 @@ public class OverviewState extends LauncherState { @Override public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState, - AnimatorSetBuilder builder) { + StateAnimationConfig config) { if ((fromState == NORMAL || fromState == HINT_STATE) && this == OVERVIEW) { if (SysUINavigationMode.getMode(launcher) == NO_BUTTON) { - builder.setInterpolator(ANIM_WORKSPACE_SCALE, + config.setInterpolator(ANIM_WORKSPACE_SCALE, fromState == NORMAL ? ACCEL : OVERSHOOT_1_2); - builder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL); + config.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL); } else { - builder.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2); + config.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2); // Scale up the recents, if it is not coming from the side RecentsView overview = launcher.getOverviewPanel(); @@ -240,15 +240,15 @@ public class OverviewState extends LauncherState { SCALE_PROPERTY.set(overview, RECENTS_PREPARE_SCALE); } } - builder.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2); - builder.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2); + config.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2); + config.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2); Interpolator translationInterpolator = ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(launcher) ? OVERSHOOT_1_2 : OVERSHOOT_1_7; - builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, translationInterpolator); - builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, translationInterpolator); - builder.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2); + config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, translationInterpolator); + config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, translationInterpolator); + config.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java index b34701331e..785a480174 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java @@ -21,16 +21,16 @@ import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherState.OVERVIEW_PEEK; -import static com.android.launcher3.LauncherStateManager.PLAY_ATOMIC_OVERVIEW_PEEK; -import static com.android.launcher3.LauncherStateManager.SKIP_OVERVIEW; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_HEADER_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE; import static com.android.launcher3.anim.Interpolators.ACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL_3; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_HEADER_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE; +import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK; +import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW; import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; @@ -44,10 +44,10 @@ import android.view.ViewConfiguration; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppTransitionManagerImpl; import com.android.launcher3.LauncherState; -import com.android.launcher3.LauncherStateManager.AnimationFlags; import com.android.launcher3.anim.AnimationSuccessListener; -import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.states.StateAnimationConfig; +import com.android.launcher3.states.StateAnimationConfig.AnimationFlags; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.util.VibratorWrapper; import com.android.quickstep.SystemUiProxy; @@ -105,8 +105,12 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { LauncherState fromState = isPaused ? NORMAL : OVERVIEW_PEEK; LauncherState toState = isPaused ? OVERVIEW_PEEK : NORMAL; long peekDuration = isPaused ? PEEK_IN_ANIM_DURATION : PEEK_OUT_ANIM_DURATION; - mPeekAnim = mLauncher.getStateManager().createAtomicAnimation(fromState, toState, - new AnimatorSetBuilder(), PLAY_ATOMIC_OVERVIEW_PEEK, peekDuration); + + StateAnimationConfig config = new StateAnimationConfig(); + config.duration = peekDuration; + config.animFlags = PLAY_ATOMIC_OVERVIEW_PEEK; + mPeekAnim = mLauncher.getStateManager().createAtomicAnimation( + fromState, toState, config); mPeekAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -130,10 +134,10 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { } @Override - protected AnimatorSetBuilder getAnimatorSetBuilderForStates(LauncherState fromState, - LauncherState toState) { + protected StateAnimationConfig getConfigForStates( + LauncherState fromState, LauncherState toState) { if (fromState == NORMAL && toState == ALL_APPS) { - AnimatorSetBuilder builder = new AnimatorSetBuilder(); + StateAnimationConfig builder = new StateAnimationConfig(); // Fade in prediction icons quickly, then rest of all apps after reaching overview. float progressToReachOverview = NORMAL.getVerticalProgress(mLauncher) - OVERVIEW.getVerticalProgress(mLauncher); @@ -152,7 +156,7 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { builder.setInterpolator(ANIM_WORKSPACE_FADE, DEACCEL_3); return builder; } else if (fromState == ALL_APPS && toState == NORMAL) { - AnimatorSetBuilder builder = new AnimatorSetBuilder(); + StateAnimationConfig builder = new StateAnimationConfig(); // Keep all apps/predictions opaque until the very end of the transition. float progressToReachOverview = OVERVIEW.getVerticalProgress(mLauncher); builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress( @@ -165,7 +169,7 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { 1)); return builder; } - return super.getAnimatorSetBuilderForStates(fromState, toState); + return super.getConfigForStates(fromState, toState); } @Override @@ -211,9 +215,11 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); if (mCancelled) { - mPeekAnim = mLauncher.getStateManager().createAtomicAnimation(mFromState, - mToState, new AnimatorSetBuilder(), PLAY_ATOMIC_OVERVIEW_PEEK, - PEEK_OUT_ANIM_DURATION); + StateAnimationConfig config = new StateAnimationConfig(); + config.animFlags = PLAY_ATOMIC_OVERVIEW_PEEK; + config.duration = PEEK_OUT_ANIM_DURATION; + mPeekAnim = mLauncher.getStateManager().createAtomicAnimation( + mFromState, mToState, config); mPeekAnim.start(); } mAtomicAnim = null; diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java index a0ca8865d8..77118d58af 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java @@ -15,8 +15,7 @@ */ package com.android.launcher3.uioverrides.touchcontrollers; -import static android.view.View.TRANSLATION_X; - +import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; @@ -26,9 +25,6 @@ import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TI import static com.android.launcher3.touch.AbstractStateChangeTouchController.SUCCESS_TRANSITION_PROGRESS; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.view.MotionEvent; import android.view.animation.Interpolator; @@ -36,16 +32,16 @@ import android.view.animation.Interpolator; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; -import com.android.launcher3.LauncherStateManager.AnimationConfig; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; -import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.SingleAxisSwipeDetector; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; @@ -132,46 +128,37 @@ public class NavBarToHomeTouchController implements TouchController, private void initCurrentAnimation() { long accuracy = (long) (getShiftRange() * 2); - final AnimatorSet anim = new AnimatorSet(); + final PendingAnimation builder = new PendingAnimation(accuracy); if (mStartState == OVERVIEW) { RecentsView recentsView = mLauncher.getOverviewPanel(); float pullbackDist = mPullbackDistance; if (!recentsView.isRtl()) { pullbackDist = -pullbackDist; } - ObjectAnimator pullback = ObjectAnimator.ofFloat(recentsView, TRANSLATION_X, - pullbackDist); - pullback.setInterpolator(PULLBACK_INTERPOLATOR); + + builder.setFloat(recentsView, VIEW_TRANSLATE_X, pullbackDist, PULLBACK_INTERPOLATOR); if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - pullback.addUpdateListener( - valueAnimator -> recentsView.redrawLiveTile(false /* mightNeedToRefill */)); + builder.addOnFrameCallback( + () -> recentsView.redrawLiveTile(false /* mightNeedToRefill */)); } - anim.play(pullback); } else if (mStartState == ALL_APPS) { - AnimatorSetBuilder builder = new AnimatorSetBuilder(); AllAppsTransitionController allAppsController = mLauncher.getAllAppsController(); - Animator allAppsProgress = ObjectAnimator.ofFloat(allAppsController, ALL_APPS_PROGRESS, - -mPullbackDistance / allAppsController.getShiftRange()); - allAppsProgress.setInterpolator(PULLBACK_INTERPOLATOR); - builder.play(allAppsProgress); + builder.setFloat(allAppsController, ALL_APPS_PROGRESS, + -mPullbackDistance / allAppsController.getShiftRange(), PULLBACK_INTERPOLATOR); + // Slightly fade out all apps content to further distinguish from scrolling. - builder.setInterpolator(AnimatorSetBuilder.ANIM_ALL_APPS_FADE, Interpolators - .mapToProgress(PULLBACK_INTERPOLATOR, 0, 0.5f)); - AnimationConfig config = new AnimationConfig(); + StateAnimationConfig config = new StateAnimationConfig(); config.duration = accuracy; - allAppsController.setAlphas(mEndState.getVisibleElements(mLauncher), config, builder); - anim.play(builder.build()); + config.setInterpolator(StateAnimationConfig.ANIM_ALL_APPS_FADE, Interpolators + .mapToProgress(PULLBACK_INTERPOLATOR, 0, 0.5f)); + + allAppsController.setAlphas(mEndState, config, builder); } AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mLauncher); if (topView != null) { - Animator hintCloseAnim = topView.createHintCloseAnim(mPullbackDistance); - if (hintCloseAnim != null) { - hintCloseAnim.setInterpolator(PULLBACK_INTERPOLATOR); - anim.play(hintCloseAnim); - } + topView.addHintCloseAnim(mPullbackDistance, PULLBACK_INTERPOLATOR, builder); } - anim.setDuration(accuracy); - mCurrentAnimation = AnimatorPlaybackController.wrap(anim, accuracy) + mCurrentAnimation = builder.createPlaybackController() .setOnCancelRunnable(this::clearState); } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java index 7cebabe694..064133cfd9 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java @@ -19,9 +19,9 @@ package com.android.launcher3.uioverrides.touchcontrollers; import static com.android.launcher3.LauncherState.HINT_STATE; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; -import static com.android.launcher3.LauncherStateManager.PLAY_ATOMIC_OVERVIEW_PEEK; import static com.android.launcher3.Utilities.EDGE_NAV_BAR; import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; +import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK; import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC; import android.animation.AnimatorSet; @@ -34,7 +34,7 @@ import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimationSuccessListener; -import com.android.launcher3.anim.AnimatorSetBuilder; +import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.util.VibratorWrapper; import com.android.quickstep.util.StaggeredWorkspaceAnim; @@ -171,11 +171,11 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo // StaggeredWorkspaceAnim doesn't animate overview, so we handle it here. stateManager.cancelAnimation(); - AnimatorSetBuilder builder = new AnimatorSetBuilder(); - long duration = OVERVIEW.getTransitionDuration(mLauncher); + StateAnimationConfig config = new StateAnimationConfig(); + config.duration = OVERVIEW.getTransitionDuration(mLauncher); + config.animFlags = PLAY_ATOMIC_OVERVIEW_PEEK; AnimatorSet anim = stateManager.createAtomicAnimation( - stateManager.getState(), NORMAL, builder, - PLAY_ATOMIC_OVERVIEW_PEEK, duration); + stateManager.getState(), NORMAL, config); anim.addListener(AnimationSuccessListener.forRunnable( () -> onSwipeInteractionCompleted(NORMAL, Touch.SWIPE))); anim.start(); diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java index 81a6d9b786..c92a872ba9 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java @@ -21,18 +21,18 @@ import static com.android.launcher3.LauncherState.HOTSEAT_ICONS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherState.QUICK_SWITCH; -import static com.android.launcher3.LauncherStateManager.ANIM_ALL_COMPONENTS; -import static com.android.launcher3.LauncherStateManager.SKIP_OVERVIEW; import static com.android.launcher3.anim.AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE; import static com.android.launcher3.anim.Interpolators.ACCEL_0_75; import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL_5; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity; +import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE; +import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW; import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_RIGHT; import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_UP; import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs; @@ -55,15 +55,13 @@ import android.view.animation.Interpolator; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.LauncherState; -import com.android.launcher3.LauncherStateManager.AnimationConfig; -import com.android.launcher3.LauncherStateManager.AnimationFlags; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.anim.AnimatorPlaybackController; -import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.graphics.OverviewScrim; +import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.BaseSwipeDetector; import com.android.launcher3.touch.BothAxesSwipeDetector; import com.android.launcher3.userevent.nano.LauncherLogProto; @@ -192,11 +190,9 @@ public class NoButtonQuickSwitchTouchController implements TouchController, ShelfAnimState shelfState = isPaused ? PEEK : HIDE; if (shelfState == PEEK) { // Some shelf elements (e.g. qsb) were hidden, but we need them visible when peeking. - AnimatorSetBuilder builder = new AnimatorSetBuilder(); AllAppsTransitionController allAppsController = mLauncher.getAllAppsController(); - allAppsController.setAlphas(NORMAL.getVisibleElements(mLauncher), - new AnimationConfig(), builder); - builder.build().setDuration(0).start(); + allAppsController.setAlphas( + NORMAL, new StateAnimationConfig(), NO_ANIM_PROPERTY_SETTER); if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) { // Hotseat was hidden, but we need it visible when peeking. @@ -209,12 +205,12 @@ public class NoButtonQuickSwitchTouchController implements TouchController, private void setupAnimators() { // Animate the non-overview components (e.g. workspace, shelf) out of the way. - AnimatorSetBuilder nonOverviewBuilder = new AnimatorSetBuilder(); + StateAnimationConfig nonOverviewBuilder = new StateAnimationConfig(); nonOverviewBuilder.setInterpolator(ANIM_WORKSPACE_FADE, FADE_OUT_INTERPOLATOR); nonOverviewBuilder.setInterpolator(ANIM_ALL_APPS_FADE, FADE_OUT_INTERPOLATOR); nonOverviewBuilder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, TRANSLATE_OUT_INTERPOLATOR); nonOverviewBuilder.setInterpolator(ANIM_VERTICAL_PROGRESS, TRANSLATE_OUT_INTERPOLATOR); - updateNonOverviewAnim(QUICK_SWITCH, nonOverviewBuilder, ANIM_ALL_COMPONENTS); + updateNonOverviewAnim(QUICK_SWITCH, nonOverviewBuilder); mNonOverviewAnim.dispatchOnStart(); if (mRecentsView.getTaskViewCount() == 0) { @@ -230,11 +226,12 @@ public class NoButtonQuickSwitchTouchController implements TouchController, } /** Create state animation to control non-overview components. */ - private void updateNonOverviewAnim(LauncherState toState, AnimatorSetBuilder builder, - @AnimationFlags int animComponents) { - long accuracy = (long) (Math.max(mXRange, mYRange) * 2); - mNonOverviewAnim = mLauncher.getStateManager().createAnimationToNewWorkspace(toState, - builder, accuracy, this::clearState, animComponents | SKIP_OVERVIEW); + private void updateNonOverviewAnim(LauncherState toState, StateAnimationConfig config) { + config.duration = (long) (Math.max(mXRange, mYRange) * 2); + config.animFlags = config.animFlags | SKIP_OVERVIEW; + mNonOverviewAnim = mLauncher.getStateManager() + .createAnimationToNewWorkspace(toState, config) + .setOnCancelRunnable(this::clearState); } private void setupOverviewAnimators() { @@ -419,8 +416,10 @@ public class NoButtonQuickSwitchTouchController implements TouchController, if (flingUpToNormal && !mIsHomeScreenVisible) { // We are flinging to home while workspace is invisible, run the same staggered // animation as from an app. + StateAnimationConfig config = new StateAnimationConfig(); // Update mNonOverviewAnim to do nothing so it doesn't interfere. - updateNonOverviewAnim(targetState, new AnimatorSetBuilder(), 0 /* animComponents */); + config.animFlags = 0; + updateNonOverviewAnim(targetState, config); nonOverviewAnim = mNonOverviewAnim.getAnimationPlayer(); new StaggeredWorkspaceAnim(mLauncher, velocity.y, false /* animateOverviewScrim */) diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java index 8de1b3acbe..9e53959568 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java @@ -17,18 +17,17 @@ package com.android.launcher3.uioverrides.touchcontrollers; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.QUICK_SWITCH; -import static com.android.launcher3.LauncherStateManager.ANIM_ALL_COMPONENTS; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_Y; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE; import static com.android.launcher3.anim.Interpolators.ACCEL_2; import static com.android.launcher3.anim.Interpolators.DEACCEL_2; import static com.android.launcher3.anim.Interpolators.INSTANT; import static com.android.launcher3.anim.Interpolators.LINEAR; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE; import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW; import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; @@ -41,7 +40,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.Utilities; -import com.android.launcher3.anim.AnimatorSetBuilder; +import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.AbstractStateChangeTouchController; import com.android.launcher3.touch.SingleAxisSwipeDetector; import com.android.launcher3.userevent.nano.LauncherLogProto; @@ -108,30 +107,30 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll @Override protected float initCurrentAnimation(int animComponents) { - AnimatorSetBuilder animatorSetBuilder = new AnimatorSetBuilder(); - setupInterpolators(animatorSetBuilder); - long accuracy = (long) (getShiftRange() * 2); - mCurrentAnimation = mLauncher.getStateManager().createAnimationToNewWorkspace(mToState, - animatorSetBuilder, accuracy, this::clearState, ANIM_ALL_COMPONENTS); - mCurrentAnimation.getAnimationPlayer().addUpdateListener(valueAnimator -> { - updateFullscreenProgress((Float) valueAnimator.getAnimatedValue()); - }); + StateAnimationConfig config = new StateAnimationConfig(); + setupInterpolators(config); + config.duration = (long) (getShiftRange() * 2); + mCurrentAnimation = mLauncher.getStateManager() + .createAnimationToNewWorkspace(mToState, config) + .setOnCancelRunnable(this::clearState); + mCurrentAnimation.getAnimationPlayer().addUpdateListener(valueAnimator -> + updateFullscreenProgress((Float) valueAnimator.getAnimatedValue())); return 1 / getShiftRange(); } - private void setupInterpolators(AnimatorSetBuilder animatorSetBuilder) { - animatorSetBuilder.setInterpolator(ANIM_WORKSPACE_FADE, DEACCEL_2); - animatorSetBuilder.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_2); + private void setupInterpolators(StateAnimationConfig stateAnimationConfig) { + stateAnimationConfig.setInterpolator(ANIM_WORKSPACE_FADE, DEACCEL_2); + stateAnimationConfig.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_2); if (SysUINavigationMode.getMode(mLauncher) == Mode.NO_BUTTON) { // Overview lives to the left of workspace, so translate down later than over - animatorSetBuilder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL_2); - animatorSetBuilder.setInterpolator(ANIM_VERTICAL_PROGRESS, ACCEL_2); - animatorSetBuilder.setInterpolator(ANIM_OVERVIEW_SCALE, ACCEL_2); - animatorSetBuilder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, ACCEL_2); - animatorSetBuilder.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT); + stateAnimationConfig.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL_2); + stateAnimationConfig.setInterpolator(ANIM_VERTICAL_PROGRESS, ACCEL_2); + stateAnimationConfig.setInterpolator(ANIM_OVERVIEW_SCALE, ACCEL_2); + stateAnimationConfig.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, ACCEL_2); + stateAnimationConfig.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT); } else { - animatorSetBuilder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, LINEAR); - animatorSetBuilder.setInterpolator(ANIM_VERTICAL_PROGRESS, LINEAR); + stateAnimationConfig.setInterpolator(ANIM_WORKSPACE_TRANSLATE, LINEAR); + stateAnimationConfig.setInterpolator(ANIM_VERTICAL_PROGRESS, LINEAR); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java index cc58fcfd57..b0125a893f 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java @@ -214,7 +214,7 @@ public abstract class TaskViewTouchController if (mCurrentAnimation != null) { mCurrentAnimation.setOnCancelRunnable(null); } - mCurrentAnimation = AnimatorPlaybackController.wrap(mPendingAnimation, maxDuration) + mCurrentAnimation = mPendingAnimation.createPlaybackController() .setOnCancelRunnable(this::clearState); onUserControlledAnimationCreated(mCurrentAnimation); mCurrentAnimation.getTarget().addListener(this); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java index e1ff4f4525..aaf7619dc6 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -48,7 +48,7 @@ import com.android.systemui.shared.system.TransactionCompat; * * @param activity that contains the overview */ -final class AppToOverviewAnimationProvider implements +final class AppToOverviewAnimationProvider extends RemoteAnimationProvider { private static final long RECENTS_LAUNCH_DURATION = 250; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java index 71580cae8b..4abb86a20f 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java @@ -213,7 +213,7 @@ public final class FallbackActivityInterface implements @Override public Rect getOverviewWindowBounds(Rect homeBounds, RemoteAnimationTargetCompat target) { // TODO: Remove this once b/77875376 is fixed - return target.sourceContainerBounds; + return target.screenSpaceBounds; } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java index fc50660c9c..c6b719a114 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java @@ -33,6 +33,7 @@ import com.android.launcher3.appprediction.PredictionUiStateManager; import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.quickstep.util.ActivityInitListener; +import com.android.quickstep.util.RemoteAnimationProvider; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -187,7 +188,15 @@ public class OverviewCommandHelper { // Otherwise, start overview. mListener = mActivityInterface.createActivityInitListener(this::onActivityReady); mListener.registerAndStartActivity(mOverviewComponentObserver.getOverviewIntent(), - this::createWindowAnimation, mContext, MAIN_EXECUTOR.getHandler(), + new RemoteAnimationProvider() { + @Override + public AnimatorSet createWindowAnimation( + RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets) { + return RecentsActivityCommand.this.createWindowAnimation(appTargets, + wallpaperTargets); + } + }, mContext, MAIN_EXECUTOR.getHandler(), mAnimationProvider.getRecentsLaunchDuration()); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java index 681ce0237b..d9e9cc7783 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java @@ -50,6 +50,7 @@ import com.android.systemui.shared.system.WindowManagerWrapper; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius; import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows; +import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING; @@ -119,7 +120,7 @@ public class AppWindowAnimationHelper { private void updateSourceStack(RemoteAnimationTargetCompat target) { mSourceInsets.set(target.contentInsets); - mSourceStackBounds.set(target.sourceContainerBounds); + mSourceStackBounds.set(target.screenSpaceBounds); // TODO: Should sourceContainerBounds already have this offset? mSourceStackBounds.offsetTo(target.position.x, target.position.y); @@ -199,9 +200,17 @@ public class AppWindowAnimationHelper { for (int i = 0; i < params.mTargetSet.unfilteredApps.length; i++) { RemoteAnimationTargetCompat app = params.mTargetSet.unfilteredApps[i]; SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash); - mTmpMatrix.setTranslate(app.position.x, app.position.y); + if (app.localBounds != null) { + mTmpMatrix.setTranslate(0, 0); + if (app.activityType == ACTIVITY_TYPE_HOME && app.mode == MODE_CLOSING) { + mTmpMatrix.setTranslate(app.localBounds.left, app.localBounds.top); + } + } else { + mTmpMatrix.setTranslate(app.position.x, app.position.y); + } + Rect crop = mTmpRect; - crop.set(app.sourceContainerBounds); + crop.set(app.screenSpaceBounds); crop.offsetTo(0, 0); float alpha; float cornerRadius = 0f; @@ -211,7 +220,11 @@ public class AppWindowAnimationHelper { alpha = mTaskAlphaCallback.getAlpha(app, params.mTargetAlpha); if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) { mTmpMatrix.setRectToRect(mSourceRect, mCurrentRect, ScaleToFit.FILL); - mTmpMatrix.postTranslate(app.position.x, app.position.y); + if (app.localBounds != null) { + mTmpMatrix.postTranslate(app.localBounds.left, app.localBounds.top); + } else { + mTmpMatrix.postTranslate(app.position.x, app.position.y); + } mCurrentClipRectF.roundOut(crop); if (mSupportsRoundedCornersOnWindows) { if (params.mCornerRadius > -1) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java index 7e17fbf909..43c5cb5251 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java @@ -18,9 +18,10 @@ package com.android.quickstep.util; import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y; import static com.android.launcher3.LauncherState.BACKGROUND_APP; import static com.android.launcher3.LauncherState.NORMAL; -import static com.android.launcher3.LauncherStateManager.ANIM_ALL_COMPONENTS; -import static com.android.launcher3.LauncherStateManager.SKIP_OVERVIEW; +import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; import static com.android.launcher3.anim.Interpolators.LINEAR; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS; +import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -33,14 +34,13 @@ import com.android.launcher3.CellLayout; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; -import com.android.launcher3.LauncherStateManager.AnimationConfig; import com.android.launcher3.R; import com.android.launcher3.ShortcutAndWidgetContainer; import com.android.launcher3.Workspace; -import com.android.launcher3.anim.AnimatorSetBuilder; -import com.android.launcher3.anim.PropertySetter; +import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.SpringAnimationBuilder; import com.android.launcher3.graphics.OverviewScrim; +import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.util.DynamicResource; import com.android.quickstep.views.RecentsView; import com.android.systemui.plugins.ResourceProvider; @@ -143,11 +143,11 @@ public class StaggeredWorkspaceAnim { * Setup workspace with 0 duration to prepare for our staggered animation. */ private void prepareToAnimate(Launcher launcher) { - AnimatorSetBuilder builder = new AnimatorSetBuilder(); + StateAnimationConfig config = new StateAnimationConfig(); + config.animFlags = ANIM_ALL_COMPONENTS | SKIP_OVERVIEW; + config.duration = 0; // setRecentsAttachedToAppWindow() will animate recents out. - launcher.getStateManager().createAtomicAnimation( - BACKGROUND_APP, NORMAL, builder, ANIM_ALL_COMPONENTS | SKIP_OVERVIEW, 0); - builder.build().start(); + 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); @@ -197,16 +197,12 @@ public class StaggeredWorkspaceAnim { } private void addScrimAnimationForState(Launcher launcher, LauncherState state, long duration) { - AnimatorSetBuilder scrimAnimBuilder = new AnimatorSetBuilder(); - AnimationConfig scrimAnimConfig = new AnimationConfig(); - scrimAnimConfig.duration = duration; - PropertySetter scrimPropertySetter = scrimAnimConfig.getPropertySetter(scrimAnimBuilder); - launcher.getWorkspace().getStateTransitionAnimation().setScrim(scrimPropertySetter, state); - mAnimators.play(scrimAnimBuilder.build()); - Animator fadeOverviewScrim = ObjectAnimator.ofFloat( - launcher.getDragLayer().getOverviewScrim(), OverviewScrim.SCRIM_PROGRESS, - state.getOverviewScrimAlpha(launcher)); - fadeOverviewScrim.setDuration(duration); - mAnimators.play(fadeOverviewScrim); + PendingAnimation builder = new PendingAnimation(duration, mAnimators); + launcher.getWorkspace().getStateTransitionAnimation().setScrim(builder, state); + builder.setFloat( + launcher.getDragLayer().getOverviewScrim(), + OverviewScrim.SCRIM_PROGRESS, + state.getOverviewScrimAlpha(launcher), + ACCEL_DEACCEL); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java index b5e6af475d..8322d8c754 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java @@ -1195,7 +1195,7 @@ public abstract class RecentsView extends PagedView impl if (mPendingAnimation != null) { mPendingAnimation.finish(false, Touch.SWIPE); } - PendingAnimation anim = new PendingAnimation(); + PendingAnimation anim = new PendingAnimation(duration); int count = getPageCount(); if (count == 0) { @@ -1311,7 +1311,7 @@ public abstract class RecentsView extends PagedView impl if (FeatureFlags.IS_STUDIO_BUILD && mPendingAnimation != null) { throw new IllegalStateException("Another pending animation is still running"); } - PendingAnimation anim = new PendingAnimation(); + PendingAnimation anim = new PendingAnimation(duration); int count = getTaskViewCount(); for (int i = 0; i < count; i++) { @@ -1345,8 +1345,7 @@ public abstract class RecentsView extends PagedView impl } private void runDismissAnimation(PendingAnimation pendingAnim) { - AnimatorPlaybackController controller = - AnimatorPlaybackController.wrap(pendingAnim, DISMISS_TASK_DURATION); + AnimatorPlaybackController controller = pendingAnim.createPlaybackController(); controller.dispatchOnStart(); controller.setEndAction(() -> pendingAnim.finish(true, Touch.SWIPE)); controller.getAnimationPlayer().setInterpolator(FAST_OUT_SLOW_IN); @@ -1671,7 +1670,7 @@ public abstract class RecentsView extends PagedView impl int count = getTaskViewCount(); if (count == 0) { - return new PendingAnimation(); + return new PendingAnimation(duration); } int targetSysUiFlags = tv.getThumbnail().getSysUiStatusNavFlags(); @@ -1710,10 +1709,9 @@ public abstract class RecentsView extends PagedView impl anim.play(backgroundBlur); } anim.play(progressAnim); - anim.setDuration(duration) - .setInterpolator(interpolator); + anim.setDuration(duration).setInterpolator(interpolator); - mPendingAnimation = new PendingAnimation(); + mPendingAnimation = new PendingAnimation(duration); mPendingAnimation.add(anim); mPendingAnimation.addEndListener((endState) -> { if (endState.isSuccess) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java index 0e1640edb1..c94b56cade 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java @@ -285,8 +285,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { public AnimatorPlaybackController createLaunchAnimationForRunningTask() { final PendingAnimation pendingAnimation = getRecentsView().createTaskLaunchAnimation( this, RECENTS_LAUNCH_DURATION, TOUCH_RESPONSE_INTERPOLATOR); - AnimatorPlaybackController currentAnimation = - AnimatorPlaybackController.wrap(pendingAnimation, RECENTS_LAUNCH_DURATION); + AnimatorPlaybackController currentAnimation = pendingAnimation.createPlaybackController(); currentAnimation.setEndAction(() -> { pendingAnimation.finish(true, Touch.SWIPE); launchTask(false); diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index 809543ac98..a7d00c5c72 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -52,10 +52,12 @@ import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener; import com.android.quickstep.SystemUiProxy; +import com.android.quickstep.util.RemoteAnimationProvider; import com.android.quickstep.util.RemoteFadeOutAnimationListener; import com.android.quickstep.util.ShelfPeekAnim; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.stream.Stream; @@ -262,17 +264,21 @@ public abstract class BaseQuickstepLauncher extends Launcher public void useFadeOutAnimationForLauncherStart(CancellationSignal signal) { QuickstepAppTransitionManagerImpl appTransitionManager = (QuickstepAppTransitionManagerImpl) getAppTransitionManager(); - appTransitionManager.setRemoteAnimationProvider((appTargets, wallpaperTargets) -> { + appTransitionManager.setRemoteAnimationProvider(new RemoteAnimationProvider() { + @Override + public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets) { - // On the first call clear the reference. - signal.cancel(); + // On the first call clear the reference. + signal.cancel(); - ValueAnimator fadeAnimation = ValueAnimator.ofFloat(1, 0); - fadeAnimation.addUpdateListener(new RemoteFadeOutAnimationListener(appTargets, - wallpaperTargets)); - AnimatorSet anim = new AnimatorSet(); - anim.play(fadeAnimation); - return anim; + ValueAnimator fadeAnimation = ValueAnimator.ofFloat(1, 0); + fadeAnimation.addUpdateListener(new RemoteFadeOutAnimationListener(appTargets, + wallpaperTargets)); + AnimatorSet anim = new AnimatorSet(); + anim.play(fadeAnimation); + return anim; + } }, signal); } diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java index 874adb2b2c..4ff0a72d2e 100644 --- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java +++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java @@ -34,7 +34,8 @@ import com.android.systemui.shared.system.RemoteAnimationRunnerCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; @TargetApi(Build.VERSION_CODES.P) -public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat { +public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat, + WrappedAnimationRunnerImpl { private final Handler mHandler; private final boolean mStartAtFrontOfQueue; @@ -49,6 +50,10 @@ public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCo mStartAtFrontOfQueue = startAtFrontOfQueue; } + public Handler getHandler() { + return mHandler; + } + // Called only in R+ platform @BinderThread public void onAnimationStart(RemoteAnimationTargetCompat[] appTargets, diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java index 96340b22e6..fbd7a8a4b6 100644 --- a/quickstep/src/com/android/launcher3/LauncherInitListener.java +++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java @@ -15,6 +15,7 @@ */ package com.android.launcher3; +import android.animation.AnimatorSet; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; @@ -25,6 +26,7 @@ import android.os.Handler; import com.android.launcher3.util.ActivityTracker; import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.RemoteAnimationProvider; +import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.function.BiPredicate; @@ -51,17 +53,21 @@ public class LauncherInitListener extends ActivityInitListener { // Set a one-time animation provider. After the first call, this will get cleared. // TODO: Probably also check the intended target id. CancellationSignal cancellationSignal = new CancellationSignal(); - appTransitionManager.setRemoteAnimationProvider((appTargets, wallpaperTargets) -> { + appTransitionManager.setRemoteAnimationProvider(new RemoteAnimationProvider() { + @Override + public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets) { - // On the first call clear the reference. - cancellationSignal.cancel(); - RemoteAnimationProvider provider = mRemoteAnimationProvider; - mRemoteAnimationProvider = null; + // On the first call clear the reference. + cancellationSignal.cancel(); + RemoteAnimationProvider provider = mRemoteAnimationProvider; + mRemoteAnimationProvider = null; - if (provider != null && launcher.getStateManager().getState().overviewUi) { - return provider.createWindowAnimation(appTargets, wallpaperTargets); + if (provider != null && launcher.getStateManager().getState().overviewUi) { + return provider.createWindowAnimation(appTargets, wallpaperTargets); + } + return null; } - return null; }, cancellationSignal); } launcher.deferOverlayCallbacksUntilNextResumeOrStop(); diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java index f69135937d..b9bd6b1d54 100644 --- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java @@ -49,6 +49,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Matrix; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; @@ -86,8 +87,6 @@ import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; import com.android.systemui.shared.system.WindowManagerWrapper; -import java.lang.ref.WeakReference; - /** * {@link LauncherAppTransitionManager} with Quickstep-specific app transitions for launching from * home and/or all-apps. Not used for 3p launchers. @@ -299,8 +298,12 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans if (mLauncher.isInMultiWindowMode()) { for (RemoteAnimationTargetCompat target : appTargets) { if (target.mode == MODE_OPENING) { - bounds.set(target.sourceContainerBounds); - bounds.offsetTo(target.position.x, target.position.y); + bounds.set(target.screenSpaceBounds); + if (target.localBounds != null) { + bounds.set(target.localBounds); + } else { + bounds.offsetTo(target.position.x, target.position.y); + } return bounds; } } @@ -460,6 +463,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans RectF targetBounds = new RectF(windowTargetBounds); RectF currentBounds = new RectF(); RectF temp = new RectF(); + Point tmpPos = new Point(); AnimatorSet animatorSet = new AnimatorSet(); ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1); @@ -547,6 +551,13 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans for (int i = appTargets.length - 1; i >= 0; i--) { RemoteAnimationTargetCompat target = appTargets[i]; SurfaceParams.Builder builder = new SurfaceParams.Builder(target.leash); + + tmpPos.set(target.position.x, target.position.y); + if (target.localBounds != null) { + final Rect localBounds = target.localBounds; + tmpPos.set(target.localBounds.left, target.localBounds.top); + } + if (target.mode == MODE_OPENING) { matrix.setScale(scale, scale); matrix.postTranslate(transX0, transY0); @@ -563,9 +574,9 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans .withAlpha(1f - mIconAlpha.value) .withCornerRadius(mWindowRadius.value); } else { - matrix.setTranslate(target.position.x, target.position.y); + matrix.setTranslate(tmpPos.x, tmpPos.y); builder.withMatrix(matrix) - .withWindowCrop(target.sourceContainerBounds) + .withWindowCrop(target.screenSpaceBounds) .withAlpha(1f); } builder.withLayer(RemoteAnimationProvider.getLayer(target, MODE_OPENING)); @@ -662,7 +673,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans RemoteAnimationTargetCompat target = appTargets[i]; params[i] = new SurfaceParams.Builder(target.leash) .withAlpha(1f) - .withWindowCrop(target.sourceContainerBounds) + .withWindowCrop(target.screenSpaceBounds) .withLayer(RemoteAnimationProvider.getLayer(target, MODE_OPENING)) .withCornerRadius(cornerRadius) .build(); @@ -681,6 +692,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans SyncRtSurfaceTransactionApplierCompat surfaceApplier = new SyncRtSurfaceTransactionApplierCompat(mDragLayer); Matrix matrix = new Matrix(); + Point tmpPos = new Point(); ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1); int duration = CLOSING_TRANSITION_DURATION_MS; float windowCornerRadius = mDeviceProfile.isMultiWindowMode @@ -697,22 +709,28 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans for (int i = appTargets.length - 1; i >= 0; i--) { RemoteAnimationTargetCompat target = appTargets[i]; SurfaceParams.Builder builder = new SurfaceParams.Builder(target.leash); + + tmpPos.set(target.position.x, target.position.y); + if (target.localBounds != null) { + tmpPos.set(target.localBounds.left, target.localBounds.top); + } + if (target.mode == MODE_CLOSING) { matrix.setScale(mScale.value, mScale.value, - target.sourceContainerBounds.centerX(), - target.sourceContainerBounds.centerY()); + target.screenSpaceBounds.centerX(), + target.screenSpaceBounds.centerY()); matrix.postTranslate(0, mDy.value); - matrix.postTranslate(target.position.x, target.position.y); + matrix.postTranslate(tmpPos.x, tmpPos.y); builder.withMatrix(matrix) .withAlpha(mAlpha.value) .withCornerRadius(windowCornerRadius); } else { - matrix.setTranslate(target.position.x, target.position.y); + matrix.setTranslate(tmpPos.x, tmpPos.y); builder.withMatrix(matrix) .withAlpha(1f); } params[i] = builder - .withWindowCrop(target.sourceContainerBounds) + .withWindowCrop(target.screenSpaceBounds) .withLayer(RemoteAnimationProvider.getLayer(target, MODE_CLOSING)) .build(); } @@ -784,52 +802,6 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans == PackageManager.PERMISSION_GRANTED; } - /** - * Used with WrappedLauncherAnimationRunner as an interface for the runner to call back to the - * implementation. - */ - protected interface WrappedAnimationRunnerImpl { - Handler getHandler(); - void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, - LauncherAnimationRunner.AnimationResult result); - } - - /** - * This class is needed to wrap any animation runner that is a part of the - * RemoteAnimationDefinition: - * - Launcher creates a new instance of the LauncherAppTransitionManagerImpl whenever it is - * created, which in turn registers a new definition - * - When the definition is registered, window manager retains a strong binder reference to the - * runner passed in - * - If the Launcher activity is recreated, the new definition registered will replace the old - * reference in the system's activity record, but until the system server is GC'd, the binder - * reference will still exist, which references the runner in the Launcher process, which - * references the (old) Launcher activity through this class - * - * Instead we make the runner provided to the definition static only holding a weak reference to - * the runner implementation. When this animation manager is destroyed, we remove the Launcher - * reference to the runner, leaving only the weak ref from the runner. - */ - protected static class WrappedLauncherAnimationRunner - extends LauncherAnimationRunner { - private WeakReference mImpl; - - public WrappedLauncherAnimationRunner(R animationRunnerImpl, boolean startAtFrontOfQueue) { - super(animationRunnerImpl.getHandler(), startAtFrontOfQueue); - mImpl = new WeakReference<>(animationRunnerImpl); - } - - @Override - public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, AnimationResult result) { - R animationRunnerImpl = mImpl.get(); - if (animationRunnerImpl != null) { - animationRunnerImpl.onCreateAnimation(appTargets, wallpaperTargets, result); - } - } - } - /** * Remote animation runner for animation from the app to Launcher, including recents. */ diff --git a/quickstep/src/com/android/launcher3/WrappedAnimationRunnerImpl.java b/quickstep/src/com/android/launcher3/WrappedAnimationRunnerImpl.java new file mode 100644 index 0000000000..da2aee4386 --- /dev/null +++ b/quickstep/src/com/android/launcher3/WrappedAnimationRunnerImpl.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 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; + +import android.os.Handler; + +import com.android.systemui.shared.system.RemoteAnimationTargetCompat; + +/** + * Used with WrappedLauncherAnimationRunner as an interface for the runner to call back to the + * implementation. + */ +public interface WrappedAnimationRunnerImpl { + Handler getHandler(); + void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets, + LauncherAnimationRunner.AnimationResult result); +} diff --git a/quickstep/src/com/android/launcher3/WrappedLauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/WrappedLauncherAnimationRunner.java new file mode 100644 index 0000000000..1753b62ca3 --- /dev/null +++ b/quickstep/src/com/android/launcher3/WrappedLauncherAnimationRunner.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2020 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; + +import com.android.systemui.shared.system.RemoteAnimationTargetCompat; + +import java.lang.ref.WeakReference; + +/** + * This class is needed to wrap any animation runner that is a part of the + * RemoteAnimationDefinition: + * - Launcher creates a new instance of the LauncherAppTransitionManagerImpl whenever it is + * created, which in turn registers a new definition + * - When the definition is registered, window manager retains a strong binder reference to the + * runner passed in + * - If the Launcher activity is recreated, the new definition registered will replace the old + * reference in the system's activity record, but until the system server is GC'd, the binder + * reference will still exist, which references the runner in the Launcher process, which + * references the (old) Launcher activity through this class + * + * Instead we make the runner provided to the definition static only holding a weak reference to + * the runner implementation. When this animation manager is destroyed, we remove the Launcher + * reference to the runner, leaving only the weak ref from the runner. + */ +public class WrappedLauncherAnimationRunner + extends LauncherAnimationRunner { + private WeakReference mImpl; + + public WrappedLauncherAnimationRunner(R animationRunnerImpl, boolean startAtFrontOfQueue) { + super(animationRunnerImpl.getHandler(), startAtFrontOfQueue); + mImpl = new WeakReference<>(animationRunnerImpl); + } + + @Override + public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets, AnimationResult result) { + R animationRunnerImpl = mImpl.get(); + if (animationRunnerImpl != null) { + animationRunnerImpl.onCreateAnimation(appTargets, wallpaperTargets, result); + } + } +} diff --git a/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java b/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java index 671aab00d9..e82a50455b 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java +++ b/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java @@ -16,19 +16,23 @@ package com.android.launcher3.uioverrides; -import android.animation.ValueAnimator; +import static com.android.launcher3.anim.Interpolators.LINEAR; +import static com.android.quickstep.AnimatedFloat.VALUE; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager; -import com.android.launcher3.anim.AnimatorSetBuilder; +import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.util.UiThreadHelper; +import com.android.quickstep.AnimatedFloat; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SystemUiProxy; public class BackButtonAlphaHandler implements LauncherStateManager.StateHandler { private final BaseQuickstepLauncher mLauncher; + private final AnimatedFloat mBackAlpha = new AnimatedFloat(this::updateBackAlpha); public BackButtonAlphaHandler(BaseQuickstepLauncher launcher) { mLauncher = launcher; @@ -38,8 +42,8 @@ public class BackButtonAlphaHandler implements LauncherStateManager.StateHandler public void setState(LauncherState state) { } @Override - public void setStateWithAnimation(LauncherState toState, - AnimatorSetBuilder builder, LauncherStateManager.AnimationConfig config) { + public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config, + PendingAnimation animation) { if (config.onlyPlayAtomicComponent()) { return; } @@ -51,17 +55,12 @@ public class BackButtonAlphaHandler implements LauncherStateManager.StateHandler return; } - float fromAlpha = SystemUiProxy.INSTANCE.get(mLauncher).getLastBackButtonAlpha(); - float toAlpha = toState.hideBackButton ? 0 : 1; - if (Float.compare(fromAlpha, toAlpha) != 0) { - ValueAnimator anim = ValueAnimator.ofFloat(fromAlpha, toAlpha); - anim.setDuration(config.duration); - anim.addUpdateListener(valueAnimator -> { - final float alpha = (float) valueAnimator.getAnimatedValue(); - UiThreadHelper.setBackButtonAlphaAsync(mLauncher, - BaseQuickstepLauncher.SET_BACK_BUTTON_ALPHA, alpha, false /* animate */); - }); - builder.play(anim); - } + mBackAlpha.value = SystemUiProxy.INSTANCE.get(mLauncher).getLastBackButtonAlpha(); + animation.setFloat(mBackAlpha, VALUE, toState.hideBackButton ? 0 : 1, LINEAR); + } + + private void updateBackAlpha() { + UiThreadHelper.setBackButtonAlphaAsync(mLauncher, + BaseQuickstepLauncher.SET_BACK_BUTTON_ALPHA, mBackAlpha.value, false /* animate */); } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/BackgroundBlurController.java b/quickstep/src/com/android/launcher3/uioverrides/BackgroundBlurController.java index 022a5f7f8a..513310e945 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/BackgroundBlurController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/BackgroundBlurController.java @@ -26,8 +26,8 @@ import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.anim.AnimatorSetBuilder; -import com.android.launcher3.anim.PropertySetter; +import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.states.StateAnimationConfig; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.SurfaceControlCompat; import com.android.systemui.shared.system.TransactionCompat; @@ -133,16 +133,15 @@ public class BackgroundBlurController implements LauncherStateManager.StateHandl } @Override - public void setStateWithAnimation(LauncherState toState, AnimatorSetBuilder builder, - LauncherStateManager.AnimationConfig config) { + public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config, + PendingAnimation animation) { if (mSurface == null || config.onlyPlayAtomicComponent()) { return; } int toBackgroundBlurRadius = toState.getBackgroundBlurRadius(mLauncher); if (mBackgroundBlurRadius != toBackgroundBlurRadius) { - PropertySetter propertySetter = config.getPropertySetter(builder); - propertySetter.setInt(this, BACKGROUND_BLUR, toBackgroundBlurRadius, LINEAR); + animation.setInt(this, BACKGROUND_BLUR, toBackgroundBlurRadius, LINEAR); } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java index 94e67f06c7..03454f77f8 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java @@ -20,17 +20,17 @@ import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA; import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X; import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y; -import static com.android.launcher3.LauncherStateManager.PLAY_ATOMIC_OVERVIEW_PEEK; -import static com.android.launcher3.LauncherStateManager.PLAY_ATOMIC_OVERVIEW_SCALE; -import static com.android.launcher3.LauncherStateManager.SKIP_OVERVIEW; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCRIM_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_Y; import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.graphics.Scrim.SCRIM_PROGRESS; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCRIM_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y; +import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK; +import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE; +import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW; import android.util.FloatProperty; import android.view.View; @@ -41,11 +41,10 @@ import androidx.annotation.NonNull; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherState.ScaleAndTranslation; -import com.android.launcher3.LauncherStateManager.AnimationConfig; import com.android.launcher3.LauncherStateManager.StateHandler; -import com.android.launcher3.anim.AnimatorSetBuilder; -import com.android.launcher3.anim.PropertySetter; +import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.graphics.OverviewScrim; +import com.android.launcher3.states.StateAnimationConfig; /** * State handler for recents view. Manages UI changes and animations for recents view based off the @@ -86,8 +85,8 @@ public abstract class BaseRecentsViewStateController } @Override - public final void setStateWithAnimation(@NonNull final LauncherState toState, - @NonNull AnimatorSetBuilder builder, @NonNull AnimationConfig config) { + public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config, + PendingAnimation builder) { if (!config.hasAnimationFlag(PLAY_ATOMIC_OVERVIEW_PEEK | PLAY_ATOMIC_OVERVIEW_SCALE)) { // The entire recents animation is played atomically. return; @@ -95,25 +94,24 @@ public abstract class BaseRecentsViewStateController if (config.hasAnimationFlag(SKIP_OVERVIEW)) { return; } - setStateWithAnimationInternal(toState, builder, config); + setStateWithAnimationInternal(toState, config, builder); } /** * Core logic for animating the recents view UI. * * @param toState state to animate to - * @param builder animator set builder * @param config current animation config + * @param setter animator set builder */ void setStateWithAnimationInternal(@NonNull final LauncherState toState, - @NonNull AnimatorSetBuilder builder, @NonNull AnimationConfig config) { - PropertySetter setter = config.getPropertySetter(builder); + @NonNull StateAnimationConfig config, @NonNull PendingAnimation setter) { ScaleAndTranslation scaleAndTranslation = toState.getOverviewScaleAndTranslation(mLauncher); - Interpolator scaleInterpolator = builder.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR); + Interpolator scaleInterpolator = config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR); setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleAndTranslation.scale, scaleInterpolator); - Interpolator translateXInterpolator = builder.getInterpolator( + Interpolator translateXInterpolator = config.getInterpolator( ANIM_OVERVIEW_TRANSLATE_X, LINEAR); - Interpolator translateYInterpolator = builder.getInterpolator( + Interpolator translateYInterpolator = config.getInterpolator( ANIM_OVERVIEW_TRANSLATE_Y, LINEAR); float translationX = scaleAndTranslation.translationX; if (mRecentsView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) { @@ -123,14 +121,14 @@ public abstract class BaseRecentsViewStateController setter.setFloat(mRecentsView, VIEW_TRANSLATE_Y, scaleAndTranslation.translationY, translateYInterpolator); setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0, - builder.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT)); + config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT)); OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim(); setter.setFloat(scrim, SCRIM_PROGRESS, toState.getOverviewScrimAlpha(mLauncher), - builder.getInterpolator(ANIM_OVERVIEW_SCRIM_FADE, LINEAR)); + config.getInterpolator(ANIM_OVERVIEW_SCRIM_FADE, LINEAR)); if (mActionsView != null) { setter.setFloat(mActionsView, VIEW_TRANSLATE_X, translationX, translateXInterpolator); setter.setFloat(mActionsView, VIEW_ALPHA, toState.overviewUi ? 1 : 0, - builder.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT)); + config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT)); } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/PreviewSurfaceRenderer.java b/quickstep/src/com/android/launcher3/uioverrides/PreviewSurfaceRenderer.java new file mode 100644 index 0000000000..548223a8fe --- /dev/null +++ b/quickstep/src/com/android/launcher3/uioverrides/PreviewSurfaceRenderer.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 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.uioverrides; + +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; + +import android.content.Context; +import android.os.Bundle; +import android.util.Size; +import android.view.View; + +import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.graphics.LauncherPreviewRenderer; +import com.android.systemui.shared.system.SurfaceViewRequestReceiver; + +/** Render preview using surface view. */ +public class PreviewSurfaceRenderer { + + /** Handle a received surface view request. */ + public static void render(Context context, Bundle bundle) { + final String gridName = bundle.getString("name"); + bundle.remove("name"); + final InvariantDeviceProfile idp = new InvariantDeviceProfile(context, gridName); + + MAIN_EXECUTOR.execute(() -> { + View view = new LauncherPreviewRenderer(context, idp).getRenderedView(); + new SurfaceViewRequestReceiver().onReceive(context, bundle, view, + new Size(view.getMeasuredWidth(), view.getMeasuredHeight())); + }); + } +} diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java index 3d0fc561d1..bef191ef8f 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java @@ -9,7 +9,7 @@ import android.view.MotionEvent; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; -import com.android.launcher3.LauncherStateManager.AnimationFlags; +import com.android.launcher3.states.StateAnimationConfig.AnimationFlags; import com.android.launcher3.touch.AbstractStateChangeTouchController; import com.android.launcher3.touch.SingleAxisSwipeDetector; import com.android.launcher3.userevent.nano.LauncherLogProto; diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java index a060d64620..cc3fd97b49 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java @@ -19,13 +19,13 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_ACCESSIBLE; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS; import static com.android.launcher3.anim.Interpolators.ACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; import android.animation.TimeInterpolator; @@ -37,11 +37,10 @@ import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; -import com.android.launcher3.LauncherStateManager.AnimationFlags; import com.android.launcher3.allapps.AllAppsTransitionController; -import com.android.launcher3.anim.AnimatorPlaybackController; -import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.states.StateAnimationConfig; +import com.android.launcher3.states.StateAnimationConfig.AnimationFlags; import com.android.launcher3.touch.AbstractStateChangeTouchController; import com.android.launcher3.touch.SingleAxisSwipeDetector; import com.android.launcher3.uioverrides.states.OverviewState; @@ -148,16 +147,16 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr return isTouchOverHotseat(mLauncher, ev) ? ContainerType.HOTSEAT : ContainerType.WORKSPACE; } - private AnimatorSetBuilder getNormalToOverviewAnimation() { + private StateAnimationConfig getNormalToOverviewAnimation() { mAllAppsInterpolatorWrapper.baseInterpolator = LINEAR; - AnimatorSetBuilder builder = new AnimatorSetBuilder(); + StateAnimationConfig builder = new StateAnimationConfig(); builder.setInterpolator(ANIM_VERTICAL_PROGRESS, mAllAppsInterpolatorWrapper); return builder; } - public static AnimatorSetBuilder getOverviewToAllAppsAnimation() { - AnimatorSetBuilder builder = new AnimatorSetBuilder(); + private static StateAnimationConfig getOverviewToAllAppsAnimation() { + StateAnimationConfig builder = new StateAnimationConfig(); builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(ACCEL, 0, ALL_APPS_CONTENT_FADE_THRESHOLD)); builder.setInterpolator(ANIM_OVERVIEW_FADE, Interpolators.clampToProgress(DEACCEL, @@ -165,8 +164,8 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr return builder; } - private AnimatorSetBuilder getAllAppsToOverviewAnimation() { - AnimatorSetBuilder builder = new AnimatorSetBuilder(); + private StateAnimationConfig getAllAppsToOverviewAnimation() { + StateAnimationConfig builder = new StateAnimationConfig(); builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(DEACCEL, 1 - ALL_APPS_CONTENT_FADE_THRESHOLD, 1)); builder.setInterpolator(ANIM_OVERVIEW_FADE, Interpolators.clampToProgress(ACCEL, @@ -174,41 +173,42 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr return builder; } - private AnimatorSetBuilder getNormalToAllAppsAnimation() { - AnimatorSetBuilder builder = new AnimatorSetBuilder(); + private StateAnimationConfig getNormalToAllAppsAnimation() { + StateAnimationConfig builder = new StateAnimationConfig(); builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(ACCEL, 0, ALL_APPS_CONTENT_FADE_THRESHOLD)); return builder; } - private AnimatorSetBuilder getAllAppsToNormalAnimation() { - AnimatorSetBuilder builder = new AnimatorSetBuilder(); + private StateAnimationConfig getAllAppsToNormalAnimation() { + StateAnimationConfig builder = new StateAnimationConfig(); builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(DEACCEL, 1 - ALL_APPS_CONTENT_FADE_THRESHOLD, 1)); return builder; } @Override - protected AnimatorSetBuilder getAnimatorSetBuilderForStates(LauncherState fromState, - LauncherState toState) { - AnimatorSetBuilder builder = new AnimatorSetBuilder(); + protected StateAnimationConfig getConfigForStates( + LauncherState fromState, LauncherState toState) { + final StateAnimationConfig config; if (fromState == NORMAL && toState == OVERVIEW) { - builder = getNormalToOverviewAnimation(); + config = getNormalToOverviewAnimation(); } else if (fromState == OVERVIEW && toState == ALL_APPS) { - builder = getOverviewToAllAppsAnimation(); + config = getOverviewToAllAppsAnimation(); } else if (fromState == ALL_APPS && toState == OVERVIEW) { - builder = getAllAppsToOverviewAnimation(); + config = getAllAppsToOverviewAnimation(); } else if (fromState == NORMAL && toState == ALL_APPS) { - builder = getNormalToAllAppsAnimation(); + config = getNormalToAllAppsAnimation(); } else if (fromState == ALL_APPS && toState == NORMAL) { - builder = getAllAppsToNormalAnimation(); + config = getAllAppsToNormalAnimation(); + } else { + config = new StateAnimationConfig(); } - return builder; + return config; } @Override - protected float initCurrentAnimation(@AnimationFlags int animComponents) { - animComponents = updateAnimComponentsOnReinit(animComponents); + protected float initCurrentAnimation(@AnimationFlags int animFlags) { float range = getShiftRange(); long maxAccuracy = (long) (2 * range); @@ -217,8 +217,10 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr float totalShift = endVerticalShift - startVerticalShift; - final AnimatorSetBuilder builder = totalShift == 0 ? new AnimatorSetBuilder() - : getAnimatorSetBuilderForStates(mFromState, mToState); + final StateAnimationConfig config = totalShift == 0 ? new StateAnimationConfig() + : getConfigForStates(mFromState, mToState); + config.animFlags = updateAnimComponentsOnReinit(animFlags); + config.duration = maxAccuracy; cancelPendingAnim(); @@ -232,15 +234,15 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr cancelPendingAnim(); clearState(); }; - mCurrentAnimation = AnimatorPlaybackController.wrap(mPendingAnimation, maxAccuracy) + mCurrentAnimation = mPendingAnimation.createPlaybackController() .setOnCancelRunnable(onCancelRunnable); mLauncher.getStateManager().setCurrentUserControlledAnimation(mCurrentAnimation); totalShift = LayoutUtils.getShelfTrackingDistance(mLauncher, mLauncher.getDeviceProfile()); } else { mCurrentAnimation = mLauncher.getStateManager() - .createAnimationToNewWorkspace(mToState, builder, maxAccuracy, this::clearState, - animComponents); + .createAnimationToNewWorkspace(mToState, config) + .setOnCancelRunnable(this::clearState); } if (totalShift == 0) { diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java index 6520c4f091..21b97ecc7f 100644 --- a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java +++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java @@ -21,21 +21,22 @@ import android.content.Context; import android.os.Handler; import com.android.launcher3.LauncherAnimationRunner; +import com.android.launcher3.WrappedLauncherAnimationRunner; import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.RemoteAnimationAdapterCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.TransactionCompat; -@FunctionalInterface -public interface RemoteAnimationProvider { +public abstract class RemoteAnimationProvider { + LauncherAnimationRunner mAnimationRunner; static final int Z_BOOST_BASE = 800570000; - AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, + public abstract AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, RemoteAnimationTargetCompat[] wallpaperTargets); - default ActivityOptions toActivityOptions(Handler handler, long duration, Context context) { - LauncherAnimationRunner runner = new LauncherAnimationRunner(handler, + ActivityOptions toActivityOptions(Handler handler, long duration, Context context) { + mAnimationRunner = new LauncherAnimationRunner(handler, false /* startAtFrontOfQueue */) { @Override @@ -44,8 +45,11 @@ public interface RemoteAnimationProvider { result.setAnimation(createWindowAnimation(appTargets, wallpaperTargets), context); } }; + final LauncherAnimationRunner wrapper = new WrappedLauncherAnimationRunner( + mAnimationRunner, false /* startAtFrontOfQueue */); + return ActivityOptionsCompat.makeRemoteAnimation( - new RemoteAnimationAdapterCompat(runner, duration, 0)); + new RemoteAnimationAdapterCompat(wrapper, duration, 0)); } /** @@ -63,7 +67,7 @@ public interface RemoteAnimationProvider { } } - static int getLayer(RemoteAnimationTargetCompat target, int boostModeTarget) { + public static int getLayer(RemoteAnimationTargetCompat target, int boostModeTarget) { return target.mode == boostModeTarget ? Z_BOOST_BASE + target.prefixOrderIndex : target.prefixOrderIndex; @@ -72,7 +76,7 @@ public interface RemoteAnimationProvider { /** * @return the target with the lowest opaque layer for a certain app animation, or null. */ - static RemoteAnimationTargetCompat findLowestOpaqueLayerTarget( + public static RemoteAnimationTargetCompat findLowestOpaqueLayerTarget( RemoteAnimationTargetCompat[] appTargets, int mode) { int lowestLayer = Integer.MAX_VALUE; int lowestLayerIndex = -1; diff --git a/res/values/strings.xml b/res/values/strings.xml index 9d0fb56a9e..7748b3a400 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -208,7 +208,7 @@ Show notification dots - Add icon to Home screen + Add app icons to Home screen For new apps diff --git a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java new file mode 100644 index 0000000000..8f58d8b507 --- /dev/null +++ b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2020 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.model; + +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT; +import static com.android.launcher3.LauncherSettings.Favorites.TMP_CONTENT_URI; +import static com.android.launcher3.provider.LauncherDbUtils.dropTable; +import static com.android.launcher3.util.LauncherModelHelper.APP_ICON; +import static com.android.launcher3.util.LauncherModelHelper.DESKTOP; +import static com.android.launcher3.util.LauncherModelHelper.HOTSEAT; +import static com.android.launcher3.util.LauncherModelHelper.SHORTCUT; +import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.graphics.Point; +import android.os.Process; + +import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.pm.UserCache; +import com.android.launcher3.util.LauncherModelHelper; +import com.android.launcher3.util.LauncherRoboTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; + +import java.util.HashSet; + +/** Unit tests for {@link GridSizeMigrationTaskV2} */ +@RunWith(LauncherRoboTestRunner.class) +public class GridSizeMigrationTaskV2Test { + + private LauncherModelHelper mModelHelper; + private Context mContext; + private SQLiteDatabase mDb; + + private HashSet mValidPackages; + private InvariantDeviceProfile mIdp; + + @Before + public void setUp() { + mModelHelper = new LauncherModelHelper(); + mContext = RuntimeEnvironment.application; + mDb = mModelHelper.provider.getDb(); + + mValidPackages = new HashSet<>(); + mValidPackages.add(TEST_PACKAGE); + mIdp = InvariantDeviceProfile.INSTANCE.get(mContext); + + long userSerial = UserCache.INSTANCE.get(mContext).getSerialNumberForUser( + Process.myUserHandle()); + dropTable(mDb, LauncherSettings.Favorites.TMP_TABLE); + LauncherSettings.Favorites.addTableToDb(mDb, userSerial, false, + LauncherSettings.Favorites.TMP_TABLE); + } + + @Test + public void testMigration() { + final String testPackage1 = "com.android.launcher3.validpackage1"; + final String testPackage2 = "com.android.launcher3.validpackage2"; + final String testPackage3 = "com.android.launcher3.validpackage3"; + final String testPackage4 = "com.android.launcher3.validpackage4"; + final String testPackage5 = "com.android.launcher3.validpackage5"; + final String testPackage7 = "com.android.launcher3.validpackage7"; + + mValidPackages.add(testPackage1); + mValidPackages.add(testPackage2); + mValidPackages.add(testPackage3); + mValidPackages.add(testPackage4); + mValidPackages.add(testPackage5); + mValidPackages.add(testPackage7); + + int[] srcHotseatItems = { + mModelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI), + mModelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI), + -1, + mModelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI), + mModelHelper.addItem(APP_ICON, 4, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI), + }; + mModelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage5, 5, TMP_CONTENT_URI); + + int[] destHotseatItems = { + -1, + mModelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2), + -1, + }; + mModelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage7); + + mIdp.numHotseatIcons = 3; + mIdp.numColumns = 3; + mIdp.numRows = 3; + GridSizeMigrationTaskV2.DbReader srcReader = new GridSizeMigrationTaskV2.DbReader(mDb, + LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages, 5); + GridSizeMigrationTaskV2.DbReader destReader = new GridSizeMigrationTaskV2.DbReader(mDb, + LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages, 3); + GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader, + destReader, 3, new Point(mIdp.numColumns, mIdp.numRows)); + task.migrate(); + + Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI, + new String[]{LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.INTENT}, + "container=" + CONTAINER_HOTSEAT, null, null, null); + assertEquals(c.getCount(), 3); + int screenIndex = c.getColumnIndex(LauncherSettings.Favorites.SCREEN); + int intentIndex = c.getColumnIndex(LauncherSettings.Favorites.INTENT); + c.moveToNext(); + assertEquals(c.getInt(screenIndex), 1); + assertTrue(c.getString(intentIndex).contains(testPackage2)); + c.moveToNext(); + assertEquals(c.getInt(screenIndex), 0); + assertTrue(c.getString(intentIndex).contains(testPackage1)); + c.moveToNext(); + assertEquals(c.getInt(screenIndex), 2); + assertTrue(c.getString(intentIndex).contains(testPackage3)); + c.close(); + + c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI, + new String[]{LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY, + LauncherSettings.Favorites.INTENT}, + "container=" + CONTAINER_DESKTOP, null, null, null); + assertEquals(c.getCount(), 2); + intentIndex = c.getColumnIndex(LauncherSettings.Favorites.INTENT); + int cellXIndex = c.getColumnIndex(LauncherSettings.Favorites.CELLX); + int cellYIndex = c.getColumnIndex(LauncherSettings.Favorites.CELLY); + + c.moveToNext(); + assertTrue(c.getString(intentIndex).contains(testPackage7)); + c.moveToNext(); + assertTrue(c.getString(intentIndex).contains(testPackage5)); + assertEquals(c.getInt(cellXIndex), 0); + assertEquals(c.getInt(cellYIndex), 2); + } +} diff --git a/robolectric_tests/src/com/android/launcher3/util/LauncherModelHelper.java b/robolectric_tests/src/com/android/launcher3/util/LauncherModelHelper.java index e133cf2778..20b1453b6f 100644 --- a/robolectric_tests/src/com/android/launcher3/util/LauncherModelHelper.java +++ b/robolectric_tests/src/com/android/launcher3/util/LauncherModelHelper.java @@ -230,7 +230,21 @@ public class LauncherModelHelper { } public int addItem(int type, int screen, int container, int x, int y) { - return addItem(type, screen, container, x, y, mDefaultProfileId); + return addItem(type, screen, container, x, y, mDefaultProfileId, TEST_PACKAGE); + } + + public int addItem(int type, int screen, int container, int x, int y, long profileId) { + return addItem(type, screen, container, x, y, profileId, TEST_PACKAGE); + } + + public int addItem(int type, int screen, int container, int x, int y, String packageName) { + return addItem(type, screen, container, x, y, mDefaultProfileId, packageName); + } + + public int addItem(int type, int screen, int container, int x, int y, String packageName, + int id, Uri contentUri) { + addItem(type, screen, container, x, y, mDefaultProfileId, packageName, id, contentUri); + return id; } /** @@ -238,11 +252,19 @@ public class LauncherModelHelper { * @param type {@link #APP_ICON} or {@link #SHORTCUT} or >= 2 for * folder (where the type represents the number of items in the folder). */ - public int addItem(int type, int screen, int container, int x, int y, long profileId) { + public int addItem(int type, int screen, int container, int x, int y, long profileId, + String packageName) { Context context = RuntimeEnvironment.application; int id = LauncherSettings.Settings.call(context.getContentResolver(), LauncherSettings.Settings.METHOD_NEW_ITEM_ID) .getInt(LauncherSettings.Settings.EXTRA_VALUE); + addItem(type, screen, container, x, y, profileId, packageName, id, CONTENT_URI); + return id; + } + + public void addItem(int type, int screen, int container, int x, int y, long profileId, + String packageName, int id, Uri contentUri) { + Context context = RuntimeEnvironment.application; ContentValues values = new ContentValues(); values.put(LauncherSettings.Favorites._ID, id); @@ -257,7 +279,7 @@ public class LauncherModelHelper { if (type == APP_ICON || type == SHORTCUT) { values.put(LauncherSettings.Favorites.ITEM_TYPE, type); values.put(LauncherSettings.Favorites.INTENT, - new Intent(Intent.ACTION_MAIN).setPackage(TEST_PACKAGE).toUri(0)); + new Intent(Intent.ACTION_MAIN).setPackage(packageName).toUri(0)); } else { values.put(LauncherSettings.Favorites.ITEM_TYPE, LauncherSettings.Favorites.ITEM_TYPE_FOLDER); @@ -267,8 +289,7 @@ public class LauncherModelHelper { } } - context.getContentResolver().insert(CONTENT_URI, values); - return id; + context.getContentResolver().insert(contentUri, values); } public int[][][] createGrid(int[][][] typeArray) { diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java index af2cdc3ed0..12b5fc1afa 100644 --- a/src/com/android/launcher3/AbstractFloatingView.java +++ b/src/com/android/launcher3/AbstractFloatingView.java @@ -22,7 +22,6 @@ import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CH import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled; import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent; -import android.animation.Animator; import android.annotation.SuppressLint; import android.content.Context; import android.util.AttributeSet; @@ -30,11 +29,12 @@ import android.util.Pair; import android.view.MotionEvent; import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; +import android.view.animation.Interpolator; import android.widget.LinearLayout; import androidx.annotation.IntDef; -import androidx.annotation.Nullable; +import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.util.TouchController; @@ -134,9 +134,8 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch * Creates a user-controlled animation to hint that the view will be closed if completed. * @param distanceToMove The max distance that elements should move from their starting point. */ - public @Nullable Animator createHintCloseAnim(float distanceToMove) { - return null; - } + public void addHintCloseAnim( + float distanceToMove, Interpolator interpolator, PendingAnimation target) { } public abstract void logActionCommand(int command); diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index 697048a0da..a699c32848 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -17,6 +17,7 @@ package com.android.launcher3; import static com.android.launcher3.config.FeatureFlags.MULTI_DB_GRID_MIRATION_ALGO; +import static com.android.launcher3.provider.LauncherDbUtils.copyTable; import static com.android.launcher3.provider.LauncherDbUtils.dropTable; import static com.android.launcher3.provider.LauncherDbUtils.tableExists; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; @@ -164,8 +165,11 @@ public class LauncherProvider extends ContentProvider { return false; } - mOpenHelper.close(); + DatabaseHelper oldHelper = mOpenHelper; mOpenHelper = new DatabaseHelper(getContext()); + copyTable(oldHelper.getReadableDatabase(), Favorites.TABLE_NAME, + mOpenHelper.getWritableDatabase(), Favorites.TMP_TABLE, getContext()); + oldHelper.close(); return true; } diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index 216c221dc6..f516446ccb 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -102,6 +102,11 @@ public class LauncherSettings { */ public static final String PREVIEW_TABLE_NAME = "favorites_preview"; + /** + * Temporary table used specifically for multi-db grid migrations + */ + public static final String TMP_TABLE = "favorites_tmp"; + /** * The content:// style URL for "favorites" table */ @@ -114,6 +119,12 @@ public class LauncherSettings { public static final Uri PREVIEW_CONTENT_URI = Uri.parse("content://" + LauncherProvider.AUTHORITY + "/" + PREVIEW_TABLE_NAME); + /** + * The content:// style URL for "favorites_tmp" table + */ + public static final Uri TMP_CONTENT_URI = Uri.parse("content://" + + LauncherProvider.AUTHORITY + "/" + TMP_TABLE); + /** * The content:// style URL for a given row, identified by its id. * diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java index 62b89276ab..df71f16ec7 100644 --- a/src/com/android/launcher3/LauncherState.java +++ b/src/com/android/launcher3/LauncherState.java @@ -20,11 +20,6 @@ import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; import static android.view.View.VISIBLE; import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE; import static com.android.launcher3.anim.Interpolators.ACCEL; import static com.android.launcher3.anim.Interpolators.ACCEL_2; import static com.android.launcher3.anim.Interpolators.DEACCEL; @@ -32,6 +27,11 @@ import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7; import static com.android.launcher3.anim.Interpolators.clampToProgress; import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS; import static com.android.launcher3.states.RotationHelper.REQUEST_NONE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE; import static com.android.launcher3.testing.TestProtocol.ALL_APPS_STATE_ORDINAL; import static com.android.launcher3.testing.TestProtocol.BACKGROUND_APP_STATE_ORDINAL; import static com.android.launcher3.testing.TestProtocol.HINT_STATE_ORDINAL; @@ -46,9 +46,9 @@ import android.view.View; import android.view.animation.Interpolator; import com.android.launcher3.allapps.AllAppsContainerView; -import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.states.HintState; import com.android.launcher3.states.SpringLoadedState; +import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.uioverrides.states.AllAppsState; import com.android.launcher3.uioverrides.states.OverviewState; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; @@ -325,13 +325,13 @@ public abstract class LauncherState { * - Setting some start values (e.g. scale) for views that are hidden but about to be shown. */ public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState, - AnimatorSetBuilder builder) { + StateAnimationConfig config) { if (this == NORMAL && fromState == OVERVIEW) { - builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL); - builder.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL); - builder.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f)); - builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL); - builder.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7); + config.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL); + config.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL); + config.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f)); + config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL); + config.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7); Workspace workspace = launcher.getWorkspace(); // Start from a higher workspace scale, but only if we're invisible so we don't jump. @@ -363,7 +363,7 @@ public abstract class LauncherState { } } else if (this == NORMAL && fromState == OVERVIEW_PEEK) { // Keep fully visible until the very end (when overview is offscreen) to make invisible. - builder.setInterpolator(ANIM_OVERVIEW_FADE, t -> t < 1 ? 0 : 1); + config.setInterpolator(ANIM_OVERVIEW_FADE, t -> t < 1 ? 0 : 1); } } diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java index 04134f29aa..24d0c4136b 100644 --- a/src/com/android/launcher3/LauncherStateManager.java +++ b/src/com/android/launcher3/LauncherStateManager.java @@ -17,26 +17,23 @@ package com.android.launcher3; 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.ANIM_ALL_COMPONENTS; import android.animation.Animator; +import android.animation.Animator.AnimatorListener; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.os.Handler; import android.os.Looper; -import androidx.annotation.IntDef; - import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; -import com.android.launcher3.anim.AnimatorSetBuilder; -import com.android.launcher3.anim.PropertySetter; -import com.android.launcher3.anim.PropertySetter.AnimatedPropertySetter; +import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.compat.AccessibilityManagerCompat; +import com.android.launcher3.states.StateAnimationConfig; +import com.android.launcher3.states.StateAnimationConfig.AnimationFlags; import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; /** @@ -84,28 +81,7 @@ public class LauncherStateManager { public static final String TAG = "StateManager"; - // We separate the state animations into "atomic" and "non-atomic" components. The atomic - // components may be run atomically - that is, all at once, instead of user-controlled. However, - // atomic components are not restricted to this purpose; they can be user-controlled alongside - // non atomic components as well. Note that each gesture model has exactly one atomic component, - // PLAY_ATOMIC_OVERVIEW_SCALE *or* PLAY_ATOMIC_OVERVIEW_PEEK. - @IntDef(flag = true, value = { - PLAY_NON_ATOMIC, - PLAY_ATOMIC_OVERVIEW_SCALE, - PLAY_ATOMIC_OVERVIEW_PEEK, - SKIP_OVERVIEW, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface AnimationFlags {} - public static final int PLAY_NON_ATOMIC = 1 << 0; - public static final int PLAY_ATOMIC_OVERVIEW_SCALE = 1 << 1; - public static final int PLAY_ATOMIC_OVERVIEW_PEEK = 1 << 2; - public static final int SKIP_OVERVIEW = 1 << 3; - - public static final int ANIM_ALL_COMPONENTS = PLAY_NON_ATOMIC | PLAY_ATOMIC_OVERVIEW_SCALE - | PLAY_ATOMIC_OVERVIEW_PEEK; - - private final AnimationConfig mConfig = new AnimationConfig(); + private final AnimationState mConfig = new AnimationState(); private final Handler mUiHandler; private final Launcher mLauncher; private final ArrayList mListeners = new ArrayList<>(); @@ -140,7 +116,7 @@ public class LauncherStateManager { writer.println(prefix + "\tmCurrentStableState:" + mCurrentStableState); writer.println(prefix + "\tmState:" + mState); writer.println(prefix + "\tmRestState:" + mRestState); - writer.println(prefix + "\tisInTransition:" + (mConfig.mCurrentAnimation != null)); + writer.println(prefix + "\tisInTransition:" + (mConfig.currentAnimation != null)); } public StateHandler[] getStateHandlers() { @@ -171,7 +147,7 @@ public class LauncherStateManager { */ public boolean isInStableState(LauncherState state) { return mState == state && mCurrentStableState == state - && (mConfig.mTargetState == null || mConfig.mTargetState == state); + && (mConfig.targetState == null || mConfig.targetState == state); } /** @@ -218,12 +194,12 @@ public class LauncherStateManager { } public void reapplyState(boolean cancelCurrentAnimation) { - boolean wasInAnimation = mConfig.mCurrentAnimation != null; + boolean wasInAnimation = mConfig.currentAnimation != null; if (cancelCurrentAnimation) { cancelAllStateElementAnimation(); cancelAnimation(); } - if (mConfig.mCurrentAnimation == null) { + if (mConfig.currentAnimation == null) { for (StateHandler handler : getStateHandlers()) { handler.setState(mState); } @@ -237,16 +213,16 @@ public class LauncherStateManager { final Runnable onCompleteRunnable) { animated &= Utilities.areAnimationsEnabled(mLauncher); if (mLauncher.isInState(state)) { - if (mConfig.mCurrentAnimation == null) { + if (mConfig.currentAnimation == null) { // Run any queued runnable if (onCompleteRunnable != null) { onCompleteRunnable.run(); } return; - } else if (!mConfig.userControlled && animated && mConfig.mTargetState == state) { + } else if (!mConfig.userControlled && animated && mConfig.targetState == state) { // We are running the same animation as requested if (onCompleteRunnable != null) { - mConfig.mCurrentAnimation.addListener( + mConfig.currentAnimation.addListener( AnimationSuccessListener.forRunnable(onCompleteRunnable)); } return; @@ -276,9 +252,9 @@ public class LauncherStateManager { if (delay > 0) { // Create the animation after the delay as some properties can change between preparing // the animation and running the animation. - int startChangeId = mConfig.mChangeId; + int startChangeId = mConfig.changeId; mUiHandler.postDelayed(() -> { - if (mConfig.mChangeId == startChangeId) { + if (mConfig.changeId == startChangeId) { goToStateAnimated(state, fromState, onCompleteRunnable); } }, delay); @@ -294,11 +270,11 @@ public class LauncherStateManager { mConfig.duration = state == NORMAL ? fromState.getTransitionDuration(mLauncher) : state.getTransitionDuration(mLauncher); - - AnimatorSetBuilder builder = new AnimatorSetBuilder(); - prepareForAtomicAnimation(fromState, state, builder); - AnimatorSet animation = createAnimationToNewWorkspaceInternal( - state, builder, onCompleteRunnable); + prepareForAtomicAnimation(fromState, state, mConfig); + AnimatorSet animation = createAnimationToNewWorkspaceInternal(state).getAnim(); + if (onCompleteRunnable != null) { + animation.addListener(AnimationSuccessListener.forRunnable(onCompleteRunnable)); + } mUiHandler.post(new StartAnimRunnable(animation)); } @@ -308,44 +284,22 @@ public class LauncherStateManager { * - Setting some start values (e.g. scale) for views that are hidden but about to be shown. */ public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toState, - AnimatorSetBuilder builder) { - toState.prepareForAtomicAnimation(mLauncher, fromState, builder); - } - - public AnimatorSet createAtomicAnimation(LauncherState fromState, LauncherState toState, - AnimatorSetBuilder builder, @AnimationFlags int animFlags, long duration) { - prepareForAtomicAnimation(fromState, toState, builder); - AnimationConfig config = new AnimationConfig(); - config.mAnimFlags = animFlags; - config.duration = duration; - for (StateHandler handler : mLauncher.getStateManager().getStateHandlers()) { - handler.setStateWithAnimation(toState, builder, config); - } - return builder.build(); + StateAnimationConfig config) { + toState.prepareForAtomicAnimation(mLauncher, fromState, config); } /** - * Creates a {@link AnimatorPlaybackController} that can be used for a controlled - * state transition. The UI is force-set to fromState before creating the controller. - * @param fromState the initial state for the transition. - * @param state the final state for the transition. - * @param duration intended duration for normal playback. Use higher duration for better - * accuracy. + * Creates an animation representing atomic transitions between the provided states */ - public AnimatorPlaybackController createAnimationToNewWorkspace( - LauncherState fromState, LauncherState state, long duration) { - // Since we are creating a state animation to a different state, temporarily prevent state - // change as part of config reset. - LauncherState originalRestState = mRestState; - mRestState = state; - mConfig.reset(); - mRestState = originalRestState; + public AnimatorSet createAtomicAnimation( + LauncherState fromState, LauncherState toState, StateAnimationConfig config) { + PendingAnimation builder = new PendingAnimation(config.duration); + prepareForAtomicAnimation(fromState, toState, config); - for (StateHandler handler : getStateHandlers()) { - handler.setState(fromState); + for (StateHandler handler : mLauncher.getStateManager().getStateHandlers()) { + handler.setStateWithAnimation(toState, config, builder); } - - return createAnimationToNewWorkspace(state, duration); + return builder.getAnim(); } /** @@ -362,32 +316,27 @@ public class LauncherStateManager { public AnimatorPlaybackController createAnimationToNewWorkspace( LauncherState state, long duration, @AnimationFlags int animComponents) { - return createAnimationToNewWorkspace(state, new AnimatorSetBuilder(), duration, null, - animComponents); + StateAnimationConfig config = new StateAnimationConfig(); + config.duration = duration; + config.animFlags = animComponents; + return createAnimationToNewWorkspace(state, config); } public AnimatorPlaybackController createAnimationToNewWorkspace(LauncherState state, - AnimatorSetBuilder builder, long duration, Runnable onCancelRunnable, - @AnimationFlags int animComponents) { + StateAnimationConfig config) { mConfig.reset(); - mConfig.userControlled = true; - mConfig.mAnimFlags = animComponents; - mConfig.duration = duration; - mConfig.playbackController = AnimatorPlaybackController.wrap( - createAnimationToNewWorkspaceInternal(state, builder, null), duration) - .setOnCancelRunnable(onCancelRunnable); + config.copyTo(mConfig); + mConfig.playbackController = createAnimationToNewWorkspaceInternal(state) + .createPlaybackController(); return mConfig.playbackController; } - protected AnimatorSet createAnimationToNewWorkspaceInternal(final LauncherState state, - AnimatorSetBuilder builder, final Runnable onCompleteRunnable) { - + private PendingAnimation createAnimationToNewWorkspaceInternal(final LauncherState state) { + PendingAnimation builder = new PendingAnimation(mConfig.duration); for (StateHandler handler : getStateHandlers()) { - handler.setStateWithAnimation(state, builder, mConfig); + handler.setStateWithAnimation(state, mConfig, builder); } - - final AnimatorSet animation = builder.build(); - animation.addListener(new AnimationSuccessListener() { + builder.getAnim().addListener(new AnimationSuccessListener() { @Override public void onAnimationStart(Animator animation) { @@ -397,15 +346,11 @@ public class LauncherStateManager { @Override public void onAnimationSuccess(Animator animator) { - // Run any queued runnables - if (onCompleteRunnable != null) { - onCompleteRunnable.run(); - } onStateTransitionEnd(state); } }); - mConfig.setAnimation(animation, state); - return mConfig.mCurrentAnimation; + mConfig.setAnimation(builder.getAnim(), state); + return builder; } private void onStateTransitionStart(LauncherState state) { @@ -452,7 +397,7 @@ public class LauncherStateManager { } public void moveToRestState() { - if (mConfig.mCurrentAnimation != null && mConfig.userControlled) { + if (mConfig.currentAnimation != null && mConfig.userControlled) { // The user is doing something. Lets not mess it up return; } @@ -500,12 +445,12 @@ public class LauncherStateManager { && mConfig.playbackController.getTarget() == childAnim) { clearCurrentAnimation(); break; - } else if (mConfig.mCurrentAnimation == childAnim) { + } else if (mConfig.currentAnimation == childAnim) { clearCurrentAnimation(); break; } } - boolean reapplyNeeded = mConfig.mCurrentAnimation != null; + boolean reapplyNeeded = mConfig.currentAnimation != null; cancelAnimation(); if (reapplyNeeded) { reapplyState(); @@ -557,9 +502,9 @@ public class LauncherStateManager { } private void clearCurrentAnimation() { - if (mConfig.mCurrentAnimation != null) { - mConfig.mCurrentAnimation.removeListener(mConfig); - mConfig.mCurrentAnimation = null; + if (mConfig.currentAnimation != null) { + mConfig.currentAnimation.removeListener(mConfig); + mConfig.currentAnimation = null; } mConfig.playbackController = null; } @@ -574,54 +519,42 @@ public class LauncherStateManager { @Override public void run() { - if (mConfig.mCurrentAnimation != mAnim) { + if (mConfig.currentAnimation != mAnim) { return; } mAnim.start(); } } - public static class AnimationConfig extends AnimatorListenerAdapter { - public long duration; - public boolean userControlled; - public AnimatorPlaybackController playbackController; - private @AnimationFlags int mAnimFlags = ANIM_ALL_COMPONENTS; - private PropertySetter mPropertySetter; + private static class AnimationState extends StateAnimationConfig implements AnimatorListener { + + private static final StateAnimationConfig DEFAULT = new StateAnimationConfig(); + + public AnimatorPlaybackController playbackController; + public AnimatorSet currentAnimation; + public LauncherState targetState; - private AnimatorSet mCurrentAnimation; - private LauncherState mTargetState; // Id to keep track of config changes, to tie an animation with the corresponding request - private int mChangeId = 0; + public int changeId = 0; /** * Cancels the current animation and resets config variables. */ public void reset() { - duration = 0; - userControlled = false; - mAnimFlags = ANIM_ALL_COMPONENTS; - mPropertySetter = null; - mTargetState = null; + DEFAULT.copyTo(this); + targetState = null; if (playbackController != null) { playbackController.getAnimationPlayer().cancel(); playbackController.dispatchOnCancel(); - } else if (mCurrentAnimation != null) { - mCurrentAnimation.setDuration(0); - mCurrentAnimation.cancel(); + } else if (currentAnimation != null) { + currentAnimation.setDuration(0); + currentAnimation.cancel(); } - mCurrentAnimation = null; + currentAnimation = null; playbackController = null; - mChangeId ++; - } - - public PropertySetter getPropertySetter(AnimatorSetBuilder builder) { - if (mPropertySetter == null) { - mPropertySetter = duration == 0 ? NO_ANIM_PROPERTY_SETTER - : new AnimatedPropertySetter(duration, builder); - } - return mPropertySetter; + changeId++; } @Override @@ -629,51 +562,25 @@ public class LauncherStateManager { if (playbackController != null && playbackController.getTarget() == animation) { playbackController = null; } - if (mCurrentAnimation == animation) { - mCurrentAnimation = null; + if (currentAnimation == animation) { + currentAnimation = null; } } public void setAnimation(AnimatorSet animation, LauncherState targetState) { - mCurrentAnimation = animation; - mTargetState = targetState; - mCurrentAnimation.addListener(this); + currentAnimation = animation; + this.targetState = targetState; + currentAnimation.addListener(this); } - /** - * @return Whether Overview is scaling as part of this animation. If this is the only - * component (i.e. NON_ATOMIC_COMPONENT isn't included), then this scaling is happening - * atomically, rather than being part of a normal state animation. StateHandlers can use - * this to designate part of their animation that should scale with Overview. - */ - public boolean playAtomicOverviewScaleComponent() { - return hasAnimationFlag(PLAY_ATOMIC_OVERVIEW_SCALE); - } + @Override + public void onAnimationStart(Animator animator) { } - /** - * @return Whether this animation will play atomically at the same time as a different, - * user-controlled state transition. StateHandlers, which contribute to both animations, can - * use this to avoid animating the same properties in both animations, since they'd conflict - * with one another. - */ - public boolean onlyPlayAtomicComponent() { - return getAnimComponents() == PLAY_ATOMIC_OVERVIEW_SCALE - || getAnimComponents() == PLAY_ATOMIC_OVERVIEW_PEEK; - } + @Override + public void onAnimationCancel(Animator animator) { } - /** - * Returns true if the config and any of the provided component flags - */ - public boolean hasAnimationFlag(@AnimationFlags int a) { - return (mAnimFlags & a) != 0; - } - - /** - * @return Only the flags that determine which animation components to play. - */ - public @AnimationFlags int getAnimComponents() { - return mAnimFlags & ANIM_ALL_COMPONENTS; - } + @Override + public void onAnimationRepeat(Animator animator) { } } public interface StateHandler { @@ -686,8 +593,8 @@ public class LauncherStateManager { /** * Sets the UI to {@param state} by animating any changes. */ - void setStateWithAnimation(LauncherState toState, - AnimatorSetBuilder builder, AnimationConfig config); + void setStateWithAnimation( + LauncherState toState, StateAnimationConfig config, PendingAnimation animation); } public interface StateListener { diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index fc1a074501..ead6018505 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -60,11 +60,10 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.widget.Toast; import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener; -import com.android.launcher3.LauncherStateManager.AnimationConfig; import com.android.launcher3.accessibility.AccessibleDragListenerAdapter; import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper; -import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dot.FolderDotInfo; import com.android.launcher3.dragndrop.DragController; @@ -83,6 +82,7 @@ import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.pageindicators.WorkspacePageIndicator; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider; +import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.WorkspaceTouchListener; import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; @@ -1383,10 +1383,10 @@ public class Workspace extends PagedView * Sets the current workspace {@link LauncherState}, then animates the UI */ @Override - public void setStateWithAnimation(LauncherState toState, - AnimatorSetBuilder builder, AnimationConfig config) { + public void setStateWithAnimation( + LauncherState toState, StateAnimationConfig config, PendingAnimation animation) { StateTransitionListener listener = new StateTransitionListener(toState); - mStateTransitionAnimation.setStateWithAnimation(toState, builder, config); + mStateTransitionAnimation.setStateWithAnimation(toState, config, animation); // Invalidate the pages now, so that we have the visible pages before the // animation is started @@ -1399,7 +1399,7 @@ public class Workspace extends PagedView stepAnimator.addUpdateListener(listener); stepAnimator.setDuration(config.duration); stepAnimator.addListener(listener); - builder.play(stepAnimator); + animation.add(stepAnimator); } public WorkspaceStateTransitionAnimation getStateTransitionAnimation() { diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java index 6653426b91..c521c34e33 100644 --- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java +++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java @@ -22,27 +22,27 @@ import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA; import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X; import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y; import static com.android.launcher3.LauncherState.HOTSEAT_ICONS; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_SCALE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_TRANSLATE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.ZOOM_OUT; import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER; import static com.android.launcher3.graphics.WorkspaceAndHotseatScrim.SCRIM_PROGRESS; import static com.android.launcher3.graphics.WorkspaceAndHotseatScrim.SYSUI_PROGRESS; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE; import android.view.View; import android.view.animation.Interpolator; import com.android.launcher3.LauncherState.PageAlphaProvider; import com.android.launcher3.LauncherState.ScaleAndTranslation; -import com.android.launcher3.LauncherStateManager.AnimationConfig; import com.android.launcher3.allapps.AllAppsContainerView; -import com.android.launcher3.anim.AnimatorSetBuilder; +import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.PropertySetter; import com.android.launcher3.graphics.WorkspaceAndHotseatScrim; +import com.android.launcher3.states.StateAnimationConfig; /** * Manages the animations between each of the workspace states. @@ -60,13 +60,15 @@ public class WorkspaceStateTransitionAnimation { } public void setState(LauncherState toState) { - setWorkspaceProperty(toState, NO_ANIM_PROPERTY_SETTER, new AnimatorSetBuilder(), - new AnimationConfig()); + setWorkspaceProperty(toState, NO_ANIM_PROPERTY_SETTER, new StateAnimationConfig()); } - public void setStateWithAnimation(LauncherState toState, AnimatorSetBuilder builder, - AnimationConfig config) { - setWorkspaceProperty(toState, config.getPropertySetter(builder), builder, config); + /** + * @see com.android.launcher3.LauncherStateManager.StateHandler#setStateWithAnimation + */ + public void setStateWithAnimation( + LauncherState toState, StateAnimationConfig config, PendingAnimation animation) { + setWorkspaceProperty(toState, animation, config); } public float getFinalScale() { @@ -77,7 +79,7 @@ public class WorkspaceStateTransitionAnimation { * Starts a transition animation for the workspace. */ private void setWorkspaceProperty(LauncherState state, PropertySetter propertySetter, - AnimatorSetBuilder builder, AnimationConfig config) { + StateAnimationConfig config) { ScaleAndTranslation scaleAndTranslation = state.getWorkspaceScaleAndTranslation(mLauncher); ScaleAndTranslation hotseatScaleAndTranslation = state.getHotseatScaleAndTranslation( mLauncher); @@ -87,11 +89,11 @@ public class WorkspaceStateTransitionAnimation { final int childCount = mWorkspace.getChildCount(); for (int i = 0; i < childCount; i++) { applyChildState(state, (CellLayout) mWorkspace.getChildAt(i), i, pageAlphaProvider, - propertySetter, builder, config); + propertySetter, config); } int elements = state.getVisibleElements(mLauncher); - Interpolator fadeInterpolator = builder.getInterpolator(ANIM_WORKSPACE_FADE, + Interpolator fadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE, pageAlphaProvider.interpolator); boolean playAtomicComponent = config.playAtomicOverviewScaleComponent(); Hotseat hotseat = mWorkspace.getHotseat(); @@ -99,7 +101,7 @@ public class WorkspaceStateTransitionAnimation { AllAppsContainerView qsbScaleView = mLauncher.getAppsView(); View qsbView = qsbScaleView.getSearchView(); if (playAtomicComponent) { - Interpolator scaleInterpolator = builder.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT); + Interpolator scaleInterpolator = config.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT); propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator); if (!hotseat.getRotationMode().isTransposed) { @@ -107,7 +109,7 @@ public class WorkspaceStateTransitionAnimation { setPivotToScaleWithWorkspace(qsbScaleView); } float hotseatScale = hotseatScaleAndTranslation.scale; - Interpolator hotseatScaleInterpolator = builder.getInterpolator(ANIM_HOTSEAT_SCALE, + Interpolator hotseatScaleInterpolator = config.getInterpolator(ANIM_HOTSEAT_SCALE, scaleInterpolator); propertySetter.setFloat(hotseat, SCALE_PROPERTY, hotseatScale, hotseatScaleInterpolator); @@ -127,13 +129,13 @@ public class WorkspaceStateTransitionAnimation { Interpolator translationInterpolator = !playAtomicComponent ? LINEAR - : builder.getInterpolator(ANIM_WORKSPACE_TRANSLATE, ZOOM_OUT); + : config.getInterpolator(ANIM_WORKSPACE_TRANSLATE, ZOOM_OUT); propertySetter.setFloat(mWorkspace, VIEW_TRANSLATE_X, scaleAndTranslation.translationX, translationInterpolator); propertySetter.setFloat(mWorkspace, VIEW_TRANSLATE_Y, scaleAndTranslation.translationY, translationInterpolator); - Interpolator hotseatTranslationInterpolator = builder.getInterpolator( + Interpolator hotseatTranslationInterpolator = config.getInterpolator( ANIM_HOTSEAT_TRANSLATE, translationInterpolator); propertySetter.setFloat(hotseat, VIEW_TRANSLATE_Y, hotseatScaleAndTranslation.translationY, hotseatTranslationInterpolator); @@ -166,12 +168,12 @@ public class WorkspaceStateTransitionAnimation { public void applyChildState(LauncherState state, CellLayout cl, int childIndex) { applyChildState(state, cl, childIndex, state.getWorkspacePageAlphaProvider(mLauncher), - NO_ANIM_PROPERTY_SETTER, new AnimatorSetBuilder(), new AnimationConfig()); + NO_ANIM_PROPERTY_SETTER, new StateAnimationConfig()); } private void applyChildState(LauncherState state, CellLayout cl, int childIndex, PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter, - AnimatorSetBuilder builder, AnimationConfig config) { + StateAnimationConfig config) { float pageAlpha = pageAlphaProvider.getPageAlpha(childIndex); int drawableAlpha = Math.round(pageAlpha * (state.hasWorkspacePageBackground ? 255 : 0)); @@ -181,7 +183,7 @@ public class WorkspaceStateTransitionAnimation { DRAWABLE_ALPHA, drawableAlpha, ZOOM_OUT); } if (config.playAtomicOverviewScaleComponent()) { - Interpolator fadeInterpolator = builder.getInterpolator(ANIM_WORKSPACE_FADE, + Interpolator fadeInterpolator = config.getInterpolator(ANIM_WORKSPACE_FADE, pageAlphaProvider.interpolator); propertySetter.setFloat(cl.getShortcutsAndWidgets(), VIEW_ALPHA, pageAlpha, fadeInterpolator); diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index 744f4eb96b..7600f527d0 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -5,13 +5,13 @@ import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA; import static com.android.launcher3.LauncherState.APPS_VIEW_ITEM_MASK; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherState.VERTICAL_SWIPE_INDICATOR; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_HEADER_FADE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE; -import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS; import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_HEADER_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS; import static com.android.launcher3.util.SystemUiController.UI_STATE_ALL_APPS; import android.animation.Animator; @@ -24,12 +24,12 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; -import com.android.launcher3.LauncherStateManager.AnimationConfig; import com.android.launcher3.LauncherStateManager.StateHandler; import com.android.launcher3.R; import com.android.launcher3.anim.AnimationSuccessListener; -import com.android.launcher3.anim.AnimatorSetBuilder; +import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.PropertySetter; +import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.util.Themes; import com.android.launcher3.views.ScrimView; @@ -112,7 +112,7 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil * @param progress value between 0 and 1, 0 shows all apps and 1 shows workspace * * @see #setState(LauncherState) - * @see #setStateWithAnimation(LauncherState, AnimatorSetBuilder, AnimationConfig) + * @see #setStateWithAnimation(LauncherState, StateAnimationConfig, PendingAnimation) */ public void setProgress(float progress) { mProgress = progress; @@ -143,7 +143,7 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil @Override public void setState(LauncherState state) { setProgress(state.getVerticalProgress(mLauncher)); - setAlphas(state, null, new AnimatorSetBuilder()); + setAlphas(state, new StateAnimationConfig(), NO_ANIM_PROPERTY_SETTER); onProgressAnimationEnd(); } @@ -153,7 +153,7 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil */ @Override public void setStateWithAnimation(LauncherState toState, - AnimatorSetBuilder builder, AnimationConfig config) { + StateAnimationConfig config, PendingAnimation builder) { float targetProgress = toState.getVerticalProgress(mLauncher); if (Float.compare(mProgress, targetProgress) == 0) { setAlphas(toState, config, builder); @@ -168,14 +168,14 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil } Interpolator interpolator = config.userControlled ? LINEAR : toState == OVERVIEW - ? builder.getInterpolator(ANIM_OVERVIEW_SCALE, FAST_OUT_SLOW_IN) + ? config.getInterpolator(ANIM_OVERVIEW_SCALE, FAST_OUT_SLOW_IN) : FAST_OUT_SLOW_IN; + Animator anim = createSpringAnimation(mProgress, targetProgress); anim.setDuration(config.duration); - anim.setInterpolator(builder.getInterpolator(ANIM_VERTICAL_PROGRESS, interpolator)); + anim.setInterpolator(config.getInterpolator(ANIM_VERTICAL_PROGRESS, interpolator)); anim.addListener(getProgressAnimatorListener()); - - builder.play(anim); + builder.add(anim); setAlphas(toState, config, builder); } @@ -184,21 +184,18 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil return ObjectAnimator.ofFloat(this, ALL_APPS_PROGRESS, progressValues); } - private void setAlphas(LauncherState toState, AnimationConfig config, - AnimatorSetBuilder builder) { - setAlphas(toState.getVisibleElements(mLauncher), config, builder); - } - - public void setAlphas(int visibleElements, AnimationConfig config, AnimatorSetBuilder builder) { - PropertySetter setter = config == null ? NO_ANIM_PROPERTY_SETTER - : config.getPropertySetter(builder); + /** + * Updates the property for the provided state + */ + public void setAlphas(LauncherState state, StateAnimationConfig config, PropertySetter setter) { + int visibleElements = state.getVisibleElements(mLauncher); boolean hasHeaderExtra = (visibleElements & ALL_APPS_HEADER_EXTRA) != 0; boolean hasAllAppsContent = (visibleElements & ALL_APPS_CONTENT) != 0; boolean hasAnyVisibleItem = (visibleElements & APPS_VIEW_ITEM_MASK) != 0; - Interpolator allAppsFade = builder.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR); - Interpolator headerFade = builder.getInterpolator(ANIM_ALL_APPS_HEADER_FADE, allAppsFade); + Interpolator allAppsFade = config.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR); + Interpolator headerFade = config.getInterpolator(ANIM_ALL_APPS_HEADER_FADE, allAppsFade); setter.setViewAlpha(mAppsView.getContentView(), hasAllAppsContent ? 1 : 0, allAppsFade); setter.setViewAlpha(mAppsView.getScrollBar(), hasAllAppsContent ? 1 : 0, allAppsFade); mAppsView.getFloatingHeaderView().setContentVisibility(hasHeaderExtra, hasAllAppsContent, diff --git a/src/com/android/launcher3/anim/AnimatorPlaybackController.java b/src/com/android/launcher3/anim/AnimatorPlaybackController.java index 1fc21fd63e..958c86366c 100644 --- a/src/com/android/launcher3/anim/AnimatorPlaybackController.java +++ b/src/com/android/launcher3/anim/AnimatorPlaybackController.java @@ -64,13 +64,6 @@ public class AnimatorPlaybackController implements ValueAnimator.AnimatorUpdateL return new AnimatorPlaybackController(anim, duration, childAnims); } - public static AnimatorPlaybackController wrap(PendingAnimation anim, long duration) { - /** - * TODO: use {@link AnimatorSet#setCurrentPlayTime(long)} once b/68382377 is fixed. - */ - return new AnimatorPlaybackController(anim.anim, duration, anim.animHolders); - } - private static final FloatProperty CURRENT_PLAY_TIME = new FloatProperty("current-play-time") { @Override @@ -96,8 +89,8 @@ public class AnimatorPlaybackController implements ValueAnimator.AnimatorUpdateL protected boolean mTargetCancelled = false; protected Runnable mOnCancelRunnable; - private AnimatorPlaybackController( - AnimatorSet anim, long duration, ArrayList childAnims) { + /** package private */ + AnimatorPlaybackController(AnimatorSet anim, long duration, ArrayList childAnims) { mAnim = anim; mDuration = duration; diff --git a/src/com/android/launcher3/anim/AnimatorSetBuilder.java b/src/com/android/launcher3/anim/AnimatorSetBuilder.java deleted file mode 100644 index d814b19e69..0000000000 --- a/src/com/android/launcher3/anim/AnimatorSetBuilder.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2017 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.anim; - -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.util.SparseArray; -import android.view.animation.Interpolator; - -import java.util.ArrayList; - -/** - * Utility class for building animator set - */ -public class AnimatorSetBuilder { - - public static final int ANIM_VERTICAL_PROGRESS = 0; - public static final int ANIM_WORKSPACE_SCALE = 1; - public static final int ANIM_WORKSPACE_TRANSLATE = 2; - public static final int ANIM_WORKSPACE_FADE = 3; - public static final int ANIM_HOTSEAT_SCALE = 4; - public static final int ANIM_HOTSEAT_TRANSLATE = 5; - public static final int ANIM_OVERVIEW_SCALE = 6; - public static final int ANIM_OVERVIEW_TRANSLATE_X = 7; - public static final int ANIM_OVERVIEW_TRANSLATE_Y = 8; - public static final int ANIM_OVERVIEW_FADE = 9; - public static final int ANIM_ALL_APPS_FADE = 10; - public static final int ANIM_OVERVIEW_SCRIM_FADE = 11; - public static final int ANIM_ALL_APPS_HEADER_FADE = 12; // e.g. predictions - - protected final ArrayList mAnims = new ArrayList<>(); - - private final SparseArray mInterpolators = new SparseArray<>(); - - public void play(Animator anim) { - mAnims.add(anim); - } - - public AnimatorSet build() { - AnimatorSet anim = new AnimatorSet(); - anim.playTogether(mAnims); - return anim; - } - - public Interpolator getInterpolator(int animId, Interpolator fallback) { - return mInterpolators.get(animId, fallback); - } - - public void setInterpolator(int animId, Interpolator interpolator) { - mInterpolators.put(animId, interpolator); - } -} diff --git a/src/com/android/launcher3/anim/PendingAnimation.java b/src/com/android/launcher3/anim/PendingAnimation.java index 562d160b50..9a25c47a74 100644 --- a/src/com/android/launcher3/anim/PendingAnimation.java +++ b/src/com/android/launcher3/anim/PendingAnimation.java @@ -19,9 +19,12 @@ import static com.android.launcher3.anim.AnimatorPlaybackController.addAnimation import android.animation.Animator; import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; -import android.annotation.TargetApi; -import android.os.Build; +import android.animation.ValueAnimator; +import android.util.FloatProperty; +import android.util.IntProperty; +import android.view.View; import com.android.launcher3.anim.AnimatorPlaybackController.Holder; @@ -37,14 +40,24 @@ import java.util.function.Consumer; * * TODO: Find a better name */ -@TargetApi(Build.VERSION_CODES.O) -public class PendingAnimation { +public class PendingAnimation implements PropertySetter { private final ArrayList> mEndListeners = new ArrayList<>(); - /** package private **/ - final AnimatorSet anim = new AnimatorSet(); - final ArrayList animHolders = new ArrayList<>(); + private final ArrayList mAnimHolders = new ArrayList<>(); + private final AnimatorSet mAnim; + private final long mDuration; + + private ValueAnimator mProgressAnimator; + + public PendingAnimation(long duration) { + this(duration, new AnimatorSet()); + } + + public PendingAnimation(long duration, AnimatorSet targetSet) { + mDuration = duration; + mAnim = targetSet; + } /** * Utility method to sent an interpolator on an animation and add it to the list @@ -63,8 +76,8 @@ public class PendingAnimation { } public void add(Animator a, SpringProperty springProperty) { - anim.play(a); - addAnimationHoldersRecur(a, springProperty, animHolders); + mAnim.play(a); + addAnimationHoldersRecur(a, springProperty, mAnimHolders); } public void finish(boolean isSuccess, int logAction) { @@ -74,6 +87,67 @@ public class PendingAnimation { mEndListeners.clear(); } + @Override + public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) { + if (view == null || view.getAlpha() == alpha) { + return; + } + ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha); + anim.addListener(new AlphaUpdateListener(view)); + anim.setDuration(mDuration).setInterpolator(interpolator); + add(anim); + } + + @Override + public void setFloat(T target, FloatProperty property, float value, + TimeInterpolator interpolator) { + if (property.get(target) == value) { + return; + } + Animator anim = ObjectAnimator.ofFloat(target, property, value); + anim.setDuration(mDuration).setInterpolator(interpolator); + add(anim); + } + + @Override + public void setInt(T target, IntProperty property, int value, + TimeInterpolator interpolator) { + if (property.get(target) == value) { + return; + } + Animator anim = ObjectAnimator.ofInt(target, property, value); + anim.setDuration(mDuration).setInterpolator(interpolator); + add(anim); + } + + /** + * Adds a callback to be run on every frame of the animation + */ + public void addOnFrameCallback(Runnable runnable) { + if (mProgressAnimator == null) { + mProgressAnimator = ValueAnimator.ofFloat(0, 1).setDuration(mDuration); + add(mProgressAnimator); + } + + mProgressAnimator.addUpdateListener(anim -> runnable.run()); + } + + public AnimatorSet getAnim() { + return mAnim; + } + + /** + * Creates a controller for this animation + */ + public AnimatorPlaybackController createPlaybackController() { + return new AnimatorPlaybackController(mAnim, mDuration, mAnimHolders); + } + + /** + * Add a listener of receiving the end state. + * Note that the listeners are called as a result of calling {@link #finish(boolean, int)} + * and not automatically + */ public void addEndListener(Consumer listener) { mEndListeners.add(listener); } diff --git a/src/com/android/launcher3/anim/PropertySetter.java b/src/com/android/launcher3/anim/PropertySetter.java index 0b2eb48675..2ce620bbe1 100644 --- a/src/com/android/launcher3/anim/PropertySetter.java +++ b/src/com/android/launcher3/anim/PropertySetter.java @@ -16,8 +16,6 @@ package com.android.launcher3.anim; -import android.animation.Animator; -import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.util.FloatProperty; import android.util.IntProperty; @@ -26,68 +24,35 @@ import android.view.View; /** * Utility class for setting a property with or without animation */ -public class PropertySetter { +public interface PropertySetter { - public static final PropertySetter NO_ANIM_PROPERTY_SETTER = new PropertySetter(); + PropertySetter NO_ANIM_PROPERTY_SETTER = new PropertySetter() { }; - public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) { + /** + * Sets the view alpha using the provided interpolator. + * Unlike {@link #setFloat}, this also updates the visibility of the view as alpha changes + * between zero and non-zero. + */ + default void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) { if (view != null) { view.setAlpha(alpha); AlphaUpdateListener.updateVisibility(view); } } - public void setFloat(T target, FloatProperty property, float value, + /** + * Updates the float property of the target using the provided interpolator + */ + default void setFloat(T target, FloatProperty property, float value, TimeInterpolator interpolator) { property.setValue(target, value); } - public void setInt(T target, IntProperty property, int value, + /** + * Updates the int property of the target using the provided interpolator + */ + default void setInt(T target, IntProperty property, int value, TimeInterpolator interpolator) { property.setValue(target, value); } - - public static class AnimatedPropertySetter extends PropertySetter { - - private final long mDuration; - private final AnimatorSetBuilder mStateAnimator; - - public AnimatedPropertySetter(long duration, AnimatorSetBuilder builder) { - mDuration = duration; - mStateAnimator = builder; - } - - @Override - public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) { - if (view == null || view.getAlpha() == alpha) { - return; - } - ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha); - anim.addListener(new AlphaUpdateListener(view)); - anim.setDuration(mDuration).setInterpolator(interpolator); - mStateAnimator.play(anim); - } - - @Override - public void setFloat(T target, FloatProperty property, float value, - TimeInterpolator interpolator) { - if (property.get(target) == value) { - return; - } - Animator anim = ObjectAnimator.ofFloat(target, property, value); - anim.setDuration(mDuration).setInterpolator(interpolator); - mStateAnimator.play(anim); - } - - @Override - public void setInt(T target, IntProperty property, int value, - TimeInterpolator interpolator) { - if (property.get(target) == value) { - return; - } - Animator anim = ObjectAnimator.ofInt(target, property, value); - anim.setDuration(mDuration).setInterpolator(interpolator); - mStateAnimator.play(anim); - } - } } diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index 650b20a7f4..dfd36e71f6 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -100,11 +100,11 @@ public final class FeatureFlags { "Suggests folder names instead of blank text."); public static final BooleanFlag APP_SEARCH_IMPROVEMENTS = new DeviceFlag( - "APP_SEARCH_IMPROVEMENTS", false, + "APP_SEARCH_IMPROVEMENTS", true, "Adds localized title and keyword search and ranking"); - public static final BooleanFlag ENABLE_PREDICTION_DISMISS = new DeviceFlag( - "ENABLE_PREDICTION_DISMISS", true, "Allow option to dimiss apps from predicted list"); + public static final BooleanFlag ENABLE_PREDICTION_DISMISS = getDebugFlag( + "ENABLE_PREDICTION_DISMISS", false, "Allow option to dimiss apps from predicted list"); public static final BooleanFlag ENABLE_QUICK_CAPTURE_GESTURE = getDebugFlag( "ENABLE_QUICK_CAPTURE_GESTURE", true, "Swipe from right to left to quick capture"); @@ -117,11 +117,11 @@ public final class FeatureFlags { "ASSISTANT_GIVES_LAUNCHER_FOCUS", false, "Allow Launcher to handle nav bar gestures while Assistant is running over it"); - public static final BooleanFlag ENABLE_HYBRID_HOTSEAT = new DeviceFlag( + public static final BooleanFlag ENABLE_HYBRID_HOTSEAT = getDebugFlag( "ENABLE_HYBRID_HOTSEAT", false, "Fill gaps in hotseat with predicted apps"); - public static final BooleanFlag HOTSEAT_MIGRATE_NEW_PAGE = new DeviceFlag( - "HOTSEAT_MIGRATE_NEW_PAGE", true, + public static final BooleanFlag HOTSEAT_MIGRATE_NEW_PAGE = getDebugFlag( + "HOTSEAT_MIGRATE_NEW_PAGE", false, "Migrates hotseat to a new workspace page instead of same page"); public static final BooleanFlag ENABLE_DEEP_SHORTCUT_ICON_CACHE = getDebugFlag( @@ -131,13 +131,18 @@ public final class FeatureFlags { "MULTI_DB_GRID_MIRATION_ALGO", false, "Use the multi-db grid migration algorithm"); public static final BooleanFlag ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER = getDebugFlag( - "ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER", true, - "Show launcher preview in grid picker"); + "ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER", true, "Show launcher preview in grid picker"); + + public static final BooleanFlag USE_SURFACE_VIEW_FOR_GRID_PREVIEW = getDebugFlag( + "USE_SURFACE_VIEW_FOR_GRID_PREVIEW", false, "Use surface view for grid preview"); public static final BooleanFlag ENABLE_OVERVIEW_ACTIONS = getDebugFlag( "ENABLE_OVERVIEW_ACTIONS", true, "Show app actions instead of the shelf in Overview." + " As part of this decoupling, also distinguish swipe up from nav bar vs above it."); + public static final BooleanFlag ENABLE_SELECT_MODE = getDebugFlag( + "ENABLE_SELECT_MODE", true, "Show Select Mode button in Overview Actions"); + public static final BooleanFlag ENABLE_DATABASE_RESTORE = getDebugFlag( "ENABLE_DATABASE_RESTORE", true, "Enable database restore when new restore session is created"); diff --git a/src/com/android/launcher3/graphics/GridOptionsProvider.java b/src/com/android/launcher3/graphics/GridOptionsProvider.java index 71b436600d..607aba9e6b 100644 --- a/src/com/android/launcher3/graphics/GridOptionsProvider.java +++ b/src/com/android/launcher3/graphics/GridOptionsProvider.java @@ -1,5 +1,6 @@ package com.android.launcher3.graphics; +import static com.android.launcher3.config.FeatureFlags.USE_SURFACE_VIEW_FOR_GRID_PREVIEW; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import android.content.ContentProvider; @@ -19,6 +20,7 @@ import android.util.Xml; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.InvariantDeviceProfile.GridOption; import com.android.launcher3.R; +import com.android.launcher3.uioverrides.PreviewSurfaceRenderer; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -62,6 +64,11 @@ public class GridOptionsProvider extends ContentProvider { private static final String KEY_PREVIEW = "preview"; private static final String MIME_TYPE_PNG = "image/png"; + private static final String METHOD_GET_PREVIEW = "get_preview"; + private static final String METADATA_KEY_PREVIEW_VERSION = "preview_version"; + + + public static final PipeDataWriter> BITMAP_WRITER = new PipeDataWriter>() { @Override @@ -98,6 +105,10 @@ public class GridOptionsProvider extends ContentProvider { .add(KEY_IS_DEFAULT, idp.numColumns == gridOption.numColumns && idp.numRows == gridOption.numRows); } + Bundle metadata = new Bundle(); + metadata.putString(METADATA_KEY_PREVIEW_VERSION, + USE_SURFACE_VIEW_FOR_GRID_PREVIEW.get() ? "V2" : "V1"); + cursor.setExtras(metadata); return cursor; } @@ -188,4 +199,14 @@ public class GridOptionsProvider extends ContentProvider { throw new FileNotFoundException(e.getMessage()); } } + + @Override + public Bundle call(String method, String arg, Bundle extras) { + if (!METHOD_GET_PREVIEW.equals(method)) { + return null; + } + + PreviewSurfaceRenderer.render(getContext(), extras); + return null; + } } diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java index 02e98e80df..5bc66106ab 100644 --- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java +++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java @@ -262,6 +262,13 @@ public class LauncherPreviewRenderer implements Callable { }); } + /** Populate preview and render it. */ + public View getRenderedView() { + MainThreadRenderer renderer = new MainThreadRenderer(mContext); + renderer.populate(); + return renderer.mRootView; + } + private class MainThreadRenderer extends ContextThemeWrapper implements ActivityContext, WorkspaceLayoutManager, LayoutInflater.Factory2 { @@ -388,7 +395,7 @@ public class LauncherPreviewRenderer implements Callable { } } - private void renderScreenShot(Canvas canvas) { + private void populate() { if (ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER.get()) { boolean needsToMigrate = needsToMigrate(mContext, mIdp); boolean success = false; @@ -499,7 +506,10 @@ public class LauncherPreviewRenderer implements Callable { measureView(mRootView, mDp.widthPx, mDp.heightPx); // Additional measure for views which use auto text size API measureView(mRootView, mDp.widthPx, mDp.heightPx); + } + private void renderScreenShot(Canvas canvas) { + populate(); mRootView.draw(canvas); dispatchVisibilityAggregated(mRootView, false); } diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java index 3770d178a0..89077ee1d3 100644 --- a/src/com/android/launcher3/logging/UserEventDispatcher.java +++ b/src/com/android/launcher3/logging/UserEventDispatcher.java @@ -143,7 +143,7 @@ public class UserEventDispatcher implements ResourceBasedOverride { fillIntentInfo(itemTarget, intent, userHandle); } LauncherEvent event = newLauncherEvent(action, targets); - ItemInfo info = (ItemInfo) v.getTag(); + ItemInfo info = v == null ? null : (ItemInfo) v.getTag(); if (info != null && Utilities.IS_DEBUG_DEVICE && FeatureFlags.ENABLE_HYBRID_HOTSEAT.get()) { FileLog.d(TAG, "appLaunch: packageName:" + info.getTargetComponent().getPackageName() + ",isWorkApp:" + (info.user != null && !Process.myUserHandle().equals( diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java index 3ba740d4d1..a0846001a1 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationTask.java +++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java @@ -936,8 +936,8 @@ public class GridSizeMigrationTask { boolean dbChanged = false; if (migrateForPreview) { - copyTable(transaction.getDb(), Favorites.TABLE_NAME, Favorites.PREVIEW_TABLE_NAME, - context); + copyTable(transaction.getDb(), Favorites.TABLE_NAME, transaction.getDb(), + Favorites.PREVIEW_TABLE_NAME, context); } GridBackupTable backupTable = new GridBackupTable(context, transaction.getDb(), @@ -950,10 +950,11 @@ public class GridSizeMigrationTask { HashSet validPackages = getValidPackages(context); // Hotseat. - if (srcHotseatCount != idp.numHotseatIcons) { - // Migrate hotseat. - dbChanged = new GridSizeMigrationTask(context, transaction.getDb(), validPackages, - migrateForPreview, srcHotseatCount, idp.numHotseatIcons).migrateHotseat(); + if (srcHotseatCount != idp.numHotseatIcons + && new GridSizeMigrationTask(context, transaction.getDb(), validPackages, + migrateForPreview, srcHotseatCount, + idp.numHotseatIcons).migrateHotseat()) { + dbChanged = true; } // Grid size diff --git a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java index 197b29c688..0bdccfa16c 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java +++ b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java @@ -16,9 +16,46 @@ package com.android.launcher3.model; +import static com.android.launcher3.Utilities.getPointString; +import static com.android.launcher3.provider.LauncherDbUtils.dropTable; + +import android.content.ComponentName; +import android.content.ContentValues; import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.database.sqlite.SQLiteDatabase; +import android.graphics.Point; +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.VisibleForTesting; import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherAppWidgetProviderInfo; +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.Utilities; +import com.android.launcher3.graphics.LauncherPreviewRenderer; +import com.android.launcher3.pm.InstallSessionHelper; +import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction; +import com.android.launcher3.util.GridOccupancy; +import com.android.launcher3.util.IntArray; +import com.android.launcher3.widget.WidgetManagerHelper; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; /** * This class takes care of shrinking the workspace (by maximum of one row and one column), as a @@ -26,14 +63,63 @@ import com.android.launcher3.InvariantDeviceProfile; */ public class GridSizeMigrationTaskV2 { - private GridSizeMigrationTaskV2(Context context) { + public static final String KEY_MIGRATION_SRC_WORKSPACE_SIZE = "migration_src_workspace_size"; + public static final String KEY_MIGRATION_SRC_HOTSEAT_COUNT = "migration_src_hotseat_count"; + private static final String TAG = "GridSizeMigrationTaskV2"; + private static final boolean DEBUG = true; + + private final Context mContext; + private final SQLiteDatabase mDb; + private final DbReader mSrcReader; + private final DbReader mDestReader; + + private final List mHotseatItems; + private final List mWorkspaceItems; + + private final List mHotseatDiff; + private final List mWorkspaceDiff; + + private final int mDestHotseatSize; + private final int mTrgX, mTrgY; + + @VisibleForTesting + protected GridSizeMigrationTaskV2(Context context, SQLiteDatabase db, DbReader srcReader, + DbReader destReader, int destHotseatSize, Point targetSize) { + mContext = context; + mDb = db; + mSrcReader = srcReader; + mDestReader = destReader; + + mHotseatItems = destReader.loadHotseatEntries(); + mWorkspaceItems = destReader.loadAllWorkspaceEntries(); + + mHotseatDiff = calcDiff(mSrcReader.loadHotseatEntries(), mHotseatItems); + mWorkspaceDiff = calcDiff(mSrcReader.loadAllWorkspaceEntries(), mWorkspaceItems); + mDestHotseatSize = destHotseatSize; + + mTrgX = targetSize.x; + mTrgY = targetSize.y; + } + + /** + * Check given a new IDP, if migration is necessary. + */ + public static boolean needsToMigrate(Context context, InvariantDeviceProfile idp) { + SharedPreferences prefs = Utilities.getPrefs(context); + String gridSizeString = getPointString(idp.numColumns, idp.numRows); + + return !gridSizeString.equals(prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, "")) + || idp.numHotseatIcons != prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, + idp.numHotseatIcons); } /** See {@link #migrateGridIfNeeded(Context, InvariantDeviceProfile)} */ public static boolean migrateGridIfNeeded(Context context) { - // To be implemented. - return true; + if (context instanceof LauncherPreviewRenderer.PreviewContext) { + return true; + } + return migrateGridIfNeeded(context, null); } /** @@ -43,7 +129,608 @@ public class GridSizeMigrationTaskV2 { * @return false if the migration failed. */ public static boolean migrateGridIfNeeded(Context context, InvariantDeviceProfile idp) { - // To be implemented. + boolean migrateForPreview = idp != null; + if (!migrateForPreview) { + idp = LauncherAppState.getIDP(context); + } + + if (!needsToMigrate(context, idp)) { + return true; + } + + SharedPreferences prefs = Utilities.getPrefs(context); + String gridSizeString = getPointString(idp.numColumns, idp.numRows); + + if (gridSizeString.equals(prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, "")) + && idp.numHotseatIcons == prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, + idp.numHotseatIcons)) { + // Skip if workspace and hotseat sizes have not changed. + return true; + } + + HashSet validPackages = getValidPackages(context); + int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons); + + if (!LauncherSettings.Settings.call( + context.getContentResolver(), + LauncherSettings.Settings.METHOD_UPDATE_CURRENT_OPEN_HELPER).getBoolean( + LauncherSettings.Settings.EXTRA_VALUE)) { + return false; + } + + long migrationStartTime = System.currentTimeMillis(); + try (SQLiteTransaction t = (SQLiteTransaction) LauncherSettings.Settings.call( + context.getContentResolver(), + LauncherSettings.Settings.METHOD_NEW_TRANSACTION).getBinder( + LauncherSettings.Settings.EXTRA_VALUE)) { + + DbReader srcReader = new DbReader(t.getDb(), LauncherSettings.Favorites.TMP_TABLE, + context, validPackages, srcHotseatCount); + DbReader destReader = new DbReader(t.getDb(), LauncherSettings.Favorites.TABLE_NAME, + context, validPackages, idp.numHotseatIcons); + + Point targetSize = new Point(idp.numColumns, idp.numRows); + GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(context, t.getDb(), + srcReader, destReader, idp.numHotseatIcons, targetSize); + task.migrate(); + + dropTable(t.getDb(), LauncherSettings.Favorites.TMP_TABLE); + + t.commit(); + return true; + } catch (Exception e) { + Log.e(TAG, "Error during grid migration", e); + + return false; + } finally { + Log.v(TAG, "Workspace migration completed in " + + (System.currentTimeMillis() - migrationStartTime)); + + // Save current configuration, so that the migration does not run again. + prefs.edit() + .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString) + .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons) + .apply(); + } + } + + @VisibleForTesting + protected boolean migrate() { + if (mHotseatDiff.isEmpty() && mWorkspaceDiff.isEmpty()) { + return false; + } + + // Migrate hotseat + HotseatPlacementSolution hotseatSolution = new HotseatPlacementSolution(mDb, mSrcReader, + mContext, mDestHotseatSize, mHotseatItems, mHotseatDiff); + hotseatSolution.find(); + + // Sort the items by the reading order. + Collections.sort(mWorkspaceDiff); + + // Migrate workspace. + for (int screenId = 0; screenId <= mDestReader.mLastScreenId; screenId++) { + if (DEBUG) { + Log.d(TAG, "Migrating " + screenId); + } + List entries = mDestReader.loadWorkspaceEntries(screenId); + GridPlacementSolution workspaceSolution = new GridPlacementSolution(mDb, mSrcReader, + mContext, entries, screenId, mTrgX, mTrgY, mWorkspaceDiff); + workspaceSolution.find(); + if (mWorkspaceDiff.isEmpty()) { + break; + } + } + + int screenId = mDestReader.mLastScreenId + 1; + while (!mWorkspaceDiff.isEmpty()) { + GridPlacementSolution workspaceSolution = new GridPlacementSolution(mDb, mSrcReader, + mContext, new ArrayList<>(), screenId, mTrgX, mTrgY, mWorkspaceDiff); + workspaceSolution.find(); + screenId++; + } return true; } + + /** Return what's in the src but not in the dest */ + private static List calcDiff(List src, List dest) { + Set destSet = dest.parallelStream().map(DbEntry::getIntentStr).collect( + Collectors.toSet()); + List diff = new ArrayList<>(); + for (DbEntry entry : src) { + if (!destSet.contains(entry.mIntent)) { + diff.add(entry); + } + } + return diff; + } + + private static void insertEntryInDb(SQLiteDatabase db, Context context, + ArrayList entriesFromSrcDb, DbEntry entry) { + int id = -1; + switch (entry.itemType) { + case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: + case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: + case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: { + for (DbEntry e : entriesFromSrcDb) { + if (TextUtils.equals(e.mIntent, entry.mIntent)) { + id = e.id; + } + } + + break; + } + case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: { + for (DbEntry e : entriesFromSrcDb) { + if (e.mFolderItems.size() == entry.mFolderItems.size() + && e.mFolderItems.containsAll(entry.mFolderItems)) { + id = e.id; + } + } + break; + } + case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: + case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET: { + for (DbEntry e : entriesFromSrcDb) { + if (TextUtils.equals(e.mProvider, entry.mProvider)) { + id = e.id; + break; + } + } + break; + } + default: + return; + } + + Cursor c = db.query(LauncherSettings.Favorites.TMP_TABLE, null, + LauncherSettings.Favorites._ID + " = '" + id + "'", null, null, null, null); + + while (c.moveToNext()) { + ContentValues values = new ContentValues(); + DatabaseUtils.cursorRowToContentValues(c, values); + entry.updateContentValues(values); + values.put(LauncherSettings.Favorites._ID, + LauncherSettings.Settings.call(context.getContentResolver(), + LauncherSettings.Settings.METHOD_NEW_ITEM_ID).getInt( + LauncherSettings.Settings.EXTRA_VALUE)); + db.insert(LauncherSettings.Favorites.TABLE_NAME, null, values); + } + c.close(); + } + + private static void removeEntryFromDb(SQLiteDatabase db, IntArray entryId) { + db.delete(LauncherSettings.Favorites.TABLE_NAME, Utilities.createDbSelectionQuery( + LauncherSettings.Favorites._ID, entryId), null); + } + + private static HashSet getValidPackages(Context context) { + // Initialize list of valid packages. This contain all the packages which are already on + // the device and packages which are being installed. Any item which doesn't belong to + // this set is removed. + // Since the loader removes such items anyway, removing these items here doesn't cause + // any extra data loss and gives us more free space on the grid for better migration. + HashSet validPackages = new HashSet<>(); + for (PackageInfo info : context.getPackageManager() + .getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES)) { + validPackages.add(info.packageName); + } + InstallSessionHelper.INSTANCE.get(context) + .getActiveSessions().keySet() + .forEach(packageUserKey -> validPackages.add(packageUserKey.mPackageName)); + return validPackages; + } + + protected static class GridPlacementSolution { + + private final SQLiteDatabase mDb; + private final DbReader mSrcReader; + private final Context mContext; + private final GridOccupancy mOccupied; + private final int mScreenId; + private final int mTrgX; + private final int mTrgY; + private final List mItemsToPlace; + + private int mNextStartX; + private int mNextStartY; + + GridPlacementSolution(SQLiteDatabase db, DbReader srcReader, Context context, + List placedWorkspaceItems, int screenId, int trgX, + int trgY, List itemsToPlace) { + mDb = db; + mSrcReader = srcReader; + mContext = context; + mOccupied = new GridOccupancy(trgX, trgY); + mScreenId = screenId; + mTrgX = trgX; + mTrgY = trgY; + mNextStartX = 0; + mNextStartY = mTrgY - 1; + for (DbEntry entry : placedWorkspaceItems) { + mOccupied.markCells(entry, true); + } + mItemsToPlace = itemsToPlace; + } + + public void find() { + Iterator iterator = mItemsToPlace.iterator(); + while (iterator.hasNext()) { + final DbEntry entry = iterator.next(); + if (entry.minSpanX > mTrgX || entry.minSpanY > mTrgY) { + iterator.remove(); + continue; + } + if (findPlacement(entry)) { + insertEntryInDb(mDb, mContext, mSrcReader.mWorkspaceEntries, entry); + iterator.remove(); + } + } + } + + private boolean findPlacement(DbEntry entry) { + for (int y = mNextStartY; y >= 0; y--) { + for (int x = mNextStartX; x < mTrgX; x++) { + boolean fits = mOccupied.isRegionVacant(x, y, entry.spanX, entry.spanY); + boolean minFits = mOccupied.isRegionVacant(x, y, entry.minSpanX, + entry.minSpanY); + if (minFits) { + entry.spanX = entry.minSpanX; + entry.spanY = entry.minSpanY; + } + if (fits || minFits) { + entry.screenId = mScreenId; + entry.cellX = x; + entry.cellY = y; + mOccupied.markCells(entry, true); + mNextStartX = x + entry.spanX; + mNextStartY = y; + return true; + } + } + } + return false; + } + } + + protected static class HotseatPlacementSolution { + + private final SQLiteDatabase mDb; + private final DbReader mSrcReader; + private final Context mContext; + private final HotseatOccupancy mOccupied; + private final List mItemsToPlace; + + HotseatPlacementSolution(SQLiteDatabase db, DbReader srcReader, Context context, + int hotseatSize, List placedHotseatItems, List itemsToPlace) { + mDb = db; + mSrcReader = srcReader; + mContext = context; + mOccupied = new HotseatOccupancy(hotseatSize); + for (DbEntry entry : placedHotseatItems) { + mOccupied.markCells(entry, true); + } + mItemsToPlace = itemsToPlace; + } + + public void find() { + for (int i = 0; i < mOccupied.mCells.length; i++) { + if (!mOccupied.mCells[i] && !mItemsToPlace.isEmpty()) { + DbEntry entry = mItemsToPlace.remove(0); + entry.screenId = i; + // These values does not affect the item position, but we should set them + // to something other than -1. + entry.cellX = i; + entry.cellY = 0; + insertEntryInDb(mDb, mContext, mSrcReader.mHotseatEntries, entry); + mOccupied.markCells(entry, true); + } + } + } + + private class HotseatOccupancy { + + private final boolean[] mCells; + + private HotseatOccupancy(int hotseatSize) { + mCells = new boolean[hotseatSize]; + } + + private void markCells(ItemInfo item, boolean value) { + mCells[item.screenId] = value; + } + } + } + + protected static class DbReader { + + private final SQLiteDatabase mDb; + private final String mTableName; + private final Context mContext; + private final HashSet mValidPackages; + private final int mHotseatSize; + private int mLastScreenId = -1; + + private final ArrayList mHotseatEntries = new ArrayList<>(); + private final ArrayList mWorkspaceEntries = new ArrayList<>(); + + DbReader(SQLiteDatabase db, String tableName, Context context, + HashSet validPackages, int hotseatSize) { + mDb = db; + mTableName = tableName; + mContext = context; + mValidPackages = validPackages; + mHotseatSize = hotseatSize; + } + + protected ArrayList loadHotseatEntries() { + Cursor c = queryWorkspace( + new String[]{ + LauncherSettings.Favorites._ID, // 0 + LauncherSettings.Favorites.ITEM_TYPE, // 1 + LauncherSettings.Favorites.INTENT, // 2 + LauncherSettings.Favorites.SCREEN}, // 3 + LauncherSettings.Favorites.CONTAINER + " = " + + LauncherSettings.Favorites.CONTAINER_HOTSEAT); + + final int indexId = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID); + final int indexItemType = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); + final int indexIntent = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT); + final int indexScreen = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN); + + IntArray entriesToRemove = new IntArray(); + while (c.moveToNext()) { + DbEntry entry = new DbEntry(); + entry.id = c.getInt(indexId); + entry.itemType = c.getInt(indexItemType); + entry.screenId = c.getInt(indexScreen); + + if (entry.screenId >= mHotseatSize) { + entriesToRemove.add(entry.id); + continue; + } + + try { + // calculate weight + switch (entry.itemType) { + case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: + case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: + case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: { + entry.mIntent = c.getString(indexIntent); + verifyIntent(c.getString(indexIntent)); + break; + } + case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: { + int total = getFolderItemsCount(entry); + if (total == 0) { + throw new Exception("Folder is empty"); + } + break; + } + default: + throw new Exception("Invalid item type"); + } + } catch (Exception e) { + if (DEBUG) { + Log.d(TAG, "Removing item " + entry.id, e); + } + entriesToRemove.add(entry.id); + continue; + } + mHotseatEntries.add(entry); + } + removeEntryFromDb(mDb, entriesToRemove); + c.close(); + return mHotseatEntries; + } + + protected ArrayList loadAllWorkspaceEntries() { + Cursor c = queryWorkspace( + new String[]{ + LauncherSettings.Favorites._ID, // 0 + LauncherSettings.Favorites.ITEM_TYPE, // 1 + LauncherSettings.Favorites.SCREEN, // 2 + LauncherSettings.Favorites.CELLX, // 3 + LauncherSettings.Favorites.CELLY, // 4 + LauncherSettings.Favorites.SPANX, // 5 + LauncherSettings.Favorites.SPANY, // 6 + LauncherSettings.Favorites.INTENT, // 7 + LauncherSettings.Favorites.APPWIDGET_PROVIDER, // 8 + LauncherSettings.Favorites.APPWIDGET_ID}, // 9 + LauncherSettings.Favorites.CONTAINER + " = " + + LauncherSettings.Favorites.CONTAINER_DESKTOP); + return loadWorkspaceEntries(c); + } + + protected ArrayList loadWorkspaceEntries(int screen) { + Cursor c = queryWorkspace( + new String[]{ + LauncherSettings.Favorites._ID, // 0 + LauncherSettings.Favorites.ITEM_TYPE, // 1 + LauncherSettings.Favorites.SCREEN, // 2 + LauncherSettings.Favorites.CELLX, // 3 + LauncherSettings.Favorites.CELLY, // 4 + LauncherSettings.Favorites.SPANX, // 5 + LauncherSettings.Favorites.SPANY, // 6 + LauncherSettings.Favorites.INTENT, // 7 + LauncherSettings.Favorites.APPWIDGET_PROVIDER, // 8 + LauncherSettings.Favorites.APPWIDGET_ID}, // 9 + LauncherSettings.Favorites.CONTAINER + " = " + + LauncherSettings.Favorites.CONTAINER_DESKTOP + + " AND " + LauncherSettings.Favorites.SCREEN + " = " + screen); + return loadWorkspaceEntries(c); + } + + private ArrayList loadWorkspaceEntries(Cursor c) { + final int indexId = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID); + final int indexItemType = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); + final int indexScreen = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN); + final int indexCellX = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX); + final int indexCellY = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY); + final int indexSpanX = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX); + final int indexSpanY = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY); + final int indexIntent = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT); + final int indexAppWidgetProvider = c.getColumnIndexOrThrow( + LauncherSettings.Favorites.APPWIDGET_PROVIDER); + final int indexAppWidgetId = c.getColumnIndexOrThrow( + LauncherSettings.Favorites.APPWIDGET_ID); + + IntArray entriesToRemove = new IntArray(); + WidgetManagerHelper widgetManagerHelper = new WidgetManagerHelper(mContext); + while (c.moveToNext()) { + DbEntry entry = new DbEntry(); + entry.id = c.getInt(indexId); + entry.itemType = c.getInt(indexItemType); + entry.screenId = c.getInt(indexScreen); + mLastScreenId = Math.max(mLastScreenId, entry.screenId); + entry.cellX = c.getInt(indexCellX); + entry.cellY = c.getInt(indexCellY); + entry.spanX = c.getInt(indexSpanX); + entry.spanY = c.getInt(indexSpanY); + + try { + // calculate weight + switch (entry.itemType) { + case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: + case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: + case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: { + entry.mIntent = c.getString(indexIntent); + verifyIntent(entry.mIntent); + break; + } + case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: { + entry.mProvider = c.getString(indexAppWidgetProvider); + ComponentName cn = ComponentName.unflattenFromString(entry.mProvider); + verifyPackage(cn.getPackageName()); + + int widgetId = c.getInt(indexAppWidgetId); + LauncherAppWidgetProviderInfo pInfo = + widgetManagerHelper.getLauncherAppWidgetInfo(widgetId); + Point spans = null; + if (pInfo != null) { + spans = pInfo.getMinSpans(); + } + if (spans != null) { + entry.minSpanX = spans.x > 0 ? spans.x : entry.spanX; + entry.minSpanY = spans.y > 0 ? spans.y : entry.spanY; + } else { + // Assume that the widget be resized down to 2x2 + entry.minSpanX = entry.minSpanY = 2; + } + + break; + } + case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: { + int total = getFolderItemsCount(entry); + if (total == 0) { + throw new Exception("Folder is empty"); + } + break; + } + default: + throw new Exception("Invalid item type"); + } + } catch (Exception e) { + if (DEBUG) { + Log.d(TAG, "Removing item " + entry.id, e); + } + entriesToRemove.add(entry.id); + continue; + } + mWorkspaceEntries.add(entry); + } + removeEntryFromDb(mDb, entriesToRemove); + c.close(); + return mWorkspaceEntries; + } + + private int getFolderItemsCount(DbEntry entry) { + Cursor c = queryWorkspace( + new String[]{LauncherSettings.Favorites._ID, LauncherSettings.Favorites.INTENT}, + LauncherSettings.Favorites.CONTAINER + " = " + entry.id); + + int total = 0; + while (c.moveToNext()) { + try { + String intent = c.getString(1); + verifyIntent(intent); + total++; + entry.mFolderItems.add(intent); + } catch (Exception e) { + removeEntryFromDb(mDb, IntArray.wrap(c.getInt(0))); + } + } + c.close(); + return total; + } + + private Cursor queryWorkspace(String[] columns, String where) { + return mDb.query(mTableName, columns, where, null, null, null, null); + } + + /** Verifies if the mIntent should be restored. */ + private void verifyIntent(String intentStr) + throws Exception { + Intent intent = Intent.parseUri(intentStr, 0); + if (intent.getComponent() != null) { + verifyPackage(intent.getComponent().getPackageName()); + } else if (intent.getPackage() != null) { + // Only verify package if the component was null. + verifyPackage(intent.getPackage()); + } + } + + /** Verifies if the package should be restored */ + private void verifyPackage(String packageName) + throws Exception { + if (!mValidPackages.contains(packageName)) { + // TODO(b/151468819): Handle promise app icon restoration during grid migration. + throw new Exception("Package not available"); + } + } + } + + protected static class DbEntry extends ItemInfo implements Comparable { + + private String mIntent; + private String mProvider; + private Set mFolderItems = new HashSet<>(); + + /** Comparator according to the reading order */ + @Override + public int compareTo(DbEntry another) { + if (screenId != another.screenId) { + return Integer.compare(screenId, another.screenId); + } + if (cellY != another.cellY) { + return -Integer.compare(cellY, another.cellY); + } + return Integer.compare(cellX, another.cellX); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DbEntry entry = (DbEntry) o; + return Objects.equals(mIntent, entry.mIntent); + } + + @Override + public int hashCode() { + return Objects.hash(mIntent); + } + + public void updateContentValues(ContentValues values) { + values.put(LauncherSettings.Favorites.SCREEN, screenId); + values.put(LauncherSettings.Favorites.CELLX, cellX); + values.put(LauncherSettings.Favorites.CELLY, cellY); + values.put(LauncherSettings.Favorites.SPANX, spanX); + values.put(LauncherSettings.Favorites.SPANY, spanY); + } + + public String getIntentStr() { + return mIntent; + } + } } diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java index f7ecc3f1d7..dacea84613 100644 --- a/src/com/android/launcher3/provider/LauncherDbUtils.java +++ b/src/com/android/launcher3/provider/LauncherDbUtils.java @@ -118,13 +118,20 @@ public class LauncherDbUtils { db.execSQL("DROP TABLE IF EXISTS " + tableName); } - /** Copy from table to the to table. */ - public static void copyTable(SQLiteDatabase db, String from, String to, Context context) { + /** Copy fromTable in fromDb to toTable in toDb. */ + public static void copyTable(SQLiteDatabase fromDb, String fromTable, SQLiteDatabase toDb, + String toTable, Context context) { long userSerial = UserCache.INSTANCE.get(context).getSerialNumberForUser( Process.myUserHandle()); - dropTable(db, to); - Favorites.addTableToDb(db, userSerial, false, to); - db.execSQL("INSERT INTO " + to + " SELECT * FROM " + from); + dropTable(toDb, toTable); + Favorites.addTableToDb(toDb, userSerial, false, toTable); + if (fromDb != toDb) { + toDb.execSQL("ATTACH DATABASE '" + fromDb.getPath() + "' AS from_db"); + toDb.execSQL( + "INSERT INTO " + toTable + " SELECT * FROM from_db." + fromTable); + } else { + toDb.execSQL("INSERT INTO " + toTable + " SELECT * FROM " + fromTable); + } } /** diff --git a/src/com/android/launcher3/states/StateAnimationConfig.java b/src/com/android/launcher3/states/StateAnimationConfig.java new file mode 100644 index 0000000000..82cde642fa --- /dev/null +++ b/src/com/android/launcher3/states/StateAnimationConfig.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2020 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.states; + +import android.view.animation.Interpolator; + +import androidx.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Utility class for building animator set + */ +public class StateAnimationConfig { + + // We separate the state animations into "atomic" and "non-atomic" components. The atomic + // components may be run atomically - that is, all at once, instead of user-controlled. However, + // atomic components are not restricted to this purpose; they can be user-controlled alongside + // non atomic components as well. Note that each gesture model has exactly one atomic component, + // PLAY_ATOMIC_OVERVIEW_SCALE *or* PLAY_ATOMIC_OVERVIEW_PEEK. + @IntDef(flag = true, value = { + PLAY_NON_ATOMIC, + PLAY_ATOMIC_OVERVIEW_SCALE, + PLAY_ATOMIC_OVERVIEW_PEEK, + SKIP_OVERVIEW, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AnimationFlags {} + public static final int PLAY_NON_ATOMIC = 1 << 0; + public static final int PLAY_ATOMIC_OVERVIEW_SCALE = 1 << 1; + public static final int PLAY_ATOMIC_OVERVIEW_PEEK = 1 << 2; + public static final int SKIP_OVERVIEW = 1 << 3; + + public long duration; + public boolean userControlled; + public @AnimationFlags int animFlags = ANIM_ALL_COMPONENTS; + + public static final int ANIM_ALL_COMPONENTS = PLAY_NON_ATOMIC | PLAY_ATOMIC_OVERVIEW_SCALE + | PLAY_ATOMIC_OVERVIEW_PEEK; + + // Various types of animation state transition + @IntDef(value = { + ANIM_VERTICAL_PROGRESS, + ANIM_WORKSPACE_SCALE, + ANIM_WORKSPACE_TRANSLATE, + ANIM_WORKSPACE_FADE, + ANIM_HOTSEAT_SCALE, + ANIM_HOTSEAT_TRANSLATE, + ANIM_OVERVIEW_SCALE, + ANIM_OVERVIEW_TRANSLATE_X, + ANIM_OVERVIEW_TRANSLATE_Y, + ANIM_OVERVIEW_FADE, + ANIM_ALL_APPS_FADE, + ANIM_OVERVIEW_SCRIM_FADE, + ANIM_ALL_APPS_HEADER_FADE, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AnimType {} + public static final int ANIM_VERTICAL_PROGRESS = 0; + public static final int ANIM_WORKSPACE_SCALE = 1; + public static final int ANIM_WORKSPACE_TRANSLATE = 2; + public static final int ANIM_WORKSPACE_FADE = 3; + public static final int ANIM_HOTSEAT_SCALE = 4; + public static final int ANIM_HOTSEAT_TRANSLATE = 5; + public static final int ANIM_OVERVIEW_SCALE = 6; + public static final int ANIM_OVERVIEW_TRANSLATE_X = 7; + public static final int ANIM_OVERVIEW_TRANSLATE_Y = 8; + public static final int ANIM_OVERVIEW_FADE = 9; + public static final int ANIM_ALL_APPS_FADE = 10; + public static final int ANIM_OVERVIEW_SCRIM_FADE = 11; + public static final int ANIM_ALL_APPS_HEADER_FADE = 12; // e.g. predictions + + private static final int ANIM_TYPES_COUNT = 13; + + private final Interpolator[] mInterpolators = new Interpolator[ANIM_TYPES_COUNT]; + + public StateAnimationConfig() { } + + /** + * Copies the config to target + */ + public void copyTo(StateAnimationConfig target) { + target.duration = duration; + target.animFlags = animFlags; + target.userControlled = userControlled; + for (int i = 0; i < ANIM_TYPES_COUNT; i++) { + target.mInterpolators[i] = mInterpolators[i]; + } + } + + /** + * Returns the interpolator set for animId or fallback if nothing is set + * + * @see #setInterpolator(int, Interpolator) + */ + public Interpolator getInterpolator(@AnimType int animId, Interpolator fallback) { + return mInterpolators[animId] == null ? fallback : mInterpolators[animId]; + } + + /** + * Sets an interpolator for a given animation type + */ + public void setInterpolator(@AnimType int animId, Interpolator interpolator) { + mInterpolators[animId] = interpolator; + } + + /** + * @return Whether Overview is scaling as part of this animation. If this is the only + * component (i.e. NON_ATOMIC_COMPONENT isn't included), then this scaling is happening + * atomically, rather than being part of a normal state animation. StateHandlers can use + * this to designate part of their animation that should scale with Overview. + */ + public boolean playAtomicOverviewScaleComponent() { + return hasAnimationFlag(StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE); + } + + /** + * @return Whether this animation will play atomically at the same time as a different, + * user-controlled state transition. StateHandlers, which contribute to both animations, can + * use this to avoid animating the same properties in both animations, since they'd conflict + * with one another. + */ + public boolean onlyPlayAtomicComponent() { + return getAnimComponents() == StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE + || getAnimComponents() == StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK; + } + + /** + * Returns true if the config and any of the provided component flags + */ + public boolean hasAnimationFlag(@AnimationFlags int a) { + return (animFlags & a) != 0; + } + + /** + * @return Only the flags that determine which animation components to play. + */ + public @AnimationFlags int getAnimComponents() { + return animFlags & StateAnimationConfig.ANIM_ALL_COMPONENTS; + } +} diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java index c3664c3569..1d14a8f039 100644 --- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java @@ -19,11 +19,11 @@ import static com.android.launcher3.LauncherAnimUtils.MIN_PROGRESS_TO_ALL_APPS; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; -import static com.android.launcher3.LauncherStateManager.ANIM_ALL_COMPONENTS; -import static com.android.launcher3.LauncherStateManager.PLAY_ATOMIC_OVERVIEW_SCALE; -import static com.android.launcher3.LauncherStateManager.PLAY_NON_ATOMIC; import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity; import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS; +import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE; +import static com.android.launcher3.states.StateAnimationConfig.PLAY_NON_ATOMIC; import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs; import android.animation.Animator; @@ -37,12 +37,12 @@ import android.view.MotionEvent; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.LauncherState; -import com.android.launcher3.LauncherStateManager.AnimationFlags; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; -import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.states.StateAnimationConfig; +import com.android.launcher3.states.StateAnimationConfig.AnimationFlags; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; @@ -358,14 +358,18 @@ public abstract class AbstractStateChangeTouchController private AnimatorSet createAtomicAnimForState(LauncherState fromState, LauncherState targetState, long duration) { - AnimatorSetBuilder builder = getAnimatorSetBuilderForStates(fromState, targetState); - return mLauncher.getStateManager().createAtomicAnimation(fromState, targetState, builder, - PLAY_ATOMIC_OVERVIEW_SCALE, duration); + StateAnimationConfig config = getConfigForStates(fromState, targetState); + config.animFlags = PLAY_ATOMIC_OVERVIEW_SCALE; + config.duration = duration; + return mLauncher.getStateManager().createAtomicAnimation(fromState, targetState, config); } - protected AnimatorSetBuilder getAnimatorSetBuilderForStates(LauncherState fromState, - LauncherState toState) { - return new AnimatorSetBuilder(); + /** + * Returns animation config for state transition between provided states + */ + protected StateAnimationConfig getConfigForStates( + LauncherState fromState, LauncherState toState) { + return new StateAnimationConfig(); } @Override diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java index 8d5f33da9c..4a202b65d8 100644 --- a/src/com/android/launcher3/touch/AllAppsSwipeController.java +++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java @@ -23,7 +23,7 @@ import android.view.MotionEvent; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; -import com.android.launcher3.LauncherStateManager.AnimationFlags; +import com.android.launcher3.states.StateAnimationConfig.AnimationFlags; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; /** diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java index a7078a2f59..8d1a3b01d5 100644 --- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java +++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java @@ -16,8 +16,8 @@ package com.android.launcher3.widget; -import android.animation.Animator; -import android.animation.ObjectAnimator; +import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; + import android.animation.PropertyValuesHolder; import android.content.Context; import android.graphics.Rect; @@ -28,16 +28,15 @@ import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.animation.Interpolator; import android.widget.TextView; -import androidx.annotation.Nullable; - import com.android.launcher3.Insettable; import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.ResourceUtils; -import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.model.WidgetItem; import com.android.launcher3.util.PackageUserKey; @@ -156,7 +155,7 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable { setupNavBarColor(); mOpenCloseAnimator.setValues( PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED)); - mOpenCloseAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); + mOpenCloseAnimator.setInterpolator(FAST_OUT_SLOW_IN); mOpenCloseAnimator.start(); } @@ -191,9 +190,9 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable { mIsOpen ? R.string.widgets_list : R.string.widgets_list_closed)); } - @Nullable @Override - public Animator createHintCloseAnim(float distanceToMove) { - return ObjectAnimator.ofInt(this, PADDING_BOTTOM, (int) (distanceToMove + mInsets.bottom)); + public void addHintCloseAnim( + float distanceToMove, Interpolator interpolator, PendingAnimation target) { + target.setInt(this, PADDING_BOTTOM, (int) (distanceToMove + mInsets.bottom), interpolator); } } diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java index 2a102d24e4..b07a4f461d 100644 --- a/src/com/android/launcher3/widget/WidgetsFullSheet.java +++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java @@ -15,12 +15,11 @@ */ package com.android.launcher3.widget; +import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y; import static com.android.launcher3.testing.TestProtocol.NORMAL_STATE_ORDINAL; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.content.Context; import android.graphics.Rect; @@ -30,8 +29,8 @@ import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; -import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.launcher3.Insettable; @@ -39,6 +38,7 @@ import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener; import com.android.launcher3.R; +import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.views.RecyclerViewFastScroller; import com.android.launcher3.views.TopRoundedCornerView; @@ -242,13 +242,11 @@ public class WidgetsFullSheet extends BaseWidgetSheet return mAdapter.getItemCount(); } - @Nullable @Override - public Animator createHintCloseAnim(float distanceToMove) { - AnimatorSet anim = new AnimatorSet(); - anim.play(ObjectAnimator.ofFloat(mRecyclerView, TRANSLATION_Y, -distanceToMove)); - anim.play(ObjectAnimator.ofFloat(mRecyclerView, ALPHA, 0.5f)); - return anim; + public void addHintCloseAnim( + float distanceToMove, Interpolator interpolator, PendingAnimation target) { + target.setFloat(mRecyclerView, VIEW_TRANSLATE_Y, -distanceToMove, interpolator); + target.setViewAlpha(mRecyclerView, 0.5f, interpolator); } @Override diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/BackgroundBlurController.java b/src_ui_overrides/com/android/launcher3/uioverrides/BackgroundBlurController.java index 232bad3be7..75f99a9ee9 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/BackgroundBlurController.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/BackgroundBlurController.java @@ -19,10 +19,12 @@ package com.android.launcher3.uioverrides; import android.util.IntProperty; import android.view.View; + import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager; -import com.android.launcher3.anim.AnimatorSetBuilder; +import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.states.StateAnimationConfig; /** * Controls the blur, for the Launcher surface only. @@ -52,6 +54,6 @@ public class BackgroundBlurController implements LauncherStateManager.StateHandl public void setState(LauncherState toState) {} @Override - public void setStateWithAnimation(LauncherState toState, AnimatorSetBuilder builder, - LauncherStateManager.AnimationConfig config) {} + public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config, + PendingAnimation animation) { } } diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/PreviewSurfaceRenderer.java b/src_ui_overrides/com/android/launcher3/uioverrides/PreviewSurfaceRenderer.java new file mode 100644 index 0000000000..4913cadb5a --- /dev/null +++ b/src_ui_overrides/com/android/launcher3/uioverrides/PreviewSurfaceRenderer.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020 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.uioverrides; + +import android.content.Context; +import android.os.Bundle; + +/** Render preview using surface view. */ +public class PreviewSurfaceRenderer { + + /** Handle a received surface view request. */ + public static void render(Context context, Bundle bundle) { } +}