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 0019ecb427..6c64bf7c75 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -30,6 +30,7 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRA import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS; import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch; import static com.android.quickstep.TaskViewUtils.getRecentsWindowAnimator; +import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -37,7 +38,6 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; -import android.util.FloatProperty; import android.view.View; import androidx.annotation.NonNull; @@ -49,7 +49,6 @@ import com.android.launcher3.anim.AnimatorPlaybackController; 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; import com.android.quickstep.views.TaskView; @@ -199,11 +198,10 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti return ObjectAnimator.ofFloat(mLauncher.getOverviewPanel(), RecentsView.CONTENT_ALPHA, values); case INDEX_RECENTS_TRANSLATE_X_ANIM: - PagedOrientationHandler orientationHandler = - ((RecentsView)mLauncher.getOverviewPanel()).getPagedViewOrientedState() - .getOrientationHandler(); - FloatProperty translate = orientationHandler.getPrimaryViewTranslate(); - return new SpringAnimationBuilder<>(mLauncher.getOverviewPanel(), translate) + // TODO: Do not assume motion across X axis for adjacent page + return new SpringAnimationBuilder<>( + mLauncher.getOverviewPanel(), ADJACENT_PAGE_OFFSET) + .setMinimumVisibleChange(1f / mLauncher.getOverviewPanel().getWidth()) .setDampingRatio(0.8f) .setStiffness(250) .setValues(values) 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 a87d6d14d6..6da804bde8 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 @@ -61,13 +61,16 @@ public class BackgroundAppState extends OverviewState { } @Override - public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) { + public float[] getOverviewScaleAndOffset(Launcher launcher) { + return new float[] {getOverviewScale(launcher), NO_OFFSET}; + } + + private float getOverviewScale(Launcher launcher) { // Initialize the recents view scale to what it would be when starting swipe up RecentsView recentsView = launcher.getOverviewPanel(); int taskCount = recentsView.getTaskViewCount(); - if (taskCount == 0) { - return super.getOverviewScaleAndTranslation(launcher); - } + if (taskCount == 0) return 1; + TaskView dummyTask; if (recentsView.getCurrentPage() >= recentsView.getTaskViewStartIndex()) { if (recentsView.getCurrentPage() <= taskCount - 1) { @@ -78,8 +81,8 @@ public class BackgroundAppState extends OverviewState { } else { dummyTask = recentsView.getTaskViewAt(0); } - return recentsView.getTempAppWindowAnimationHelper().updateForFullscreenOverview(dummyTask) - .getScaleAndTranslation(); + return recentsView.getTempAppWindowAnimationHelper() + .updateForFullscreenOverview(dummyTask).getSrcToTargetScale(); } @Override 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 1288e7bf9b..b27f16ac08 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 @@ -24,24 +24,18 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TR import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; -import com.android.launcher3.R; -import com.android.launcher3.Utilities; import com.android.launcher3.states.StateAnimationConfig; public class OverviewPeekState extends OverviewState { + private static final float OVERVIEW_OFFSET = 0.7f; + public OverviewPeekState(int id) { super(id); } @Override - public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) { - ScaleAndTranslation result = super.getOverviewScaleAndTranslation(launcher); - result.translationX = NORMAL.getOverviewScaleAndTranslation(launcher).translationX - - launcher.getResources().getDimension(R.dimen.overview_peek_distance); - if (Utilities.isRtl(launcher.getResources())) { - result.translationX = -result.translationX; - } - return result; + public float[] getOverviewScaleAndOffset(Launcher launcher) { + return new float[] {NO_SCALE, OVERVIEW_OFFSET}; } @Override 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 fc28da3f5d..9bb424364d 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 @@ -24,7 +24,6 @@ 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.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; @@ -123,8 +122,8 @@ public class OverviewState extends LauncherState { } @Override - public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) { - return new ScaleAndTranslation(1f, 0f, 0f); + public float[] getOverviewScaleAndOffset(Launcher launcher) { + return new float[] {NO_SCALE, NO_OFFSET}; } @Override 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 c92a872ba9..f4f8bc9ecb 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 @@ -40,17 +40,15 @@ import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC; import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.CANCEL; import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.HIDE; import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.PEEK; +import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET; import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS; 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.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.graphics.PointF; import android.view.MotionEvent; -import android.view.View; import android.view.animation.Interpolator; import com.android.launcher3.BaseQuickstepLauncher; @@ -59,6 +57,7 @@ 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.PendingAnimation; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.graphics.OverviewScrim; import com.android.launcher3.states.StateAnimationConfig; @@ -237,58 +236,32 @@ public class NoButtonQuickSwitchTouchController implements TouchController, private void setupOverviewAnimators() { final LauncherState fromState = QUICK_SWITCH; final LauncherState toState = OVERVIEW; - LauncherState.ScaleAndTranslation fromScaleAndTranslation = fromState - .getOverviewScaleAndTranslation(mLauncher); - LauncherState.ScaleAndTranslation toScaleAndTranslation = toState - .getOverviewScaleAndTranslation(mLauncher); - // Update RecentView's translationX to have it start offscreen. - float startScale = Utilities.mapRange( - SCALE_DOWN_INTERPOLATOR.getInterpolation(Y_ANIM_MIN_PROGRESS), - fromScaleAndTranslation.scale, - toScaleAndTranslation.scale); - fromScaleAndTranslation.translationX = mRecentsView.getOffscreenTranslationX(startScale); // Set RecentView's initial properties. - mRecentsView.setScaleX(fromScaleAndTranslation.scale); - mRecentsView.setScaleY(fromScaleAndTranslation.scale); - mRecentsView.setTranslationX(fromScaleAndTranslation.translationX); - mRecentsView.setTranslationY(fromScaleAndTranslation.translationY); + SCALE_PROPERTY.set(mRecentsView, fromState.getOverviewScaleAndOffset(mLauncher)[0]); + ADJACENT_PAGE_OFFSET.set(mRecentsView, 1f); mRecentsView.setContentAlpha(1); mRecentsView.setFullscreenProgress(fromState.getOverviewFullscreenProgress()); + float[] scaleAndOffset = toState.getOverviewScaleAndOffset(mLauncher); // As we drag right, animate the following properties: // - RecentsView translationX // - OverviewScrim - AnimatorSet xOverviewAnim = new AnimatorSet(); - xOverviewAnim.play(ObjectAnimator.ofFloat(mRecentsView, View.TRANSLATION_X, - toScaleAndTranslation.translationX)); - xOverviewAnim.play(ObjectAnimator.ofFloat( - mLauncher.getDragLayer().getOverviewScrim(), OverviewScrim.SCRIM_PROGRESS, - toState.getOverviewScrimAlpha(mLauncher))); - long xAccuracy = (long) (mXRange * 2); - xOverviewAnim.setDuration(xAccuracy); - mXOverviewAnim = AnimatorPlaybackController.wrap(xOverviewAnim, xAccuracy); + PendingAnimation xAnim = new PendingAnimation((long) (mXRange * 2)); + xAnim.setFloat(mRecentsView, ADJACENT_PAGE_OFFSET, scaleAndOffset[1], LINEAR); + xAnim.setFloat(mLauncher.getDragLayer().getOverviewScrim(), OverviewScrim.SCRIM_PROGRESS, + toState.getOverviewScrimAlpha(mLauncher), LINEAR); + mXOverviewAnim = xAnim.createPlaybackController(); mXOverviewAnim.dispatchOnStart(); // As we drag up, animate the following properties: - // - RecentsView translationY // - RecentsView scale // - RecentsView fullscreenProgress - AnimatorSet yAnimation = new AnimatorSet(); - Animator translateYAnim = ObjectAnimator.ofFloat(mRecentsView, View.TRANSLATION_Y, - toScaleAndTranslation.translationY); - Animator scaleAnim = ObjectAnimator.ofFloat(mRecentsView, SCALE_PROPERTY, - toScaleAndTranslation.scale); - Animator fullscreenProgressAnim = ObjectAnimator.ofFloat(mRecentsView, FULLSCREEN_PROGRESS, - fromState.getOverviewFullscreenProgress(), toState.getOverviewFullscreenProgress()); - scaleAnim.setInterpolator(SCALE_DOWN_INTERPOLATOR); - fullscreenProgressAnim.setInterpolator(SCALE_DOWN_INTERPOLATOR); - yAnimation.play(translateYAnim); - yAnimation.play(scaleAnim); - yAnimation.play(fullscreenProgressAnim); - long yAccuracy = (long) (mYRange * 2); - yAnimation.setDuration(yAccuracy); - mYOverviewAnim = AnimatorPlaybackController.wrap(yAnimation, yAccuracy); + PendingAnimation yAnim = new PendingAnimation((long) (mYRange * 2)); + yAnim.setFloat(mRecentsView, SCALE_PROPERTY, scaleAndOffset[0], SCALE_DOWN_INTERPOLATOR); + yAnim.setFloat(mRecentsView, FULLSCREEN_PROGRESS, + toState.getOverviewFullscreenProgress(), SCALE_DOWN_INTERPOLATOR); + mYOverviewAnim = yAnim.createPlaybackController(); mYOverviewAnim.dispatchOnStart(); } 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 3513ad5386..6a3466c7d8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -135,8 +135,15 @@ public abstract class BaseSwipeUpHandler { - private Runnable mAdjustInterpolatorsRunnable; private Pair mSwipeUpPullbackStartAndMaxProgress = BaseActivityInterface.super.getSwipeUpPullbackStartAndMaxProgress(); @@ -242,14 +237,6 @@ public final class LauncherActivityInterface implements BaseActivityInterface { - // Adjust the translateY interpolator to account for the running task's top inset. - // When progress <= 1, this is handled by each task view as they set their fullscreen - // progress. However, once we go to progress > 1, fullscreen progress stays at 0, so - // recents as a whole needs to translate further to keep up with the app window. - TaskView runningTaskView = recentsView.getRunningTaskView(); - if (runningTaskView == null) { - runningTaskView = recentsView.getCurrentPageTaskView(); - if (runningTaskView == null) { - // There are no task views in LockTask mode when Overview is enabled. - return; - } - } - TimeInterpolator oldInterpolator = translateY.getInterpolator(); - Rect fallbackInsets = launcher.getDeviceProfile().getInsets(); - float extraTranslationY = runningTaskView.getThumbnail().getInsets(fallbackInsets).top; - float normalizedTranslationY = extraTranslationY / (fromTranslationY - endTranslationY); - translateY.setInterpolator(t -> { - float newT = oldInterpolator.getInterpolation(t); - return newT <= 1f ? newT : newT + normalizedTranslationY * (newT - 1); - }); - }; + anim.playTogether(scale, applyFullscreenProgress); // Start pulling back when RecentsView scale is 0.75f, and let it go down to 0.5f. - float pullbackStartProgress = (0.75f - fromScaleAndTranslation.scale) - / (endScaleAndTranslation.scale - fromScaleAndTranslation.scale); - float pullbackMaxProgress = (0.5f - fromScaleAndTranslation.scale) - / (endScaleAndTranslation.scale - fromScaleAndTranslation.scale); + float pullbackStartProgress = (0.75f - fromScale) / (endScale - fromScale); + float pullbackMaxProgress = (0.5f - fromScale) / (endScale - fromScale); mSwipeUpPullbackStartAndMaxProgress = new Pair<>( pullbackStartProgress, pullbackMaxProgress); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java index 31a2814ed0..5a64382478 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java @@ -17,6 +17,8 @@ package com.android.quickstep; import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER; import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS; +import static com.android.launcher3.LauncherState.BACKGROUND_APP; +import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2; @@ -39,16 +41,17 @@ import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHO import android.animation.Animator; import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.graphics.PointF; +import android.graphics.Rect; import android.graphics.RectF; import android.os.Build; import android.os.SystemClock; -import android.util.Log; import android.view.View; import android.view.View.OnApplyWindowInsetsListener; import android.view.ViewTreeObserver.OnDrawListener; @@ -67,7 +70,6 @@ import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.logging.UserEventDispatcher; -import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; @@ -78,9 +80,11 @@ import com.android.quickstep.GestureState.GestureEndTarget; import com.android.quickstep.inputconsumers.OverviewInputConsumer; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.AppWindowAnimationHelper.TargetAlphaProvider; +import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.util.RectFSpringAnim; import com.android.quickstep.util.ShelfPeekAnim; import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState; +import com.android.quickstep.util.TaskViewSimulator; import com.android.quickstep.views.LiveTileOverlay; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; @@ -177,6 +181,9 @@ public class LauncherSwipeHandler private AnimatorPlaybackController mLauncherTransitionController; private boolean mHasLauncherTransitionControllerStarted; + private final TaskViewSimulator mTaskViewSimulator; + private AnimatorPlaybackController mWindowTransitionController; + private AnimationFactory mAnimationFactory = (t) -> { }; private boolean mWasLauncherAlreadyVisible; @@ -201,6 +208,9 @@ public class LauncherSwipeHandler mTaskAnimationManager = taskAnimationManager; mTouchTimeMs = touchTimeMs; mContinuingLastGesture = continuingLastGesture; + mTaskViewSimulator = new TaskViewSimulator(context, LayoutUtils::calculateLauncherTaskSize); + + initAfterSubclassConstructor(); initStateCallbacks(); } @@ -473,23 +483,11 @@ public class LauncherSwipeHandler } else if (mContinuingLastGesture && mRecentsView.getRunningTaskIndex() != mRecentsView.getNextPage()) { recentsAttachedToAppWindow = true; - animate = false; } else if (runningTaskTarget != null && isNotInRecents(runningTaskTarget)) { // The window is going away so make sure recents is always visible in this case. recentsAttachedToAppWindow = true; - animate = false; } else { recentsAttachedToAppWindow = mIsShelfPeeking || mIsLikelyToStartNewTask; - if (animate) { - // Only animate if an adjacent task view is visible on screen. - TaskView adjacentTask1 = mRecentsView.getNextTaskView(); - TaskView adjacentTask2 = mRecentsView.getPreviousTaskView(); - float prevTranslationX = mRecentsView.getTranslationX(); - mRecentsView.setTranslationX(0); - animate = (adjacentTask1 != null && adjacentTask1.getGlobalVisibleRect(TEMP_RECT)) - || (adjacentTask2 != null && adjacentTask2.getGlobalVisibleRect(TEMP_RECT)); - mRecentsView.setTranslationX(prevTranslationX); - } } mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate); } @@ -523,6 +521,34 @@ public class LauncherSwipeHandler mAnimationFactory.createActivityInterface(mTransitionDragLength); } + @Override + protected void updateSource(Rect stackBounds, RemoteAnimationTargetCompat runningTarget) { + super.updateSource(stackBounds, runningTarget); + mTaskViewSimulator.setPreview(runningTarget, mRecentsAnimationTargets); + } + + @Override + protected void initTransitionEndpoints(DeviceProfile dp) { + super.initTransitionEndpoints(dp); + mTaskViewSimulator.setDp(dp, false /* isOpening */); + mTaskViewSimulator.setLayoutRotation( + mDeviceState.getCurrentActiveRotation(), + mDeviceState.getDisplayRotation()); + + 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); + } + /** * 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. @@ -542,7 +568,6 @@ public class LauncherSwipeHandler private void onAnimatorPlaybackControllerCreated(AnimatorPlaybackController anim) { mLauncherTransitionController = anim; mLauncherTransitionController.dispatchSetInterpolator(t -> t * mDragLengthFactor); - mAnimationFactory.adjustActivityControllerInterpolators(); mLauncherTransitionController.dispatchOnStart(); updateLauncherTransitionProgress(); } @@ -555,7 +580,9 @@ public class LauncherSwipeHandler @Override public void updateFinalShift() { if (mRecentsAnimationTargets != null) { - applyTransformUnchecked(); + // Base class expects applyTransformUnchecked to be called here. + // TODO: Remove this dependency for swipe-up animation. + // applyTransformUnchecked(); updateSysUiFlags(mCurrentShift.value); } @@ -575,6 +602,16 @@ public class LauncherSwipeHandler } } + if (mWindowTransitionController != null) { + float progress = mCurrentShift.value / mDragLengthFactor; + mWindowTransitionController.setPlayFraction(progress); + mTransformParams + .setTargetSet(mRecentsAnimationTargets) + .setLauncherOnTop(true); + + mTaskViewSimulator.setScroll(mRecentsView == null ? 0 : mRecentsView.getScrollOffset()); + mTaskViewSimulator.apply(mTransformParams); + } updateLauncherTransitionProgress(); } @@ -1020,7 +1057,6 @@ public class LauncherSwipeHandler mLauncherTransitionController.dispatchSetInterpolator(t -> end); } else { mLauncherTransitionController.dispatchSetInterpolator(adjustedInterpolator); - mAnimationFactory.adjustActivityControllerInterpolators(); } mLauncherTransitionController.getAnimationPlayer().setDuration(Math.max(0, duration)); @@ -1296,6 +1332,7 @@ public class LauncherSwipeHandler private void setTargetAlphaProvider(TargetAlphaProvider provider) { mAppWindowAnimationHelper.setTaskAlphaCallback(provider); + mTaskViewSimulator.setTaskAlphaCallback(provider); updateFinalShift(); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java index 6d1bf11135..235ac16413 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java @@ -26,7 +26,6 @@ import android.util.FloatProperty; import android.view.View; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.LauncherState.ScaleAndTranslation; import com.android.launcher3.Utilities; import com.android.quickstep.RecentsActivity; import com.android.quickstep.util.LayoutUtils; @@ -58,7 +57,6 @@ public class FallbackRecentsView extends RecentsView { private boolean mInOverviewState = true; private float mZoomScale = 1f; - private float mZoomTranslationY = 0f; private RunningTaskInfo mRunningTaskInfo; @@ -145,14 +143,11 @@ public class FallbackRecentsView extends RecentsView { if (getTaskViewCount() == 0) { mZoomScale = 1f; - mZoomTranslationY = 0f; } else { TaskView dummyTask = getTaskViewAt(0); - ScaleAndTranslation sat = getTempAppWindowAnimationHelper() + mZoomScale = getTempAppWindowAnimationHelper() .updateForFullscreenOverview(dummyTask) - .getScaleAndTranslation(); - mZoomScale = sat.scale; - mZoomTranslationY = sat.translationY; + .getSrcToTargetScale(); } setZoomProgress(mZoomInProgress); @@ -161,7 +156,6 @@ public class FallbackRecentsView extends RecentsView { public void setZoomProgress(float progress) { mZoomInProgress = progress; SCALE_PROPERTY.set(this, Utilities.mapRange(mZoomInProgress, 1, mZoomScale)); - TRANSLATION_Y.set(this, Utilities.mapRange(mZoomInProgress, 0, mZoomTranslationY)); FULLSCREEN_PROGRESS.set(this, mZoomInProgress); } 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 b7398383e8..00329b87e0 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 @@ -30,13 +30,11 @@ import android.graphics.Matrix.ScaleToFit; import android.graphics.Rect; import android.graphics.RectF; import android.os.Build; -import android.view.Surface; import androidx.annotation.Nullable; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.Interpolators; @@ -60,7 +58,7 @@ import com.android.systemui.shared.system.WindowManagerWrapper; public class AppWindowAnimationHelper { // The bounds of the source app in device coordinates - private final Rect mSourceStackBounds = new Rect(); + private final RectF mSourceStackBounds = new RectF(); // The insets of the source app private final Rect mSourceInsets = new Rect(); // The source app bounds with the source insets applied, in the device coordinates @@ -159,14 +157,10 @@ public class AppWindowAnimationHelper { mSourceRect.set(scaledTargetRect); } - private float getSrcToTargetScale() { - if (mOrientedState == null - || mOrientedState.isHomeRotationAllowed() - || mOrientedState.isDisplayPhoneNatural()) { - return mSourceRect.width() / mTargetRect.width(); - } else { - return mSourceRect.height() / mTargetRect.height(); - } + public float getSrcToTargetScale() { + return LayoutUtils.getTaskScale(mOrientedState, + mSourceRect.width(), mSourceRect.height(), + mTargetRect.width(), mTargetRect.height()); } public void prepareAnimation(DeviceProfile dp, boolean isOpening) { @@ -378,15 +372,6 @@ public class AppWindowAnimationHelper { return this; } - /** - * @return The source rect's scale and translation relative to the target rect. - */ - public LauncherState.ScaleAndTranslation getScaleAndTranslation() { - float scale = getSrcToTargetScale(); - float translationY = mSourceRect.centerY() - mSourceRect.top - mTargetRect.centerY(); - return new LauncherState.ScaleAndTranslation(scale, 0, translationY); - } - private void updateStackBoundsToMultiWindowTaskSize(BaseDraggingActivity activity) { SystemUiProxy proxy = SystemUiProxy.INSTANCE.get(activity); if (proxy.isActive()) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java new file mode 100644 index 0000000000..0131fdf5c4 --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java @@ -0,0 +1,284 @@ +/* + * 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.quickstep.util; + +import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; +import static com.android.launcher3.touch.PagedOrientationHandler.MATRIX_POST_TRANSLATE; +import static com.android.quickstep.util.AppWindowAnimationHelper.applySurfaceParams; +import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation; +import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; +import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING; +import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_FULLSCREEN; + +import android.content.Context; +import android.graphics.Matrix; +import android.graphics.PointF; +import android.graphics.Rect; +import android.graphics.RectF; + +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.touch.PagedOrientationHandler; +import com.android.quickstep.AnimatedFloat; +import com.android.quickstep.RecentsAnimationTargets; +import com.android.quickstep.util.AppWindowAnimationHelper.TargetAlphaProvider; +import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams; +import com.android.quickstep.views.RecentsView.ScrollState; +import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper; +import com.android.quickstep.views.TaskView; +import com.android.quickstep.views.TaskView.FullscreenDrawParams; +import com.android.systemui.shared.recents.model.ThumbnailData; +import com.android.systemui.shared.system.RemoteAnimationTargetCompat; +import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; + +/** + * A utility class which emulates the layout behavior of TaskView and RecentsView + */ +public class TaskViewSimulator { + + private final Rect mTmpCropRect = new Rect(); + private final RectF mTempRectF = new RectF(); + + private final RecentsOrientedState mOrientationState; + private final Context mContext; + private final TaskSizeProvider mSizeProvider; + + private final Rect mTaskRect = new Rect(); + private final PointF mPivot = new PointF(); + private DeviceProfile mDp; + + private final Matrix mMatrix = new Matrix(); + private RemoteAnimationTargetCompat mRunningTarget; + private RecentsAnimationTargets mAllTargets; + + // Whether to boost the opening animation target layers, or the closing + private int mBoostModeTargetLayers = -1; + private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a; + + // Thumbnail view properties + private final Rect mThumbnailPosition = new Rect(); + private final ThumbnailData mThumbnailData = new ThumbnailData(); + private final PreviewPositionHelper mPositionHelper; + private final Matrix mInversePositionMatrix = new Matrix(); + + // TaskView properties + private final FullscreenDrawParams mCurrentFullscreenParams; + private float mCurveScale = 1; + + // RecentsView properties + public final AnimatedFloat recentsViewScale = new AnimatedFloat(() -> { }); + public final AnimatedFloat fullScreenProgress = new AnimatedFloat(() -> { }); + private final ScrollState mScrollState = new ScrollState(); + private final int mPageSpacing; + + // Cached calculations + private boolean mLayoutValid = false; + private boolean mScrollValid = false; + + public TaskViewSimulator(Context context, TaskSizeProvider sizeProvider) { + mContext = context; + mSizeProvider = sizeProvider; + mPositionHelper = new PreviewPositionHelper(context); + mOrientationState = new RecentsOrientedState(context); + + mCurrentFullscreenParams = new FullscreenDrawParams(context); + mPageSpacing = context.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing); + } + + /** + * Sets the device profile for the current state + */ + public void setDp(DeviceProfile dp, boolean isOpening) { + mDp = dp; + mBoostModeTargetLayers = isOpening ? MODE_OPENING : MODE_CLOSING; + mLayoutValid = false; + } + + /** + * @see com.android.quickstep.views.RecentsView#setLayoutRotation(int, int) + */ + public void setLayoutRotation(int touchRotation, int displayRotation) { + if (!FeatureFlags.ENABLE_FIXED_ROTATION_TRANSFORM.get()) { + return; + } + mOrientationState.update(touchRotation, displayRotation, + mOrientationState.getLauncherRotation()); + mLayoutValid = false; + } + + /** + * @see com.android.quickstep.views.RecentsView#FULLSCREEN_PROGRESS + */ + public float getFullScreenScale() { + if (mDp == null) { + return 1; + } + mSizeProvider.calculateTaskSize(mContext, mDp, mTaskRect); + return mOrientationState.getFullScreenScaleAndPivot(mTaskRect, mDp, mPivot); + } + + /** + * Sets the targets which the simulator will control + */ + public void setPreview( + RemoteAnimationTargetCompat runningTarget, RecentsAnimationTargets allTargets) { + mRunningTarget = runningTarget; + mAllTargets = allTargets; + + mThumbnailData.insets.set(mRunningTarget.contentInsets); + // TODO: What is this? + mThumbnailData.windowingMode = WINDOWING_MODE_FULLSCREEN; + + mThumbnailPosition.set(runningTarget.screenSpaceBounds); + // TODO: Should sourceContainerBounds already have this offset? + mThumbnailPosition.offsetTo(mRunningTarget.position.x, mRunningTarget.position.y); + + mLayoutValid = false; + } + + /** + * Updates the scroll for RecentsView + */ + public void setScroll(int scroll) { + if (mScrollState.scroll != scroll) { + mScrollState.scroll = scroll; + mScrollValid = false; + } + } + + /** + * Sets an alternate function which can be used to control the alpha + */ + public void setTaskAlphaCallback(TargetAlphaProvider callback) { + mTaskAlphaCallback = callback; + } + + /** + * Applies the target to the previously set parameters + */ + public void apply(TransformParams params) { + if (mDp == null || mRunningTarget == null) { + return; + } + if (!mLayoutValid) { + mLayoutValid = true; + + getFullScreenScale(); + mThumbnailData.rotation = FeatureFlags.ENABLE_FIXED_ROTATION_TRANSFORM.get() + ? mOrientationState.getDisplayRotation() : mPositionHelper.getCurrentRotation(); + + mPositionHelper.updateThumbnailMatrix(mThumbnailPosition, mThumbnailData, + mDp.isMultiWindowMode, mTaskRect.width(), mTaskRect.height()); + + mPositionHelper.getMatrix().invert(mInversePositionMatrix); + + PagedOrientationHandler poh = mOrientationState.getOrientationHandler(); + mScrollState.halfPageSize = + poh.getPrimaryValue(mTaskRect.width(), mTaskRect.height()) / 2; + mScrollState.halfScreenSize = poh.getPrimaryValue(mDp.widthPx, mDp.heightPx) / 2; + mScrollValid = false; + } + + if (!mScrollValid) { + mScrollValid = true; + int start = mOrientationState.getOrientationHandler() + .getPrimaryValue(mTaskRect.left, mTaskRect.top); + mScrollState.screenCenter = start + mScrollState.scroll + mScrollState.halfPageSize; + mScrollState.updateInterpolation(start, mPageSpacing); + mCurveScale = TaskView.getCurveScaleForInterpolation(mScrollState.linearInterpolation); + } + + float progress = Utilities.boundToRange(fullScreenProgress.value, 0, 1); + mCurrentFullscreenParams.setProgress( + progress, recentsViewScale.value, mTaskRect.width(), mDp, mPositionHelper); + + // Apply thumbnail matrix + RectF insets = mCurrentFullscreenParams.mCurrentDrawnInsets; + float scale = mCurrentFullscreenParams.mScale; + float taskWidth = mTaskRect.width(); + float taskHeight = mTaskRect.height(); + + mMatrix.set(mPositionHelper.getMatrix()); + mMatrix.postScale(scale, scale); + mMatrix.postTranslate(insets.left, insets.top); + + // Apply TaskView matrix: scale, translate, scroll + mMatrix.postScale(mCurveScale, mCurveScale, taskWidth / 2, taskHeight / 2); + mMatrix.postTranslate(mTaskRect.left, mTaskRect.top); + mOrientationState.getOrientationHandler().set( + mMatrix, MATRIX_POST_TRANSLATE, mScrollState.scroll); + + // Apply recensView matrix + mMatrix.postScale(recentsViewScale.value, recentsViewScale.value, mPivot.x, mPivot.y); + postDisplayRotation(mOrientationState.getDisplayRotation(), + mDp.widthPx, mDp.heightPx, mMatrix); + + // Crop rect is the inverse of thumbnail matrix + mTempRectF.set(-insets.left, -insets.top, + taskWidth + insets.right, taskHeight + insets.bottom); + mInversePositionMatrix.mapRect(mTempRectF); + mTempRectF.roundOut(mTmpCropRect); + + SurfaceParams[] surfaceParams = new SurfaceParams[mAllTargets.unfilteredApps.length]; + for (int i = 0; i < mAllTargets.unfilteredApps.length; i++) { + RemoteAnimationTargetCompat app = mAllTargets.unfilteredApps[i]; + SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash) + .withLayer(RemoteAnimationProvider.getLayer(app, mBoostModeTargetLayers)); + + if (app.mode == mAllTargets.targetMode) { + float alpha = mTaskAlphaCallback.getAlpha(app, params.getTargetAlpha()); + if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) { + // Fade out Assistant overlay. + if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT + && app.isNotInRecents) { + alpha = Interpolators.ACCEL_2.getInterpolation(fullScreenProgress.value); + } + + builder.withAlpha(alpha) + .withMatrix(mMatrix) + .withWindowCrop(mTmpCropRect) + .withCornerRadius(mCurrentFullscreenParams.mCurrentDrawnCornerRadius); + } else if (params.getTargetSet().hasRecents) { + // If home has a different target then recents, reverse anim the home target. + builder.withAlpha(fullScreenProgress.value * params.getTargetAlpha()); + } + } else { + builder.withAlpha(1); + if (ENABLE_QUICKSTEP_LIVE_TILE.get() && params.isLauncherOnTop()) { + builder.withLayer(Integer.MAX_VALUE); + } + } + surfaceParams[i] = builder.build(); + } + + applySurfaceParams(params.getSyncTransactionApplier(), surfaceParams); + } + + /** + * Interface for calculating taskSize + */ + public interface TaskSizeProvider { + + /** + * Sets the outRect to the expected taskSize + */ + void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect); + } + +} diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java index 78d75c5e82..454223e06f 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java @@ -183,27 +183,6 @@ public class LauncherRecentsView extends RecentsView LayoutUtils.calculateLauncherTaskSize(getContext(), dp, outRect); } - /** - * @return The translationX to apply to this view so that the first task is just offscreen. - */ - public float getOffscreenTranslationX(float recentsScale) { - LauncherState.ScaleAndTranslation overviewScaleAndTranslation = - NORMAL.getOverviewScaleAndTranslation(mActivity); - float offscreen = mOrientationHandler.getTranslationValue(overviewScaleAndTranslation); - // Offset since scale pushes tasks outwards. - getTaskSize(sTempRect); - int taskSize = mOrientationHandler.getPrimarySize(sTempRect); - offscreen += taskSize * (recentsScale - 1) / 2; - if (mRunningTaskTileHidden) { - // The first task is hidden, so offset by its width. - offscreen -= (taskSize + getPageSpacing()) * recentsScale; - } - if (isRtl()) { - offscreen = -offscreen; - } - return offscreen; - } - @Override protected void onTaskLaunchAnimationUpdate(float progress, TaskView tv) { if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { 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 18e876817e..eee35d10aa 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 @@ -56,6 +56,7 @@ import android.content.Intent; import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Point; +import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; @@ -90,7 +91,6 @@ import com.android.launcher3.BaseActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.LauncherState; import com.android.launcher3.PagedView; import com.android.launcher3.R; import com.android.launcher3.Utilities; @@ -123,7 +123,6 @@ import com.android.quickstep.TaskThumbnailCache; import com.android.quickstep.TaskUtils; import com.android.quickstep.ViewUtils; import com.android.quickstep.util.AppWindowAnimationHelper; -import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.util.RecentsOrientedState; import com.android.systemui.plugins.ResourceProvider; import com.android.systemui.shared.recents.IPinnedStackAnimationListener; @@ -175,8 +174,23 @@ public abstract class RecentsView extends PagedView impl } }; - protected RecentsOrientedState mOrientationState; + public static final FloatProperty ADJACENT_PAGE_OFFSET = + new FloatProperty("adjacentPageOffset") { + @Override + public void setValue(RecentsView recentsView, float v) { + if (recentsView.mAdjacentPageOffset != v) { + recentsView.mAdjacentPageOffset = v; + recentsView.updateAdjacentPageOffset(); + } + } + @Override + public Float get(RecentsView recentsView) { + return recentsView.mAdjacentPageOffset; + } + }; + + protected final RecentsOrientedState mOrientationState; private OrientationEventListener mOrientationListener; private int mPreviousRotation; protected RecentsAnimationController mRecentsAnimationController; @@ -188,6 +202,7 @@ public abstract class RecentsView extends PagedView impl protected boolean mEnableDrawingLiveTile = false; protected final Rect mTempRect = new Rect(); protected final RectF mTempRectF = new RectF(); + private final PointF mTempPointF = new PointF(); private static final int DISMISS_TASK_DURATION = 300; private static final int ADDITION_TASK_DURATION = 200; @@ -198,7 +213,6 @@ public abstract class RecentsView extends PagedView impl private final float mFastFlingVelocity; private final RecentsModel mModel; private final int mTaskTopMargin; - private final int mTaskBottomMargin; private final ClearAllButton mClearAllButton; private final Rect mClearAllButtonDeadZoneRect = new Rect(); private final Rect mTaskViewDeadZoneRect = new Rect(); @@ -217,6 +231,8 @@ public abstract class RecentsView extends PagedView impl private boolean mOverlayEnabled; protected boolean mFreezeViewVisibility; + private float mAdjacentPageOffset = 0; + /** * TODO: Call reloadIdNeeded in onTaskStackChanged. */ @@ -352,7 +368,7 @@ public abstract class RecentsView extends PagedView impl mFastFlingVelocity = getResources() .getDimensionPixelSize(R.dimen.recents_fast_fling_velocity); - mActivity = (T) BaseActivity.fromContext(context); + mActivity = BaseActivity.fromContext(context); mModel = RecentsModel.INSTANCE.get(context); mIdp = InvariantDeviceProfile.INSTANCE.get(context); mTempAppWindowAnimationHelper = @@ -368,7 +384,6 @@ public abstract class RecentsView extends PagedView impl setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR); mTaskTopMargin = getResources() .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin); - mTaskBottomMargin = LayoutUtils.thumbnailBottomMargin(context); mSquaredTouchSlop = squaredTouchSlop(context); mEmptyIcon = context.getDrawable(R.drawable.ic_empty_recents); @@ -830,7 +845,6 @@ public abstract class RecentsView extends PagedView impl mTaskHeight = mTempRect.height(); mTempRect.top -= mTaskTopMargin; - mTempRect.bottom += mTaskBottomMargin; setPadding(mTempRect.left - mInsets.left, mTempRect.top - mInsets.top, dp.widthPx - mInsets.right - mTempRect.right, dp.heightPx - mInsets.bottom - mTempRect.bottom); @@ -1621,11 +1635,6 @@ public abstract class RecentsView extends PagedView impl return getTaskViewAtByAbsoluteIndex(getRunningTaskIndex() + 1); } - @Nullable - public TaskView getPreviousTaskView() { - return getTaskViewAtByAbsoluteIndex(getRunningTaskIndex() - 1); - } - @Nullable public TaskView getCurrentPageTaskView() { return getTaskViewAtByAbsoluteIndex(getCurrentPage()); @@ -1685,11 +1694,29 @@ public abstract class RecentsView extends PagedView impl updateEmptyStateUi(changed); - // Set the pivot points to match the task preview center - setPivotY(((mInsets.top + getPaddingTop() + mTaskTopMargin) - + (getHeight() - mInsets.bottom - getPaddingBottom() - mTaskBottomMargin)) / 2); - setPivotX(((mInsets.left + getPaddingLeft()) - + (getWidth() - mInsets.right - getPaddingRight())) / 2); + // Update the pivots such that when the task is scaled, it fills the full page + getTaskSize(mTempRect); + getPagedViewOrientedState().getFullScreenScaleAndPivot( + mTempRect, mActivity.getDeviceProfile(), mTempPointF); + setPivotX(mTempPointF.x); + setPivotY(mTempPointF.y); + updateAdjacentPageOffset(); + } + + private void updateAdjacentPageOffset() { + float offset = mAdjacentPageOffset * getWidth(); + if (mIsRtl) { + offset = -offset; + } + int count = getChildCount(); + + TaskView runningTask = mRunningTaskId == -1 ? null : getTaskView(mRunningTaskId); + int midPoint = runningTask == null ? -1 : indexOfChild(runningTask); + + for (int i = 0; i < count; i++) { + getChildAt(i).setTranslationX(i == midPoint ? 0 : (i < midPoint ? -offset : offset)); + } + updateCurveProperties(); } private void updateDeadZoneRects() { @@ -1771,14 +1798,10 @@ public abstract class RecentsView extends PagedView impl int centerTaskIndex = getCurrentPage(); boolean launchingCenterTask = taskIndex == centerTaskIndex; - LauncherState.ScaleAndTranslation toScaleAndTranslation = appWindowAnimationHelper - .getScaleAndTranslation(); - float toScale = toScaleAndTranslation.scale; - float toTranslationY = toScaleAndTranslation.translationY; + float toScale = appWindowAnimationHelper.getSrcToTargetScale(); if (launchingCenterTask) { RecentsView recentsView = tv.getRecentsView(); anim.play(ObjectAnimator.ofFloat(recentsView, SCALE_PROPERTY, toScale)); - anim.play(ObjectAnimator.ofFloat(recentsView, TRANSLATION_Y, toTranslationY)); anim.play(ObjectAnimator.ofFloat(recentsView, FULLSCREEN_PROGRESS, 1)); } else { // We are launching an adjacent task, so parallax the center and other adjacent task. @@ -2038,17 +2061,23 @@ public abstract class RecentsView extends PagedView impl return mClearAllButton; } + /** * @return How many pixels the running task is offset on the x-axis due to the current scrollX. */ - public float getScrollOffset() { + public int getScrollOffset() { if (getRunningTaskIndex() == -1) { return 0; } - int startScroll = getScrollForPage(getRunningTaskIndex()); - int offsetX = startScroll - mOrientationHandler.getPrimaryScroll(this); - offsetX *= mOrientationHandler.getPrimaryScale(this); - return offsetX; + return getScrollForPage(getRunningTaskIndex()) - mOrientationHandler.getPrimaryScroll(this); + } + + /** + * @return How many pixels the running task is offset on the x-axis due to the current scrollX + * and parent scale. + */ + public float getScrollOffsetScaled() { + return getScrollOffset() * mOrientationHandler.getPrimaryScale(this); } public Consumer getEventDispatcher(float navbarRotation) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java index 178ff32b4a..a05e0fa4fc 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java @@ -36,11 +36,9 @@ import android.graphics.RectF; import android.graphics.Shader; import android.util.AttributeSet; import android.util.FloatProperty; -import android.util.Log; import android.util.Property; import android.view.Surface; import android.view.View; -import android.view.ViewGroup; import com.android.launcher3.BaseActivity; import com.android.launcher3.R; @@ -50,7 +48,7 @@ import com.android.launcher3.util.SystemUiController; import com.android.launcher3.util.Themes; import com.android.quickstep.TaskOverlayFactory; import com.android.quickstep.TaskOverlayFactory.TaskOverlay; -import com.android.quickstep.util.TaskCornerRadius; +import com.android.quickstep.views.TaskView.FullscreenDrawParams; import com.android.systemui.plugins.OverviewScreenshotActions; import com.android.systemui.plugins.PluginListener; import com.android.systemui.shared.recents.model.Task; @@ -66,6 +64,8 @@ public class TaskThumbnailView extends View implements PluginListener DIM_ALPHA = new FloatProperty("dimAlpha") { @Override @@ -87,12 +87,11 @@ public class TaskThumbnailView extends View implements PluginListener 0 || mThumbnailData.isTranslucent) { + if (drawBackgroundOnly || mPreviewPositionHelper.mClipBottom > 0 + || mThumbnailData.isTranslucent) { canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mBackgroundPaint); if (drawBackgroundOnly) { return; } } - if (mClipBottom > 0) { + if (mPreviewPositionHelper.mClipBottom > 0) { canvas.save(); - canvas.clipRect(x, y, width, mClipBottom); + canvas.clipRect(x, y, width, mPreviewPositionHelper.mClipBottom); canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mPaint); canvas.restore(); } else { @@ -324,8 +321,9 @@ public class TaskThumbnailView extends View implements PluginListener 0 && windowingModeSupportsRotation; - // Scale the screenshot to always fit the width of the card. - - thumbnailScale = isOrientationDifferent - ? getMeasuredWidth() / thumbnailHeight - : getMeasuredWidth() / thumbnailWidth; - } - - if (!isRotated) { - // No Rotation - mClippedInsets.offsetTo(thumbnailInsets.left * scale, - thumbnailInsets.top * scale); - mMatrix.setTranslate(-mClippedInsets.left, -mClippedInsets.top); - } else { - setThumbnailRotation(deltaRotate, thumbnailInsets, scale); - } - - final float widthWithInsets; - final float heightWithInsets; - if (isOrientationDifferent) { - widthWithInsets = mThumbnailData.thumbnail.getHeight() * thumbnailScale; - heightWithInsets = mThumbnailData.thumbnail.getWidth() * thumbnailScale; - } else { - widthWithInsets = mThumbnailData.thumbnail.getWidth() * thumbnailScale; - heightWithInsets = mThumbnailData.thumbnail.getHeight() * thumbnailScale; - } - mClippedInsets.left *= thumbnailScale; - mClippedInsets.top *= thumbnailScale; - mClippedInsets.right = widthWithInsets - mClippedInsets.left - getMeasuredWidth(); - mClippedInsets.bottom = heightWithInsets - mClippedInsets.top - getMeasuredHeight(); - - mMatrix.postScale(thumbnailScale, thumbnailScale); - mBitmapShader.setLocalMatrix(mMatrix); - - float bitmapHeight = Math.max((isOrientationDifferent ? thumbnailWidth : thumbnailHeight) - * thumbnailScale, 0); - if (Math.round(bitmapHeight) < getMeasuredHeight()) { - mClipBottom = bitmapHeight; - } + mBitmapShader.setLocalMatrix(mPreviewPositionHelper.mMatrix); mPaint.setShader(mBitmapShader); } - - mIsOrientationChanged = isOrientationDifferent; invalidate(); // Update can be called from {@link #onSizeChanged} during layout, post handling of overlay @@ -423,51 +362,6 @@ public class TaskThumbnailView extends View implements PluginListener 0 && windowingModeSupportsRotation; + // Scale the screenshot to always fit the width of the card. + thumbnailScale = isOrientationDifferent + ? canvasWidth / thumbnailHeight + : canvasWidth / thumbnailWidth; + } + + if (!isRotated) { + // No Rotation + mClippedInsets.offsetTo(thumbnailInsets.left * scale, + thumbnailInsets.top * scale); + mMatrix.setTranslate(-mClippedInsets.left, -mClippedInsets.top); + } else { + setThumbnailRotation(deltaRotate, thumbnailInsets, scale, thumbnailPosition); + } + mMatrix.postTranslate(-thumbnailPosition.left, -thumbnailPosition.top); + + final float widthWithInsets; + final float heightWithInsets; + if (isOrientationDifferent) { + widthWithInsets = thumbnailPosition.height() * thumbnailScale; + heightWithInsets = thumbnailPosition.width() * thumbnailScale; + } else { + widthWithInsets = thumbnailPosition.width() * thumbnailScale; + heightWithInsets = thumbnailPosition.height() * thumbnailScale; + } + mClippedInsets.left *= thumbnailScale; + mClippedInsets.top *= thumbnailScale; + mClippedInsets.right = widthWithInsets - mClippedInsets.left - canvasWidth; + mClippedInsets.bottom = heightWithInsets - mClippedInsets.top - canvasHeight; + + mMatrix.postScale(thumbnailScale, thumbnailScale); + + float bitmapHeight = Math.max(0, + (isOrientationDifferent ? thumbnailWidth : thumbnailHeight) * thumbnailScale); + if (Math.round(bitmapHeight) < canvasHeight) { + mClipBottom = bitmapHeight; + } + mIsOrientationChanged = isOrientationDifferent; + } + + private int getRotationDelta(int oldRotation, int newRotation) { + int delta = newRotation - oldRotation; + if (delta < 0) delta += 4; + return delta; + } + + /** + * @param deltaRotation the number of 90 degree turns from the current orientation + * @return {@code true} if the change in rotation results in a shift from landscape to + * portrait or vice versa, {@code false} otherwise + */ + private boolean isOrientationChange(int deltaRotation) { + return deltaRotation == Surface.ROTATION_90 || deltaRotation == Surface.ROTATION_270; + } + + private void setThumbnailRotation(int deltaRotate, Rect thumbnailInsets, float scale, + Rect thumbnailPosition) { + int newLeftInset = 0; + int newTopInset = 0; + int translateX = 0; + int translateY = 0; + + mMatrix.setRotate(90 * deltaRotate); + switch (deltaRotate) { /* Counter-clockwise */ + case Surface.ROTATION_90: + newLeftInset = thumbnailInsets.bottom; + newTopInset = thumbnailInsets.left; + translateX = thumbnailPosition.height(); + break; + case Surface.ROTATION_270: + newLeftInset = thumbnailInsets.top; + newTopInset = thumbnailInsets.right; + translateY = thumbnailPosition.width(); + break; + case Surface.ROTATION_180: + newLeftInset = -thumbnailInsets.top; + newTopInset = -thumbnailInsets.left; + translateX = thumbnailPosition.width(); + translateY = thumbnailPosition.height(); + break; + } + mClippedInsets.offsetTo(newLeftInset * scale, newTopInset * scale); + mMatrix.postTranslate(translateX - mClippedInsets.left, + translateY - mClippedInsets.top); + } + + /** + * Insets to used for clipping the thumbnail (in case it is drawing outside its own space) + */ + public RectF getInsetsToDrawInFullscreen(boolean isMultiWindowMode) { + // Don't show insets in multi window mode. + return isMultiWindowMode ? EMPTY_RECT_F : mClippedInsets; + } + } } 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 470b720f5e..b0758c9e48 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 @@ -56,6 +56,7 @@ import android.widget.FrameLayout; import android.widget.Toast; import com.android.launcher3.BaseDraggingActivity; +import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; @@ -77,11 +78,11 @@ import com.android.quickstep.TaskIconCache; import com.android.quickstep.TaskOverlayFactory; import com.android.quickstep.TaskThumbnailCache; import com.android.quickstep.TaskUtils; -import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.util.RecentsOrientedState; import com.android.quickstep.util.TaskCornerRadius; import com.android.quickstep.views.RecentsView.PageCallbacks; import com.android.quickstep.views.RecentsView.ScrollState; +import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.ActivityOptionsCompat; @@ -157,8 +158,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { private float mCurveScale; private float mFullscreenProgress; private final FullscreenDrawParams mCurrentFullscreenParams; - private final float mCornerRadius; - private final float mWindowCornerRadius; private final BaseDraggingActivity mActivity; private ObjectAnimator mIconAndDimAnimator; @@ -211,9 +210,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { TaskUtils.getLaunchComponentKeyForTask(getTask().key)); mActivity.getStatsLogManager().log(TASK_LAUNCH_TAP, buildProto()); }); - mCornerRadius = TaskCornerRadius.get(context); - mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context.getResources()); - mCurrentFullscreenParams = new FullscreenDrawParams(mCornerRadius); + + mCurrentFullscreenParams = new FullscreenDrawParams(context); mDigitalWellBeingToast = new DigitalWellBeingToast(mActivity, this); mOutlineProvider = new TaskOutlineProvider(getContext(), mCurrentFullscreenParams); @@ -236,11 +234,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { super.onFinishInflate(); mSnapshotView = findViewById(R.id.snapshot); mIconView = findViewById(R.id.icon); - final Context context = getContext(); - - TaskView.LayoutParams thumbnailParams = (LayoutParams) mSnapshotView.getLayoutParams(); - thumbnailParams.bottomMargin = LayoutUtils.thumbnailBottomMargin(context); - mSnapshotView.setLayoutParams(thumbnailParams); } public boolean isTaskOverlayModal() { @@ -473,8 +466,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { int iconRotation = orientationState.getTouchRotation(); PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler(); boolean isRtl = orientationHandler.getRecentsRtlSetting(getResources()); - LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams(); - snapshotParams.bottomMargin = LayoutUtils.thumbnailBottomMargin(getContext()); int thumbnailPadding = (int) getResources().getDimension(R.dimen.task_thumbnail_top_margin); LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams(); int rotation = orientationState.getTouchRotationDegrees(); @@ -501,7 +492,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { iconParams.bottomMargin = 0; break; } - mSnapshotView.setLayoutParams(snapshotParams); mIconView.setLayoutParams(iconParams); mIconView.setRotation(rotation); } @@ -699,21 +689,16 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { return 1 - curveInterpolation * EDGE_SCALE_DOWN_FACTOR; } - public void setCurveScale(float curveScale) { + private void setCurveScale(float curveScale) { mCurveScale = curveScale; - onScaleChanged(); + setScaleX(mCurveScale); + setScaleY(mCurveScale); } public float getCurveScale() { return mCurveScale; } - private void onScaleChanged() { - float scale = mCurveScale; - setScaleX(scale); - setScaleY(scale); - } - @Override public boolean hasOverlappingRendering() { // TODO: Clip-out the icon region from the thumbnail, since they are overlapping. @@ -723,13 +708,11 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { private static final class TaskOutlineProvider extends ViewOutlineProvider { private final int mMarginTop; - private final int mMarginBottom; private FullscreenDrawParams mFullscreenParams; TaskOutlineProvider(Context context, FullscreenDrawParams fullscreenParams) { mMarginTop = context.getResources().getDimensionPixelSize( R.dimen.task_thumbnail_top_margin); - mMarginBottom = LayoutUtils.thumbnailBottomMargin(context); mFullscreenParams = fullscreenParams; } @@ -744,7 +727,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { outline.setRoundRect(0, (int) (mMarginTop * scale), (int) ((insets.left + view.getWidth() + insets.right) * scale), - (int) ((insets.top + view.getHeight() + insets.bottom - mMarginBottom) * scale), + (int) ((insets.top + view.getHeight() + insets.bottom) * scale), mFullscreenParams.mCurrentDrawnCornerRadius); } } @@ -917,23 +900,11 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { setClipToPadding(!isFullscreen); TaskThumbnailView thumbnail = getThumbnail(); - boolean isMultiWindowMode = mActivity.getDeviceProfile().isMultiWindowMode; - RectF insets = thumbnail.getInsetsToDrawInFullscreen(isMultiWindowMode); - float currentInsetsLeft = insets.left * mFullscreenProgress; - float currentInsetsRight = insets.right * mFullscreenProgress; - mCurrentFullscreenParams.setInsets(currentInsetsLeft, - insets.top * mFullscreenProgress, - currentInsetsRight, - insets.bottom * mFullscreenProgress); - float fullscreenCornerRadius = isMultiWindowMode ? 0 : mWindowCornerRadius; - mCurrentFullscreenParams.setCornerRadius(Utilities.mapRange(mFullscreenProgress, - mCornerRadius, fullscreenCornerRadius) / getRecentsView().getScaleX()); - // We scaled the thumbnail to fit the content (excluding insets) within task view width. - // Now that we are drawing left/right insets again, we need to scale down to fit them. - if (getWidth() > 0) { - mCurrentFullscreenParams.setScale(getWidth() - / (getWidth() + currentInsetsLeft + currentInsetsRight)); - } + mCurrentFullscreenParams.setProgress( + mFullscreenProgress, + getRecentsView().getScaleX(), + getWidth(), mActivity.getDeviceProfile(), + thumbnail.getPreviewPositionHelper()); if (!getRecentsView().isTaskIconScaledDown(this)) { // Some of the items in here are dependent on the current fullscreen params, but don't @@ -971,26 +942,51 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { /** * We update and subsequently draw these in {@link #setFullscreenProgress(float)}. */ - static class FullscreenDrawParams { - RectF mCurrentDrawnInsets = new RectF(); - float mCurrentDrawnCornerRadius; + public static class FullscreenDrawParams { + + private final float mCornerRadius; + private final float mWindowCornerRadius; + + public RectF mCurrentDrawnInsets = new RectF(); + public float mCurrentDrawnCornerRadius; /** The current scale we apply to the thumbnail to adjust for new left/right insets. */ - float mScale = 1; + public float mScale = 1; - public FullscreenDrawParams(float cornerRadius) { - setCornerRadius(cornerRadius); + public FullscreenDrawParams(Context context) { + mCornerRadius = TaskCornerRadius.get(context); + mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context.getResources()); + + mCurrentDrawnCornerRadius = mCornerRadius; } - public void setInsets(float left, float top, float right, float bottom) { - mCurrentDrawnInsets.set(left, top, right, bottom); + public FullscreenDrawParams() { + mCurrentDrawnCornerRadius = mWindowCornerRadius = mCornerRadius = 0; } - public void setCornerRadius(float cornerRadius) { - mCurrentDrawnCornerRadius = cornerRadius; + /** + * Sets the progress in range [0, 1] + */ + public void setProgress(float fullscreenProgress, float parentScale, int previewWidth, + DeviceProfile dp, PreviewPositionHelper pph) { + boolean isMultiWindowMode = dp.isMultiWindowMode; + RectF insets = pph.getInsetsToDrawInFullscreen(isMultiWindowMode); + + float currentInsetsLeft = insets.left * fullscreenProgress; + float currentInsetsRight = insets.right * fullscreenProgress; + mCurrentDrawnInsets.set(currentInsetsLeft, insets.top * fullscreenProgress, + currentInsetsRight, insets.bottom * fullscreenProgress); + float fullscreenCornerRadius = isMultiWindowMode ? 0 : mWindowCornerRadius; + + mCurrentDrawnCornerRadius = + Utilities.mapRange(fullscreenProgress, mCornerRadius, fullscreenCornerRadius) + / parentScale; + + // We scaled the thumbnail to fit the content (excluding insets) within task view width. + // Now that we are drawing left/right insets again, we need to scale down to fit them. + if (previewWidth > 0) { + mScale = previewWidth / (previewWidth + currentInsetsLeft + currentInsetsRight); + } } - public void setScale(float scale) { - mScale = scale; - } } } diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index b7abd619cd..65763d45ef 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -29,7 +29,6 @@ import android.content.SharedPreferences; import android.os.Bundle; import android.os.CancellationSignal; -import com.android.launcher3.LauncherState.ScaleAndTranslation; import com.android.launcher3.LauncherStateManager.StateHandler; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.WellbeingModel; @@ -38,7 +37,6 @@ import com.android.launcher3.proxy.ProxyActivityStarter; import com.android.launcher3.proxy.StartActivityParams; import com.android.launcher3.statehandlers.BackButtonAlphaHandler; import com.android.launcher3.statehandlers.DepthController; -import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.uioverrides.RecentsViewStateController; import com.android.launcher3.util.OnboardingPrefs; import com.android.launcher3.util.UiThreadHelper; @@ -204,17 +202,6 @@ public abstract class BaseQuickstepLauncher extends Launcher return new QuickstepOnboardingPrefs(this, sharedPrefs, stateManager); } - @Override - protected ScaleAndTranslation getOverviewScaleAndTranslationForNormalState() { - if (SysUINavigationMode.getMode(this) == Mode.NO_BUTTON) { - PagedOrientationHandler layoutVertical = - ((RecentsView)getOverviewPanel()).getPagedViewOrientedState().getOrientationHandler(); - return layoutVertical.getScaleAndTranslation(getDeviceProfile(), - getOverviewPanel()); - } - return super.getOverviewScaleAndTranslationForNormalState(); - } - @Override public void useFadeOutAnimationForLauncherStart(CancellationSignal signal) { QuickstepAppTransitionManagerImpl appTransitionManager = @@ -237,6 +224,12 @@ public abstract class BaseQuickstepLauncher extends Launcher }, signal); } + @Override + public float[] getNormalOverviewScaleAndOffset() { + return SysUINavigationMode.getMode(this) == Mode.NO_BUTTON + ? new float[] {1, 1} : new float[] {1.1f, 0}; + } + @Override public void onDragLayerHierarchyChanged() { onLauncherStateOrFocusChanged(); diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java index 0f45196ec4..33011acb09 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java @@ -17,8 +17,6 @@ package com.android.launcher3.uioverrides; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; -import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X; -import static com.android.launcher3.LauncherAnimUtils.VIEW_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; @@ -26,23 +24,22 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FA 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 static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET; import android.util.FloatProperty; -import android.view.View; import androidx.annotation.NonNull; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.LauncherState; -import com.android.launcher3.LauncherState.ScaleAndTranslation; import com.android.launcher3.LauncherStateManager.StateHandler; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.graphics.OverviewScrim; import com.android.launcher3.states.StateAnimationConfig; +import com.android.quickstep.views.RecentsView; /** * State handler for recents view. Manages UI changes and animations for recents view based off the @@ -50,7 +47,7 @@ import com.android.launcher3.states.StateAnimationConfig; * * @param the recents view */ -public abstract class BaseRecentsViewStateController +public abstract class BaseRecentsViewStateController implements StateHandler { protected final T mRecentsView; protected final BaseQuickstepLauncher mLauncher; @@ -62,14 +59,9 @@ public abstract class BaseRecentsViewStateController @Override public void setState(@NonNull LauncherState state) { - ScaleAndTranslation scaleAndTranslation = state.getOverviewScaleAndTranslation(mLauncher); - float translationX = scaleAndTranslation.translationX; - if (mRecentsView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) { - translationX = -translationX; - } - SCALE_PROPERTY.set(mRecentsView, scaleAndTranslation.scale); - mRecentsView.setTranslationX(translationX); - mRecentsView.setTranslationY(scaleAndTranslation.translationY); + float[] scaleAndOffset = state.getOverviewScaleAndOffset(mLauncher); + SCALE_PROPERTY.set(mRecentsView, scaleAndOffset[0]); + ADJACENT_PAGE_OFFSET.set(mRecentsView, scaleAndOffset[1]); getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0); OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim(); @@ -98,17 +90,11 @@ public abstract class BaseRecentsViewStateController */ void setStateWithAnimationInternal(@NonNull final LauncherState toState, @NonNull StateAnimationConfig config, @NonNull PendingAnimation setter) { - ScaleAndTranslation scaleAndTranslation = toState.getOverviewScaleAndTranslation(mLauncher); - float translationX = scaleAndTranslation.translationX; - if (mRecentsView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) { - translationX = -translationX; - } - setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleAndTranslation.scale, + float[] scaleAndOffset = toState.getOverviewScaleAndOffset(mLauncher); + setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleAndOffset[0], config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR)); - setter.setFloat(mRecentsView, VIEW_TRANSLATE_X, translationX, + setter.setFloat(mRecentsView, ADJACENT_PAGE_OFFSET, scaleAndOffset[1], config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR)); - setter.setFloat(mRecentsView, VIEW_TRANSLATE_Y, scaleAndTranslation.translationY, - config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR)); setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0, config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT)); diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java index 93e02a111f..33f380f99f 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java @@ -102,9 +102,8 @@ public class AllAppsState extends LauncherState { } @Override - public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) { - float slightParallax = -launcher.getDeviceProfile().allAppsCellHeightPx * 0.3f; - return new ScaleAndTranslation(0.9f, 0f, slightParallax); + public float[] getOverviewScaleAndOffset(Launcher launcher) { + return new float[] {0.9f, 0}; } @Override diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java index 94ef15a076..e4bb9aa3ac 100644 --- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java +++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java @@ -135,8 +135,6 @@ public interface BaseActivityInterface { void createActivityInterface(long transitionLength); - default void adjustActivityControllerInterpolators() { } - default void onTransitionCancelled() { } default void setShelfState(ShelfPeekAnim.ShelfAnimState animState, diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java index 1f1a99937e..4edf2fbab0 100644 --- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java +++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java @@ -63,7 +63,7 @@ public class LayoutUtils { if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) { //TODO: this needs to account for the swipe gesture height and accessibility // UI when shown. - extraSpace = 0; + extraSpace = res.getDimensionPixelSize(R.dimen.overview_actions_height); } else { extraSpace = getDefaultSwipeHeight(context, dp) + dp.workspacePageIndicatorHeight + res.getDimensionPixelSize( @@ -75,7 +75,14 @@ public class LayoutUtils { } public static void calculateFallbackTaskSize(Context context, DeviceProfile dp, Rect outRect) { - calculateTaskSize(context, dp, 0, MULTI_WINDOW_STRATEGY_DEVICE_PROFILE, outRect); + float extraSpace; + if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) { + extraSpace = context.getResources() + .getDimensionPixelSize(R.dimen.overview_actions_height); + } else { + extraSpace = 0; + } + calculateTaskSize(context, dp, extraSpace, MULTI_WINDOW_STRATEGY_DEVICE_PROFILE, outRect); } @AnyThread @@ -123,8 +130,6 @@ public class LayoutUtils { } float topIconMargin = res.getDimension(R.dimen.task_thumbnail_top_margin); - float bottomMargin = thumbnailBottomMargin(context); - float paddingVert = overviewActionsEnabled && removeShelfFromOverview(context) ? 0 : res.getDimension(R.dimen.task_card_vert_space); @@ -134,7 +139,7 @@ public class LayoutUtils { int launcherVisibleHeight = dp.heightPx - insets.top - insets.bottom; float availableHeight = launcherVisibleHeight - - topIconMargin - extraVerticalSpace - paddingVert - bottomMargin; + - topIconMargin - extraVerticalSpace - paddingVert; float availableWidth = launcherVisibleWidth - paddingHorz; float scale = Math.min(availableWidth / taskWidth, availableHeight / taskHeight); @@ -144,7 +149,7 @@ public class LayoutUtils { // Center in the visible space float x = insets.left + (launcherVisibleWidth - outWidth) / 2; float y = insets.top + Math.max(topIconMargin, - (launcherVisibleHeight - extraVerticalSpace - outHeight - bottomMargin) / 2); + (launcherVisibleHeight - extraVerticalSpace - outHeight) / 2); outRect.set(Math.round(x), Math.round(y), Math.round(x) + Math.round(outWidth), Math.round(y) + Math.round(outHeight)); } @@ -163,14 +168,16 @@ public class LayoutUtils { } /** - * Get the margin that the task thumbnail view should use. - * @return the margin in pixels. + * Gets the scale that should be applied to the TaskView so that it matches the target */ - public static int thumbnailBottomMargin(Context context) { - if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) { - return context.getResources().getDimensionPixelSize(R.dimen.overview_actions_height); + public static float getTaskScale(RecentsOrientedState orientedState, + float srcWidth, float srcHeight, float targetWidth, float targetHeight) { + if (orientedState == null + || orientedState.isHomeRotationAllowed() + || orientedState.isDisplayPhoneNatural()) { + return srcWidth / targetWidth; } else { - return 0; + return srcHeight / targetHeight; } } } diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java index bc0d2cc9f3..5be0675cbb 100644 --- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java +++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java @@ -18,9 +18,9 @@ package com.android.quickstep.util; import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.hardware.camera2.params.OutputConfiguration.ROTATION_180; import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE; import static android.view.Surface.ROTATION_0; +import static android.view.Surface.ROTATION_180; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; @@ -28,6 +28,7 @@ import static com.android.launcher3.config.FeatureFlags.FLAG_ENABLE_FIXED_ROTATI import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY; import static com.android.launcher3.states.RotationHelper.FIXED_ROTATION_TRANSFORM_SETTING_NAME; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; + import static java.lang.annotation.RetentionPolicy.SOURCE; import android.content.ContentResolver; @@ -36,6 +37,8 @@ import android.content.SharedPreferences; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Matrix; +import android.graphics.PointF; +import android.graphics.Rect; import android.graphics.RectF; import android.os.Handler; import android.provider.Settings; @@ -45,6 +48,7 @@ import android.view.Surface; import androidx.annotation.IntDef; +import com.android.launcher3.DeviceProfile; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.touch.PagedOrientationHandler; @@ -135,7 +139,7 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre */ public boolean update( @SurfaceRotation int touchRotation, @SurfaceRotation int displayRotation, - int launcherRotation) { + @SurfaceRotation int launcherRotation) { if (!FeatureFlags.ENABLE_FIXED_ROTATION_TRANSFORM.get()) { return false; } @@ -277,6 +281,25 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre } } + /** + * Returns the scale and pivot so that the provided taskRect can fit the provided full size + */ + public float getFullScreenScaleAndPivot(Rect taskView, DeviceProfile dp, PointF outPivot) { + Rect insets = dp.getInsets(); + float fullWidth = dp.widthPx - insets.left - insets.right; + float fullHeight = dp.heightPx - insets.top - insets.bottom; + final float scale = LayoutUtils.getTaskScale(this, + fullWidth, fullHeight, taskView.width(), taskView.height()); + + if (scale == 1) { + outPivot.set(fullWidth / 2, fullHeight / 2); + } else { + float factor = scale / (scale - 1); + outPivot.set(taskView.left * factor, taskView.top * factor); + } + return scale; + } + public PagedOrientationHandler getOrientationHandler() { return mOrientationHandler; } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index bf05a245b7..c4eab8fb49 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -25,6 +25,8 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_SNACKBAR; import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; +import static com.android.launcher3.LauncherState.NO_OFFSET; +import static com.android.launcher3.LauncherState.NO_SCALE; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherState.OVERVIEW_PEEK; import static com.android.launcher3.Utilities.postAsyncCallback; @@ -85,7 +87,6 @@ import androidx.annotation.StringRes; import androidx.annotation.VisibleForTesting; import com.android.launcher3.DropTarget.DragObject; -import com.android.launcher3.LauncherState.ScaleAndTranslation; import com.android.launcher3.LauncherStateManager.StateHandler; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.allapps.AllAppsContainerView; @@ -2698,10 +2699,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, return new TouchController[] {getDragController(), new AllAppsSwipeController(this)}; } - protected ScaleAndTranslation getOverviewScaleAndTranslationForNormalState() { - return new ScaleAndTranslation(1.1f, 0f, 0f); - } - public void useFadeOutAnimationForLauncherStart(CancellationSignal signal) { } public void onDragLayerHierarchyChanged() { } @@ -2724,6 +2721,14 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, return Stream.of(APP_INFO, WIDGETS, INSTALL); } + + /** + * @see LauncherState#getOverviewScaleAndOffset(Launcher) + */ + public float[] getNormalOverviewScaleAndOffset() { + return new float[] {NO_SCALE, NO_OFFSET}; + } + public static Launcher getLauncher(Context context) { return fromContext(context); } @@ -2735,6 +2740,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, return (T) activityContext; } + /** * Callback for listening for onResume */ diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java index 504666a4c2..e799df7b68 100644 --- a/src/com/android/launcher3/LauncherState.java +++ b/src/com/android/launcher3/LauncherState.java @@ -90,6 +90,9 @@ public abstract class LauncherState { protected static final int FLAG_HIDE_BACK_BUTTON = 1 << 8; protected static final int FLAG_HAS_SYS_UI_SCRIM = 1 << 9; + public static final float NO_OFFSET = 0; + public static final float NO_SCALE = 1; + protected static final PageAlphaProvider DEFAULT_ALPHA_PROVIDER = new PageAlphaProvider(ACCEL_2) { @Override @@ -220,7 +223,7 @@ public abstract class LauncherState { public abstract int getTransitionDuration(Launcher launcher); public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) { - return new ScaleAndTranslation(1, 0, 0); + return new ScaleAndTranslation(NO_SCALE, NO_OFFSET, NO_OFFSET); } public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) { @@ -228,12 +231,18 @@ public abstract class LauncherState { return getWorkspaceScaleAndTranslation(launcher); } - public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) { - return launcher.getOverviewScaleAndTranslationForNormalState(); + /** + * Returns an array of two elements. + * The first specifies the scale for the overview + * The second is the factor ([0, 1], 0 => center-screen; 1 => offscreen) by which overview + * should be shifted horizontally. + */ + public float[] getOverviewScaleAndOffset(Launcher launcher) { + return launcher.getNormalOverviewScaleAndOffset(); } public ScaleAndTranslation getQsbScaleAndTranslation(Launcher launcher) { - return new ScaleAndTranslation(1, 0, 0); + return new ScaleAndTranslation(NO_SCALE, NO_OFFSET, NO_OFFSET); } public float getOverviewFullscreenProgress() { diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java index f9f3bf4bc1..e290685d5e 100644 --- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java @@ -32,7 +32,6 @@ import android.view.View; import android.view.accessibility.AccessibilityEvent; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.LauncherState.ScaleAndTranslation; import com.android.launcher3.PagedView; import com.android.launcher3.Utilities; import com.android.launcher3.util.OverScroller; @@ -119,11 +118,6 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { return view.getMeasuredHeight(); } - @Override - public int getPrimarySize(Rect rect) { - return rect.height(); - } - @Override public float getPrimarySize(RectF rect) { return rect.height(); @@ -134,17 +128,6 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { return view.getWidth(); } - @Override - public ScaleAndTranslation getScaleAndTranslation(DeviceProfile dp, View view) { - float offscreenTranslationY = dp.heightPx - view.getPaddingTop(); - return new ScaleAndTranslation(1f, 0f, offscreenTranslationY); - } - - @Override - public float getTranslationValue(ScaleAndTranslation scaleAndTranslation) { - return scaleAndTranslation.translationY; - } - @Override public FloatProperty getPrimaryViewTranslate() { return VIEW_TRANSLATE_Y; diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java index ba4c064f5b..b8396e1119 100644 --- a/src/com/android/launcher3/touch/PagedOrientationHandler.java +++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java @@ -18,6 +18,7 @@ package com.android.launcher3.touch; import android.content.res.Resources; import android.graphics.Canvas; +import android.graphics.Matrix; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; @@ -28,7 +29,6 @@ import android.view.View; import android.view.accessibility.AccessibilityEvent; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.LauncherState; import com.android.launcher3.PagedView; import com.android.launcher3.util.OverScroller; @@ -53,16 +53,15 @@ public interface PagedOrientationHandler { Int2DAction VIEW_SCROLL_BY = View::scrollBy; Int2DAction VIEW_SCROLL_TO = View::scrollTo; Float2DAction CANVAS_TRANSLATE = Canvas::translate; + Float2DAction MATRIX_POST_TRANSLATE = Matrix::postTranslate; + void set(T target, Int2DAction action, int param); void set(T target, Float2DAction action, float param); float getPrimaryDirection(MotionEvent event, int pointerIndex); float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId); int getMeasuredSize(View view); - int getPrimarySize(Rect rect); float getPrimarySize(RectF rect); int getSecondaryDimension(View view); - LauncherState.ScaleAndTranslation getScaleAndTranslation(DeviceProfile dp, View view); - float getTranslationValue(LauncherState.ScaleAndTranslation scaleAndTranslation); FloatProperty getPrimaryViewTranslate(); FloatProperty getSecondaryViewTranslate(); void setPrimaryAndResetSecondaryTranslate(View view, float translation); @@ -98,7 +97,6 @@ public interface PagedOrientationHandler { */ void adjustFloatingIconStartVelocity(PointF velocity); - class CurveProperties { public int scroll; public int halfPageSize; diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java index 7c44ebab0c..dad00a4b5b 100644 --- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java +++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java @@ -32,7 +32,6 @@ import android.view.View; import android.view.accessibility.AccessibilityEvent; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.LauncherState.ScaleAndTranslation; import com.android.launcher3.PagedView; import com.android.launcher3.Utilities; import com.android.launcher3.util.OverScroller; @@ -117,11 +116,6 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { return view.getMeasuredWidth(); } - @Override - public int getPrimarySize(Rect rect) { - return rect.width(); - } - @Override public float getPrimarySize(RectF rect) { return rect.width(); @@ -132,17 +126,6 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { return view.getHeight(); } - @Override - public ScaleAndTranslation getScaleAndTranslation(DeviceProfile dp, View view) { - float offscreenTranslationX = dp.widthPx - view.getPaddingStart(); - return new ScaleAndTranslation(1f, offscreenTranslationX, 0f); - } - - @Override - public float getTranslationValue(ScaleAndTranslation scaleAndTranslation) { - return scaleAndTranslation.translationX; - } - @Override public FloatProperty getPrimaryViewTranslate() { return VIEW_TRANSLATE_X;