diff --git a/Android.mk b/Android.mk index 9cfcf17b99..fcd4a94efc 100644 --- a/Android.mk +++ b/Android.mk @@ -129,6 +129,7 @@ LOCAL_AAPT2_ONLY := true LOCAL_MODULE_TAGS := optional LOCAL_STATIC_JAVA_LIBRARIES := \ + SystemUI-statsd \ SystemUISharedLib \ launcherprotosnano \ launcher_log_protos_lite @@ -201,6 +202,7 @@ LOCAL_USE_AAPT2 := true LOCAL_MODULE_TAGS := optional LOCAL_STATIC_JAVA_LIBRARIES := \ + SystemUI-statsd \ SystemUISharedLib \ launcherprotosnano \ launcher_log_protos_lite diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto index 036fb02243..cac2d8f5a7 100644 --- a/protos/launcher_atom.proto +++ b/protos/launcher_atom.proto @@ -26,6 +26,7 @@ message ItemInfo { Task task = 2; Shortcut shortcut = 3; Widget widget = 4; + FolderIcon folder_icon = 9; } // When used for launch event, stores the global predictive rank optional int32 rank = 5; @@ -92,6 +93,11 @@ message Task { optional int32 index = 3; } +// Represents folder in a closed state. +message FolderIcon { + optional int32 cardinality = 1; +} + ////////////////////////////////////////////// // Containers diff --git a/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml b/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml index c93cad65bf..b9621e489f 100644 --- a/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml +++ b/quickstep/recents_ui_overrides/res/layout/predicted_hotseat_edu.xml @@ -24,13 +24,13 @@ { - float progress = (Float) anim.getAnimatedValue(); - if (progress >= overviewProgress || mLauncher.isInState(BACKGROUND_APP)) { - float hotseatShift = (progress - overviewProgress) * shiftRange; - mLauncher.getHotseat().setTranslationY(hotseatShift + sat.translationY); - } - }); - hotseatAnim.setInterpolator(LINEAR); - hotseatAnim.setDuration(springAnim.getDuration()); - - AnimatorSet anim = new AnimatorSet(); - anim.play(hotseatAnim); - anim.play(springAnim); - return anim; - } - - return springAnim; - } - case INDEX_RECENTS_FADE_ANIM: - return ObjectAnimator.ofFloat(mLauncher.getOverviewPanel(), - RecentsView.CONTENT_ALPHA, values); - case INDEX_RECENTS_TRANSLATE_X_ANIM: { - RecentsView rv = mLauncher.getOverviewPanel(); - return new SpringAnimationBuilder(mLauncher) - .setMinimumVisibleChange(1f / rv.getPageOffsetScale()) - .setDampingRatio(0.8f) - .setStiffness(250) - .setValues(values) - .build(rv, ADJACENT_PAGE_OFFSET); - } - case INDEX_PAUSE_TO_OVERVIEW_ANIM: { - 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) { - 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, config); - } - - default: - return super.createStateElementAnimation(index, values); - } - } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java index d93aea44a7..8477b103a2 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java @@ -26,10 +26,10 @@ import android.os.UserManager; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; -import com.android.launcher3.LauncherStateManager; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.FloatingHeaderView; +import com.android.launcher3.statemanager.StateManager.StateListener; import com.android.launcher3.views.ArrowTipView; import com.android.systemui.shared.system.LauncherEventUtil; @@ -71,17 +71,16 @@ public class AllAppsTipView { public static void scheduleShowIfNeeded(Launcher launcher) { if (!hasSeenAllAppsTip(launcher)) { - launcher.getStateManager().addStateListener( - new LauncherStateManager.StateListener() { - @Override - public void onStateTransitionComplete(LauncherState finalState) { - if (finalState == ALL_APPS) { - if (showAllAppsTipIfNecessary(launcher)) { - launcher.getStateManager().removeStateListener(this); - } - } + launcher.getStateManager().addStateListener(new StateListener() { + @Override + public void onStateTransitionComplete(LauncherState finalState) { + if (finalState == ALL_APPS) { + if (showAllAppsTipIfNecessary(launcher)) { + launcher.getStateManager().removeStateListener(this); } - }); + } + } + }); } } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java index 81a6070664..914d9e9774 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java @@ -38,18 +38,18 @@ import androidx.core.content.ContextCompat; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; -import com.android.launcher3.LauncherStateManager; import com.android.launcher3.R; import com.android.launcher3.allapps.FloatingHeaderRow; import com.android.launcher3.allapps.FloatingHeaderView; import com.android.launcher3.anim.PropertySetter; +import com.android.launcher3.statemanager.StateManager.StateListener; import com.android.launcher3.util.Themes; /** * A view which shows a horizontal divider */ @TargetApi(Build.VERSION_CODES.O) -public class AppsDividerView extends View implements LauncherStateManager.StateListener, +public class AppsDividerView extends View implements StateListener, FloatingHeaderRow { private static final String ALL_APPS_VISITED_COUNT = "launcher.all_apps_visited_count"; diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java index e68627a8f6..ab3c71ae86 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java @@ -32,7 +32,6 @@ import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherState; -import com.android.launcher3.LauncherStateManager.StateListener; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.AllAppsContainerView; import com.android.launcher3.allapps.AllAppsStore.OnUpdateListener; @@ -41,6 +40,7 @@ import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.shortcuts.ShortcutKey; +import com.android.launcher3.statemanager.StateManager.StateListener; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.MainThreadInitializedObject; @@ -63,8 +63,8 @@ import java.util.stream.IntStream; * 4) Maintains the current active client id (for the predictions) and all updates are performed on * that client id. */ -public class PredictionUiStateManager implements StateListener, ItemInfoUpdateReceiver, - OnIDPChangeListener, OnUpdateListener { +public class PredictionUiStateManager implements StateListener, + ItemInfoUpdateReceiver, OnIDPChangeListener, OnUpdateListener { public static final String LAST_PREDICTION_ENABLED_STATE = "last_prediction_enabled_state"; diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java index 752068843c..676114860c 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java @@ -46,6 +46,7 @@ import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.touch.ItemLongClickListener; +import com.android.launcher3.util.SafeCloseable; import com.android.launcher3.views.DoubleShadowBubbleTextView; /** @@ -65,6 +66,7 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView implements private final int mNormalizedIconRadius; private final BlurMaskFilter mShadowFilter; private int mPlateColor; + boolean mDrawForDrag = false; public PredictedAppIcon(Context context) { @@ -188,6 +190,10 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView implements } private void drawEffect(Canvas canvas, boolean isBadged) { + // Don't draw ring effect if item is about to be dragged. + if (mDrawForDrag) { + return; + } mRingPath.reset(); getShape().addToPath(mRingPath, getOutlineOffsetX(), getOutlineOffsetY(), mNormalizedIconRadius); @@ -208,6 +214,26 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView implements canvas.drawPath(mRingPath, mIconRingPaint); } + @Override + public void getSourceVisualDragBounds(Rect bounds) { + super.getSourceVisualDragBounds(bounds); + if (!mIsPinned) { + int internalSize = (int) (bounds.width() * RING_EFFECT_RATIO); + bounds.inset(internalSize, internalSize); + } + } + + @Override + public SafeCloseable prepareDrawDragView() { + mDrawForDrag = true; + invalidate(); + SafeCloseable r = super.prepareDrawDragView(); + return () -> { + r.close(); + mDrawForDrag = false; + }; + } + /** * Creates and returns a new instance of PredictedAppIcon from WorkspaceItemInfo */ diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 8ef9d04d63..70addb5a39 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -30,6 +30,7 @@ import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; +import android.util.Log; import android.view.View; import androidx.annotation.Nullable; @@ -48,6 +49,9 @@ import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.SystemShortcut; +import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory; +import com.android.launcher3.testing.TestProtocol; +import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory; import com.android.launcher3.uioverrides.touchcontrollers.FlingAndHoldTouchController; import com.android.launcher3.uioverrides.touchcontrollers.LandscapeEdgeSwipeController; import com.android.launcher3.uioverrides.touchcontrollers.NavBarToHomeTouchController; @@ -243,6 +247,9 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { @Override public TouchController[] createTouchControllers() { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.PAUSE_NOT_DETECTED, "createTouchControllers.1"); + } Mode mode = SysUINavigationMode.getMode(this); ArrayList list = new ArrayList<>(); @@ -250,7 +257,13 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { if (mode == NO_BUTTON) { list.add(new NoButtonQuickSwitchTouchController(this)); list.add(new NavBarToHomeTouchController(this)); + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.PAUSE_NOT_DETECTED, "createTouchControllers.2"); + } if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.PAUSE_NOT_DETECTED, "createTouchControllers.3"); + } list.add(new NoButtonNavbarToOverviewTouchController(this)); } else { list.add(new FlingAndHoldTouchController(this)); @@ -279,6 +292,11 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { return list.toArray(new TouchController[list.size()]); } + @Override + public AtomicAnimationFactory createAtomicAnimationFactory() { + return new QuickstepAtomicAnimationFactory(this); + } + private static final class LauncherTaskViewController extends TaskViewTouchController { diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java index 357e9ecd6f..fa0d3f347b 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java @@ -17,6 +17,7 @@ package com.android.launcher3.uioverrides.states; import android.content.Context; +import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.Launcher; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.userevent.nano.LauncherLogProto; @@ -54,11 +55,7 @@ public class BackgroundAppState extends OverviewState { @Override public float[] getOverviewScaleAndOffset(Launcher launcher) { - return new float[] {getOverviewScale(launcher), NO_OFFSET}; - } - - private float getOverviewScale(Launcher launcher) { - return ((RecentsView) launcher.getOverviewPanel()).getMaxScaleForFullScreen(); + return getOverviewScaleAndOffsetForBackgroundState(launcher); } @Override @@ -88,4 +85,11 @@ public class BackgroundAppState extends OverviewState { protected float getDepthUnchecked(Context context) { return 1f; } + + public static float[] getOverviewScaleAndOffsetForBackgroundState( + BaseDraggingActivity activity) { + return new float[] { + ((RecentsView) activity.getOverviewPanel()).getMaxScaleForFullScreen(), + NO_OFFSET}; + } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java index 4e868b0c1b..0be248691e 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java @@ -19,8 +19,8 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; +import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.Launcher; -import com.android.launcher3.R; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.quickstep.views.RecentsView; @@ -49,22 +49,25 @@ public class OverviewModalTaskState extends OverviewState { @Override public float[] getOverviewScaleAndOffset(Launcher launcher) { - Resources res = launcher.getBaseContext().getResources(); - - Rect out = new Rect(); - launcher.getOverviewPanel().getTaskSize(out); - int taskHeight = out.height(); - - float topMargin = res.getDimension(R.dimen.task_thumbnail_top_margin); - float bottomMargin = res.getDimension(R.dimen.task_thumbnail_bottom_margin_with_actions); - float newHeight = taskHeight + topMargin + bottomMargin; - float scale = newHeight / taskHeight; - - return new float[] {scale, 0}; + return getOverviewScaleAndOffsetForModalState(launcher); } @Override public float getOverviewModalness() { return 1.0f; } + + public static float[] getOverviewScaleAndOffsetForModalState(BaseDraggingActivity activity) { + Resources res = activity.getResources(); + + Rect out = new Rect(); + activity.getOverviewPanel().getTaskSize(out); + int taskHeight = out.height(); + activity.getOverviewPanel().getModalTaskSize(out); + int newHeight = out.height(); + + float scale = (float) newHeight / taskHeight; + + return new float[] {scale, NO_OFFSET}; + } } 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 b27f16ac08..fc9a11bf66 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 @@ -15,16 +15,7 @@ */ package com.android.launcher3.uioverrides.states; -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.states.StateAnimationConfig; public class OverviewPeekState extends OverviewState { private static final float OVERVIEW_OFFSET = 0.7f; @@ -37,14 +28,4 @@ public class OverviewPeekState extends OverviewState { public float[] getOverviewScaleAndOffset(Launcher launcher) { return new float[] {NO_SCALE, OVERVIEW_OFFSET}; } - - @Override - public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState, - StateAnimationConfig config) { - if (this == OVERVIEW_PEEK && fromState == NORMAL) { - 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 6f572819a1..9f31608ad7 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 @@ -15,36 +15,21 @@ */ 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.Interpolators.ACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL_2; -import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2; -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.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; import android.content.Context; import android.graphics.Rect; import android.view.View; -import android.view.animation.Interpolator; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.Workspace; -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; @@ -57,9 +42,6 @@ import com.android.quickstep.views.TaskView; */ public class OverviewState extends LauncherState { - // Scale recents takes before animating in - private static final float RECENTS_PREPARE_SCALE = 1.33f; - protected static final Rect sTempRect = new Rect(); private static final int STATE_FLAGS = FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED @@ -202,35 +184,6 @@ public class OverviewState extends LauncherState { } } - @Override - public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState, - StateAnimationConfig config) { - if ((fromState == NORMAL || fromState == HINT_STATE) && this == OVERVIEW) { - if (SysUINavigationMode.getMode(launcher) == NO_BUTTON) { - config.setInterpolator(ANIM_WORKSPACE_SCALE, - fromState == NORMAL ? ACCEL : OVERSHOOT_1_2); - config.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL); - } else { - config.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2); - - // Scale up the recents, if it is not coming from the side - RecentsView overview = launcher.getOverviewPanel(); - if (overview.getVisibility() != VISIBLE || overview.getContentAlpha() == 0) { - SCALE_PROPERTY.set(overview, RECENTS_PREPARE_SCALE); - } - } - 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; - config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, translationInterpolator); - config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, translationInterpolator); - config.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2); - } - } - public static OverviewState newBackgroundState(int id) { return new BackgroundAppState(id); } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java new file mode 100644 index 0000000000..11593a16c1 --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java @@ -0,0 +1,236 @@ +/* + * 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.states; + +import static android.view.View.VISIBLE; + +import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; +import static com.android.launcher3.LauncherState.BACKGROUND_APP; +import static com.android.launcher3.LauncherState.HINT_STATE; +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.OVERVIEW_PEEK; +import static com.android.launcher3.anim.Interpolators.ACCEL; +import static com.android.launcher3.anim.Interpolators.DEACCEL; +import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7; +import static com.android.launcher3.anim.Interpolators.DEACCEL_3; +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.LINEAR; +import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2; +import static com.android.launcher3.anim.Interpolators.OVERSHOOT_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.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_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.ANIM_VERTICAL_PROGRESS; +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; +import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET; + +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.view.View; +import android.view.animation.Interpolator; + +import com.android.launcher3.CellLayout; +import com.android.launcher3.Hotseat; +import com.android.launcher3.LauncherState; +import com.android.launcher3.LauncherState.ScaleAndTranslation; +import com.android.launcher3.Workspace; +import com.android.launcher3.allapps.AllAppsContainerView; +import com.android.launcher3.allapps.AllAppsTransitionController; +import com.android.launcher3.anim.SpringAnimationBuilder; +import com.android.launcher3.statemanager.StateManager; +import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory; +import com.android.launcher3.states.StateAnimationConfig; +import com.android.launcher3.uioverrides.QuickstepLauncher; +import com.android.quickstep.SysUINavigationMode; +import com.android.quickstep.views.RecentsView; + +/** + * Animation factory for quickstep specific transitions + */ +public class QuickstepAtomicAnimationFactory extends AtomicAnimationFactory { + + // Scale recents takes before animating in + private static final float RECENTS_PREPARE_SCALE = 1.33f; + + public static final int INDEX_SHELF_ANIM = 0; + public static final int INDEX_RECENTS_FADE_ANIM = 1; + public static final int INDEX_RECENTS_TRANSLATE_X_ANIM = 2; + public static final int INDEX_PAUSE_TO_OVERVIEW_ANIM = 3; + private static final int ANIM_COUNT = 4; + + public static final long ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW = 300; + + private final QuickstepLauncher mLauncher; + + public QuickstepAtomicAnimationFactory(QuickstepLauncher launcher) { + super(ANIM_COUNT); + mLauncher = launcher; + } + + @Override + public Animator createStateElementAnimation(int index, float... values) { + switch (index) { + case INDEX_SHELF_ANIM: { + AllAppsTransitionController aatc = mLauncher.getAllAppsController(); + Animator springAnim = aatc.createSpringAnimation(values); + + if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) { + // Translate hotseat with the shelf until reaching overview. + float overviewProgress = OVERVIEW.getVerticalProgress(mLauncher); + ScaleAndTranslation sat = OVERVIEW.getHotseatScaleAndTranslation(mLauncher); + float shiftRange = aatc.getShiftRange(); + if (values.length == 1) { + values = new float[] {aatc.getProgress(), values[0]}; + } + ValueAnimator hotseatAnim = ValueAnimator.ofFloat(values); + hotseatAnim.addUpdateListener(anim -> { + float progress = (Float) anim.getAnimatedValue(); + if (progress >= overviewProgress || mLauncher.isInState(BACKGROUND_APP)) { + float hotseatShift = (progress - overviewProgress) * shiftRange; + mLauncher.getHotseat().setTranslationY(hotseatShift + sat.translationY); + } + }); + hotseatAnim.setInterpolator(LINEAR); + hotseatAnim.setDuration(springAnim.getDuration()); + + AnimatorSet anim = new AnimatorSet(); + anim.play(hotseatAnim); + anim.play(springAnim); + return anim; + } + + return springAnim; + } + case INDEX_RECENTS_FADE_ANIM: + return ObjectAnimator.ofFloat(mLauncher.getOverviewPanel(), + RecentsView.CONTENT_ALPHA, values); + case INDEX_RECENTS_TRANSLATE_X_ANIM: { + RecentsView rv = mLauncher.getOverviewPanel(); + return new SpringAnimationBuilder(mLauncher) + .setMinimumVisibleChange(1f / rv.getPageOffsetScale()) + .setDampingRatio(0.8f) + .setStiffness(250) + .setValues(values) + .build(rv, ADJACENT_PAGE_OFFSET); + } + case INDEX_PAUSE_TO_OVERVIEW_ANIM: { + 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) { + config.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2); + config.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2); + } + + StateManager stateManager = mLauncher.getStateManager(); + return stateManager.createAtomicAnimation( + stateManager.getCurrentStableState(), OVERVIEW, config); + } + + default: + return super.createStateElementAnimation(index, values); + } + } + + @Override + public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toState, + StateAnimationConfig config) { + if (toState == NORMAL && fromState == OVERVIEW) { + 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 = mLauncher.getWorkspace(); + + // Start from a higher workspace scale, but only if we're invisible so we don't jump. + boolean isWorkspaceVisible = workspace.getVisibility() == VISIBLE; + if (isWorkspaceVisible) { + CellLayout currentChild = (CellLayout) workspace.getChildAt( + workspace.getCurrentPage()); + isWorkspaceVisible = currentChild.getVisibility() == VISIBLE + && currentChild.getShortcutsAndWidgets().getAlpha() > 0; + } + if (!isWorkspaceVisible) { + workspace.setScaleX(0.92f); + workspace.setScaleY(0.92f); + } + Hotseat hotseat = mLauncher.getHotseat(); + boolean isHotseatVisible = hotseat.getVisibility() == VISIBLE && hotseat.getAlpha() > 0; + if (!isHotseatVisible) { + hotseat.setScaleX(0.92f); + hotseat.setScaleY(0.92f); + if (ENABLE_OVERVIEW_ACTIONS.get()) { + AllAppsContainerView qsbContainer = mLauncher.getAppsView(); + View qsb = qsbContainer.getSearchView(); + boolean qsbVisible = qsb.getVisibility() == VISIBLE && qsb.getAlpha() > 0; + if (!qsbVisible) { + qsbContainer.setScaleX(0.92f); + qsbContainer.setScaleY(0.92f); + } + } + } + } else if (toState == NORMAL && fromState == OVERVIEW_PEEK) { + // Keep fully visible until the very end (when overview is offscreen) to make invisible. + config.setInterpolator(ANIM_OVERVIEW_FADE, t -> t < 1 ? 0 : 1); + } else if (toState == OVERVIEW_PEEK && fromState == NORMAL) { + 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); + } else if ((fromState == NORMAL || fromState == HINT_STATE) && toState == OVERVIEW) { + if (SysUINavigationMode.getMode(mLauncher) == NO_BUTTON) { + config.setInterpolator(ANIM_WORKSPACE_SCALE, + fromState == NORMAL ? ACCEL : OVERSHOOT_1_2); + config.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL); + } else { + config.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2); + + // Scale up the recents, if it is not coming from the side + RecentsView overview = mLauncher.getOverviewPanel(); + if (overview.getVisibility() != VISIBLE || overview.getContentAlpha() == 0) { + SCALE_PROPERTY.set(overview, RECENTS_PREPARE_SCALE); + } + } + config.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2); + config.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2); + Interpolator translationInterpolator = ENABLE_OVERVIEW_ACTIONS.get() + && removeShelfFromOverview(mLauncher) + ? OVERSHOOT_1_2 + : OVERSHOOT_1_7; + 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 8af2747352..fac478e777 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 @@ -16,7 +16,6 @@ package com.android.launcher3.uioverrides.touchcontrollers; -import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_PAUSE_TO_OVERVIEW_ANIM; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; @@ -31,23 +30,26 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_S 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.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_PAUSE_TO_OVERVIEW_ANIM; import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; +import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherAppTransitionManagerImpl; import com.android.launcher3.LauncherState; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.states.StateAnimationConfig.AnimationFlags; +import com.android.launcher3.testing.TestProtocol; +import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.util.VibratorWrapper; import com.android.quickstep.SystemUiProxy; @@ -82,7 +84,7 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { @Override protected long getAtomicDuration() { - return LauncherAppTransitionManagerImpl.ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW; + return QuickstepAtomicAnimationFactory.ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW; } @Override @@ -178,6 +180,9 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { @Override public boolean onDrag(float displacement, MotionEvent event) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.PAUSE_NOT_DETECTED, "FlingAndHoldTouchController"); + } float upDisplacement = -displacement; mMotionPauseDetector.setDisallowPause(!handlingOverviewAnim() || upDisplacement < mMotionPauseMinDisplacement @@ -206,8 +211,8 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { mPeekAnim.cancel(); } - Animator overviewAnim = mLauncher.getAppTransitionManager().createStateElementAnimation( - INDEX_PAUSE_TO_OVERVIEW_ANIM); + Animator overviewAnim = mLauncher.createAtomicAnimationFactory() + .createStateElementAnimation(INDEX_PAUSE_TO_OVERVIEW_ANIM); mAtomicAnim = new AnimatorSet(); mAtomicAnim.addListener(new AnimationSuccessListener() { @Override 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 06a481b90d..bf0690c77d 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 @@ -25,6 +25,7 @@ import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; import android.animation.ValueAnimator; +import android.util.Log; import android.view.MotionEvent; import android.view.animation.Interpolator; @@ -41,6 +42,7 @@ 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.testing.TestProtocol; import com.android.launcher3.touch.SingleAxisSwipeDetector; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; @@ -94,18 +96,37 @@ public class NavBarToHomeTouchController implements TouchController, } private boolean canInterceptTouch(MotionEvent ev) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.PAUSE_NOT_DETECTED, "NavBarToHomeTouchController.canInterceptTouch " + + ev); + } boolean cameFromNavBar = (ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) != 0; if (!cameFromNavBar) { return false; } if (mStartState.overviewUi || mStartState == ALL_APPS) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.PAUSE_NOT_DETECTED, + "NavBarToHomeTouchController.canInterceptTouch true 1 " + + mStartState.overviewUi + " " + (mStartState == ALL_APPS)); + } return true; } if (AbstractFloatingView.getTopOpenView(mLauncher) != null) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.PAUSE_NOT_DETECTED, + "NavBarToHomeTouchController.canInterceptTouch true 2 " + + AbstractFloatingView.getTopOpenView(mLauncher).getClass() + .getSimpleName()); + } return true; } if (FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS.get() && AssistantUtilities.isExcludedAssistantRunning()) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.PAUSE_NOT_DETECTED, + "NavBarToHomeTouchController.canInterceptTouch true 3"); + } return true; } return false; 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 381ecf1c4b..966e25bff5 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 @@ -27,14 +27,16 @@ import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC; import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.graphics.PointF; +import android.util.Log; import android.view.MotionEvent; import com.android.launcher3.Launcher; 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.statemanager.StateManager; import com.android.launcher3.states.StateAnimationConfig; +import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.util.VibratorWrapper; import com.android.quickstep.util.StaggeredWorkspaceAnim; @@ -63,6 +65,9 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo public NoButtonNavbarToOverviewTouchController(Launcher l) { super(l); mRecentsView = l.getOverviewPanel(); + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.PAUSE_NOT_DETECTED, "NoButtonNavbarToOverviewTouchController.ctor"); + } } @Override @@ -146,6 +151,9 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo @Override public boolean onDrag(float yDisplacement, float xDisplacement, MotionEvent event) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.PAUSE_NOT_DETECTED, "NoButtonNavbarToOverviewTouchController"); + } if (mMotionPauseDetector.isPaused()) { if (!mReachedOverview) { mStartDisplacement.set(xDisplacement, yDisplacement); @@ -165,7 +173,7 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo protected void goToOverviewOnDragEnd(float velocity) { float velocityDp = dpiFromPx(velocity); boolean isFling = Math.abs(velocityDp) > 1; - LauncherStateManager stateManager = mLauncher.getStateManager(); + StateManager stateManager = mLauncher.getStateManager(); boolean goToHomeInsteadOfOverview = isFling; if (goToHomeInsteadOfOverview) { if (velocity > 0) { 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 f4f8bc9ecb..7385658976 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 @@ -16,7 +16,6 @@ package com.android.launcher3.uioverrides.touchcontrollers; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; -import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_PAUSE_TO_OVERVIEW_ANIM; import static com.android.launcher3.LauncherState.HOTSEAT_ICONS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; @@ -35,6 +34,7 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_T 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.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_PAUSE_TO_OVERVIEW_ANIM; import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs; import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC; import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.CANCEL; @@ -312,8 +312,8 @@ public class NoButtonQuickSwitchTouchController implements TouchController, if (mMotionPauseDetector.isPaused() && noFling) { cancelAnimations(); - Animator overviewAnim = mLauncher.getAppTransitionManager().createStateElementAnimation( - INDEX_PAUSE_TO_OVERVIEW_ANIM); + Animator overviewAnim = mLauncher.createAtomicAnimationFactory() + .createStateElementAnimation(INDEX_PAUSE_TO_OVERVIEW_ANIM); overviewAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { 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 1f3b82cd98..0ee5d047c6 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 @@ -58,6 +58,7 @@ public abstract class TaskViewTouchController private final SingleAxisSwipeDetector mDetector; private final RecentsView mRecentsView; private final int[] mTempCords = new int[2]; + private final boolean mIsRtl; private PendingAnimation mPendingAnimation; private AnimatorPlaybackController mCurrentAnimation; @@ -75,6 +76,7 @@ public abstract class TaskViewTouchController public TaskViewTouchController(T activity) { mActivity = activity; mRecentsView = activity.getOverviewPanel(); + mIsRtl = Utilities.isRtl(activity.getResources()); SingleAxisSwipeDetector.Direction dir = mRecentsView.getPagedOrientationHandler().getOppositeSwipeDirection(); mDetector = new SingleAxisSwipeDetector(activity, this, dir); @@ -201,8 +203,8 @@ public abstract class TaskViewTouchController mCurrentAnimationIsGoingUp = goingUp; BaseDragLayer dl = mActivity.getDragLayer(); final int secondaryLayerDimension = orientationHandler.getSecondaryDimension(dl); - long maxDuration = (long) (2 * secondaryLayerDimension); - int verticalFactor = -orientationHandler.getTaskDismissDirectionFactor(); + long maxDuration = 2 * secondaryLayerDimension; + int verticalFactor = orientationHandler.getTaskDragDisplacementFactor(mIsRtl); int secondaryTaskDimension = orientationHandler.getSecondaryDimension(mTaskBeingDragged); if (goingUp) { mPendingAnimation = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged, @@ -236,7 +238,7 @@ public abstract class TaskViewTouchController public void onDragStart(boolean start, float startDisplacement) { PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler(); if (mCurrentAnimation == null) { - reInitAnimationController(orientationHandler.isGoingUp(startDisplacement)); + reInitAnimationController(orientationHandler.isGoingUp(startDisplacement, mIsRtl)); mDisplacementShift = 0; } else { mDisplacementShift = mCurrentAnimation.getProgressFraction() / mProgressMultiplier; @@ -250,7 +252,7 @@ public abstract class TaskViewTouchController PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler(); float totalDisplacement = displacement + mDisplacementShift; boolean isGoingUp = totalDisplacement == 0 ? mCurrentAnimationIsGoingUp : - orientationHandler.isGoingUp(totalDisplacement); + orientationHandler.isGoingUp(totalDisplacement, mIsRtl); if (isGoingUp != mCurrentAnimationIsGoingUp) { reInitAnimationController(isGoingUp); mFlingBlockCheck.blockFling(); @@ -282,7 +284,7 @@ public abstract class TaskViewTouchController float interpolatedProgress = mCurrentAnimation.getInterpolatedProgress(); if (fling) { logAction = Touch.FLING; - boolean goingUp = orientationHandler.isGoingUp(velocity); + boolean goingUp = orientationHandler.isGoingUp(velocity, mIsRtl); goingToEnd = goingUp == mCurrentAnimationIsGoingUp; } else { logAction = Touch.SWIPE; 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 b5ac6e5dce..1dd5fb7a57 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -17,7 +17,6 @@ package com.android.quickstep; import static com.android.launcher3.LauncherState.BACKGROUND_APP; import static com.android.launcher3.LauncherState.OVERVIEW; -import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR; import static com.android.launcher3.statehandlers.DepthController.DEPTH; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; @@ -36,8 +35,8 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.statehandlers.DepthController; import com.android.quickstep.util.AppWindowAnimationHelper; -import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams; import com.android.quickstep.util.RemoteAnimationProvider; +import com.android.quickstep.util.TransformParams; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; @@ -75,14 +74,10 @@ final class AppToOverviewAnimationProvider exten boolean onActivityReady(T activity, Boolean wasVisible) { activity.getOverviewPanel().showCurrentTask(mTargetTaskId); AbstractFloatingView.closeAllOpenViews(activity, wasVisible); - BaseActivityInterface.AnimationFactory factory = - mActivityInterface.prepareRecentsUI(wasVisible, - false /* animate activity */, (controller) -> { + BaseActivityInterface.AnimationFactory factory = mActivityInterface.prepareRecentsUI( + wasVisible, (controller) -> { controller.dispatchOnStart(); - ValueAnimator anim = controller.getAnimationPlayer() - .setDuration(RECENTS_LAUNCH_DURATION); - anim.setInterpolator(FAST_OUT_SLOW_IN); - anim.start(); + controller.getAnimationPlayer().end(); }); factory.onRemoteAnimationReceived(null); factory.createActivityInterface(RECENTS_LAUNCH_DURATION); @@ -164,9 +159,7 @@ final class AppToOverviewAnimationProvider exten valueAnimator.setDuration(RECENTS_LAUNCH_DURATION); valueAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); valueAnimator.addUpdateListener((v) -> { - params.setProgress((float) v.getAnimatedValue()) - .setTargetSet(targets) - .setLauncherOnTop(true); + params.setProgress((float) v.getAnimatedValue()).setTargetSet(targets); clipHelper.applyTransform(params); }); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index 313ae44902..76c6060e8b 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -15,6 +15,8 @@ */ package com.android.quickstep; +import static com.android.launcher3.LauncherState.BACKGROUND_APP; +import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.anim.Interpolators.ACCEL_1_5; import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; @@ -23,44 +25,49 @@ import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC; import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION; import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; +import android.graphics.Matrix; +import android.graphics.Matrix.ScaleToFit; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.os.Build; -import android.util.Pair; import android.view.MotionEvent; -import android.view.View; import android.view.animation.Interpolator; +import androidx.annotation.CallSuper; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.UiThread; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.util.VibratorWrapper; import com.android.launcher3.views.FloatingIconView; -import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory; import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.ActivityInitListener; -import com.android.quickstep.util.AppWindowAnimationHelper; -import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams; -import com.android.quickstep.util.RecentsOrientedState; import com.android.quickstep.util.RectFSpringAnim; +import com.android.quickstep.util.TaskViewSimulator; +import com.android.quickstep.util.TransformParams; +import com.android.quickstep.util.TransformParams.BuilderProxy; +import com.android.quickstep.util.WindowSizeStrategy; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; +import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder; import java.util.ArrayList; import java.util.function.Consumer; @@ -93,7 +100,9 @@ public abstract class BaseSwipeUpHandler mActivityInterface; protected final InputConsumerController mInputConsumer; - protected AppWindowAnimationHelper mAppWindowAnimationHelper; + protected final TaskViewSimulator mTaskViewSimulator; + private AnimatorPlaybackController mWindowTransitionController; + protected final TransformParams mTransformParams = new TransformParams(); // Shift in the range of [0, 1]. @@ -113,27 +122,25 @@ public abstract class BaseSwipeUpHandler mRecentsView.setRecentsAnimationTargets(mRecentsAnimationController, mRecentsAnimationTargets)); + mRecentsViewScrollLinked = true; } - protected void startNewTask(int successStateFlag, Consumer resultCallback) { + protected void startNewTask(Consumer resultCallback) { // Launch the task user scrolled to (mRecentsView.getNextPage()). if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { // We finish recents animation inside launchTask() when live tile is enabled. @@ -210,24 +217,41 @@ public abstract class BaseSwipeUpHandler { resultCallback.accept(success); - if (!success) { + if (success) { + if (mRecentsView.indexOfChild(nextTask) + == getLastAppearedTaskIndex()) { + onRestartLastAppearedTask(); + } + } else { mActivityInterface.onLaunchTaskFailed(); nextTask.notifyTaskLaunchFailed(TAG); - } else { - mActivityInterface.onLaunchTaskSuccess(); + mRecentsAnimationController.finish(true /* toRecents */, null); } }, MAIN_EXECUTOR.getHandler()); } - mStateCallback.setStateOnUiThread(successStateFlag); } mCanceled = false; } ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true); } + /** + * Called when we successfully startNewTask() on the task that was previously running. Normally + * we call resumeLastTask() when returning to the previously running task, but this handles a + * specific edge case: if we switch from A to B, and back to A before B appears, we need to + * start A again to ensure it stays on top. + */ + @CallSuper + protected void onRestartLastAppearedTask() { + // Finish the controller here, since we won't get onTaskAppeared() for a task that already + // appeared. + mRecentsAnimationController.finish(false, null); + } + /** * Runs the given {@param action} if the recents animation has already started, or queues it to * be run when it is next started. @@ -241,42 +265,36 @@ public abstract class BaseSwipeUpHandler dragFactorStartAndMaxProgress = - mActivityInterface.getSwipeUpPullbackStartAndMaxProgress(); - mDragLengthFactorStartPullback = dragFactorStartAndMaxProgress.first; - mDragLengthFactorMaxPullback = dragFactorStartAndMaxProgress.second; + + float startScale = mTaskViewSimulator.getFullScreenScale(); + // Start pulling back when RecentsView scale is 0.75f, and let it go down to 0.5f. + mDragLengthFactorStartPullback = (0.75f - startScale) / (1 - startScale); + mDragLengthFactorMaxPullback = (0.5f - startScale) / (1 - startScale); + } else { + mDragLengthFactor = 1; + mDragLengthFactorStartPullback = mDragLengthFactorMaxPullback = 1; } + + AnimatorSet anim = new AnimatorSet(); + anim.setDuration(mTransitionDragLength * 2); + anim.setInterpolator(t -> t * mDragLengthFactor); + anim.play(ObjectAnimator.ofFloat(mTaskViewSimulator.recentsViewScale, + AnimatedFloat.VALUE, + mTaskViewSimulator.getFullScreenScale(), 1)); + anim.play(ObjectAnimator.ofFloat(mTaskViewSimulator.fullScreenProgress, + AnimatedFloat.VALUE, + BACKGROUND_APP.getOverviewFullscreenProgress(), + OVERVIEW.getOverviewFullscreenProgress())); + mWindowTransitionController = + AnimatorPlaybackController.wrap(anim, mTransitionDragLength * 2); } /** @@ -361,9 +401,6 @@ public abstract class BaseSwipeUpHandler= end) { - return 0f; - } - return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5); - } - public interface Factory { BaseSwipeUpHandler newHandler(GestureState gestureState, long touchTimeMs, @@ -588,4 +549,135 @@ public abstract class BaseSwipeUpHandler= end) { + return 0f; + } + return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5); + } + + protected abstract class HomeAnimationFactory { + + private FloatingIconView mIconView; + + public HomeAnimationFactory(@Nullable FloatingIconView iconView) { + mIconView = iconView; + } + + public @NonNull RectF getWindowTargetRect() { + PagedOrientationHandler orientationHandler = getOrientationHandler(); + DeviceProfile dp = mDp; + final int halfIconSize = dp.iconSizePx / 2; + float primaryDimension = orientationHandler + .getPrimaryValue(dp.availableWidthPx, dp.availableHeightPx); + float secondaryDimension = orientationHandler + .getSecondaryValue(dp.availableWidthPx, dp.availableHeightPx); + final float targetX = primaryDimension / 2f; + final float targetY = secondaryDimension - dp.hotseatBarSizePx; + // Fallback to animate to center of screen. + return new RectF(targetX - halfIconSize, targetY - halfIconSize, + targetX + halfIconSize, targetY + halfIconSize); + } + + public abstract @NonNull AnimatorPlaybackController createActivityAnimationToHome(); + + public void playAtomicAnimation(float velocity) { + // No-op + } + } + + private class SpringAnimationRunner extends AnimationSuccessListener + implements RectFSpringAnim.OnUpdateListener, BuilderProxy { + + final Rect mCropRect = new Rect(); + final Matrix mMatrix = new Matrix(); + + final RectF mWindowCurrentRect = new RectF(); + final Matrix mHomeToWindowPositionMap; + + final FloatingIconView mFIV; + final AnimatorPlaybackController mHomeAnim; + final RectF mCropRectF; + + final float mStartRadius; + final float mEndRadius; + final float mWindowAlphaThreshold; + + SpringAnimationRunner(HomeAnimationFactory factory, RectF cropRectF, + Matrix homeToWindowPositionMap) { + mHomeAnim = factory.createActivityAnimationToHome(); + mCropRectF = cropRectF; + mHomeToWindowPositionMap = homeToWindowPositionMap; + + cropRectF.roundOut(mCropRect); + mFIV = factory.mIconView; + + // End on a "round-enough" radius so that the shape reveal doesn't have to do too much + // rounding at the end of the animation. + mStartRadius = mTaskViewSimulator.getCurrentCornerRadius(); + mEndRadius = cropRectF.width() / 2f; + + // We want the window alpha to be 0 once this threshold is met, so that the + // FolderIconView can be seen morphing into the icon shape. + mWindowAlphaThreshold = mFIV != null ? 1f - SHAPE_PROGRESS_DURATION : 1f; + } + + @Override + public void onUpdate(RectF currentRect, float progress) { + mHomeAnim.setPlayFraction(progress); + mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, currentRect); + + mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL); + float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius); + mTransformParams + .setTargetAlpha(getWindowAlpha(progress)) + .setCornerRadius(cornerRadius); + + mTransformParams.applySurfaceParams(mTransformParams.createSurfaceParams(this)); + if (mFIV != null) { + mFIV.update(currentRect, 1f, progress, + mWindowAlphaThreshold, mMatrix.mapRadius(cornerRadius), false); + } + } + + @Override + public void onBuildParams(Builder builder, RemoteAnimationTargetCompat app, int targetMode, + TransformParams params) { + if (app.mode == targetMode + && app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) { + builder.withMatrix(mMatrix) + .withWindowCrop(mCropRect) + .withCornerRadius(params.getCornerRadius()); + } + } + + @Override + public void onCancel() { + if (mFIV != null) { + mFIV.fastFinish(); + } + } + + @Override + public void onAnimationStart(Animator animation) { + mHomeAnim.dispatchOnStart(); + } + + @Override + public void onAnimationSuccess(Animator animator) { + mHomeAnim.getAnimationPlayer().end(); + } + } } 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 88dbbe13a5..cd546e2b31 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java @@ -15,25 +15,23 @@ */ package com.android.quickstep; +import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; -import static com.android.quickstep.fallback.FallbackRecentsView.ZOOM_PROGRESS; +import static com.android.quickstep.fallback.RecentsState.BACKGROUND_APP; +import static com.android.quickstep.fallback.RecentsState.DEFAULT; import static com.android.quickstep.util.WindowSizeStrategy.FALLBACK_RECENTS_SIZE_STRATEGY; import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA; +import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS; -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Rect; -import android.graphics.RectF; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; +import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.quickstep.fallback.FallbackRecentsView; import com.android.quickstep.util.ActivityInitListener; @@ -89,54 +87,17 @@ public final class FallbackActivityInterface implements // set to zero prior to this class becoming active. } - @NonNull @Override - public HomeAnimationFactory prepareHomeUI() { + public AnimationFactory prepareRecentsUI( + boolean activityVisible, Consumer callback) { RecentsActivity activity = getCreatedActivity(); - RecentsView recentsView = activity.getOverviewPanel(); - - return new HomeAnimationFactory() { - @NonNull - @Override - public RectF getWindowTargetRect() { - float centerX = recentsView.getPivotX(); - float centerY = recentsView.getPivotY(); - return new RectF(centerX, centerY, centerX, centerY); - } - - @NonNull - @Override - public AnimatorPlaybackController createActivityAnimationToHome() { - Animator anim = ObjectAnimator.ofFloat(recentsView, CONTENT_ALPHA, 0); - anim.addListener(new AnimationSuccessListener() { - @Override - public void onAnimationSuccess(Animator animator) { - recentsView.startHome(); - } - }); - AnimatorSet animatorSet = new AnimatorSet(); - animatorSet.play(anim); - long accuracy = 2 * Math.max(recentsView.getWidth(), recentsView.getHeight()); - return AnimatorPlaybackController.wrap(animatorSet, accuracy); - } - }; - } - - @Override - public AnimationFactory prepareRecentsUI(boolean activityVisible, - boolean animateActivity, Consumer callback) { - RecentsActivity activity = getCreatedActivity(); - if (activityVisible) { + if (activity == null) { return (transitionLength) -> { }; } + activity.getStateManager().goToState(BACKGROUND_APP); FallbackRecentsView rv = activity.getOverviewPanel(); rv.setContentAlpha(0); - rv.getClearAllButton().setVisibilityAlpha(0); - rv.setDisallowScrollToClearAll(true); - - boolean fromState = !animateActivity; - rv.setInOverviewState(fromState); return new AnimationFactory() { @@ -154,27 +115,19 @@ public final class FallbackActivityInterface implements @Override public void createActivityInterface(long transitionLength) { - AnimatorSet animatorSet = new AnimatorSet(); + PendingAnimation pa = new PendingAnimation(transitionLength * 2); + if (isAnimatingToRecents) { - ObjectAnimator anim = ObjectAnimator.ofFloat(rv, CONTENT_ALPHA, 0, 1); - anim.setDuration(transitionLength).setInterpolator(LINEAR); - animatorSet.play(anim); + pa.addFloat(rv, CONTENT_ALPHA, 0, 1, LINEAR); } - ObjectAnimator anim = ObjectAnimator.ofFloat(rv, ZOOM_PROGRESS, 1, 0); - anim.setDuration(transitionLength).setInterpolator(LINEAR); - animatorSet.play(anim); - - AnimatorPlaybackController controller = - AnimatorPlaybackController.wrap(animatorSet, transitionLength); + pa.addFloat(rv, SCALE_PROPERTY, rv.getMaxScaleForFullScreen(), 1, LINEAR); + pa.addFloat(rv, FULLSCREEN_PROGRESS, 1, 0, LINEAR); + AnimatorPlaybackController controller = pa.createPlaybackController(); // Since we are changing the start position of the UI, reapply the state, at the end - controller.setEndAction(() -> { - boolean endState = true; - rv.setInOverviewState(controller.getInterpolatedProgress() > 0.5 ? - endState : fromState); - }); - + controller.setEndAction(() -> activity.getStateManager().goToState( + controller.getInterpolatedProgress() > 0.5 ? DEFAULT : BACKGROUND_APP)); callback.accept(controller); } }; @@ -190,7 +143,7 @@ public final class FallbackActivityInterface implements @Nullable @Override public RecentsActivity getCreatedActivity() { - return BaseRecentsActivity.ACTIVITY_TRACKER.getCreatedActivity(); + return RecentsActivity.ACTIVITY_TRACKER.getCreatedActivity(); } @Nullable diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java index 45b39c859e..77e50caae7 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java @@ -24,6 +24,7 @@ import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS; import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; import static com.android.quickstep.RecentsActivity.EXTRA_TASK_ID; import static com.android.quickstep.RecentsActivity.EXTRA_THUMBNAIL; +import static com.android.quickstep.util.WindowSizeStrategy.FALLBACK_RECENTS_SIZE_STRATEGY; import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD; import android.animation.Animator; @@ -32,25 +33,24 @@ import android.app.ActivityOptions; import android.content.Context; import android.content.Intent; import android.graphics.PointF; -import android.graphics.RectF; import android.os.Bundle; import android.util.ArrayMap; import android.view.MotionEvent; +import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; -import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.util.ObjectWrapper; -import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory; +import com.android.quickstep.BaseActivityInterface.AnimationFactory; import com.android.quickstep.GestureState.GestureEndTarget; import com.android.quickstep.fallback.FallbackRecentsView; import com.android.quickstep.util.RectFSpringAnim; -import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.InputConsumerController; +import com.android.systemui.shared.system.RemoteAnimationTargetCompat; /** * Handles the navigation gestures when a 3rd party launcher is the default home activity. @@ -105,10 +105,16 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler { }; + public FallbackSwipeHandler(Context context, RecentsAnimationDeviceState deviceState, GestureState gestureState, InputConsumerController inputConsumer, boolean isLikelyToStartNewTask, boolean continuingLastGesture) { - super(context, deviceState, gestureState, inputConsumer); + super(context, deviceState, gestureState, inputConsumer, FALLBACK_RECENTS_SIZE_STRATEGY); mInQuickSwitchMode = isLikelyToStartNewTask || continuingLastGesture; mContinuingLastGesture = continuingLastGesture; @@ -118,9 +124,9 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler 1 - mLauncherAlpha.value); + mTransformParams.setBaseAlphaCallback((t, a) -> 1 - mLauncherAlpha.value); } else { - mAppWindowAnimationHelper.setBaseAlphaCallback((t, a) -> mLauncherAlpha.value); + mTransformParams.setBaseAlphaCallback((t, a) -> mLauncherAlpha.value); } // Going home has an extra long progress to ensure that it animates into the screen @@ -156,7 +162,7 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler t * mDragLengthFactor); + mLauncherTransitionController.dispatchOnStart(); + updateLauncherTransitionProgress(); + } + + private void updateLauncherTransitionProgress() { + if (mLauncherTransitionController == null + || !canCreateNewOrUpdateExistingLauncherTransitionController()) { + return; + } + // Normalize the progress to 0 to 1, as the animation controller will clamp it to that + // anyway. The controller mimics the drag length factor by applying it to its interpolators. + float progress = mCurrentShift.value / mDragLengthFactor; + mLauncherTransitionController.setPlayFraction(progress); + } + + /** + * We don't want to change mLauncherTransitionController if mGestureState.getEndTarget() == HOME + * (it has its own animation) or if we're already animating the current controller. + * @return Whether we can create the launcher controller or update its progress. + */ + private boolean canCreateNewOrUpdateExistingLauncherTransitionController() { + return mGestureState.getEndTarget() != HOME && !mHasLauncherTransitionControllerStarted; + } + @Override protected boolean moveWindowWithRecentsScroll() { return mInQuickSwitchMode; @@ -261,9 +302,8 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler= MIN_PROGRESS_FOR_OVERVIEW); } - if (mRecentsAnimationTargets != null) { - applyTransformUnchecked(); - } + applyWindowTransform(); + updateLauncherTransitionProgress(); } @Override @@ -320,15 +360,6 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler {}); + startNewTask(success -> { }); break; } } @@ -416,7 +447,7 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler= 0 && taskToLaunch != runningTaskIndex) @@ -477,11 +508,7 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler { - private Pair mSwipeUpPullbackStartAndMaxProgress = - BaseActivityInterface.super.getSwipeUpPullbackStartAndMaxProgress(); - @Override public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) { LAUNCHER_ACTIVITY_SIZE_STRATEGY.calculateTaskSize(context, dp, outRect); @@ -93,11 +83,6 @@ public final class LauncherActivityInterface implements BaseActivityInterface getSwipeUpPullbackStartAndMaxProgress() { - return mSwipeUpPullbackStartAndMaxProgress; - } - @Override public void onTransitionCancelled(boolean activityVisible) { Launcher launcher = getCreatedActivity(); @@ -148,66 +133,9 @@ public final class LauncherActivityInterface implements BaseActivityInterface callback) { + public AnimationFactory prepareRecentsUI( + boolean activityVisible, Consumer callback) { BaseQuickstepLauncher launcher = getCreatedActivity(); final LauncherState startState = launcher.getStateManager().getState(); @@ -217,8 +145,7 @@ public final class LauncherActivityInterface implements BaseActivityInterface