From f2393f1d206a88d092a2637511216edb5dad4da4 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 1 Apr 2020 20:13:12 -0700 Subject: [PATCH] Adding TaskViewSimulator for simulating taskView layout on a remote target 1. Tanslating contents of RecentsView instead of recentsView itself. When translating, we keep the current TaskView from moving. This allows the remoteTarget to follow an individual taskView. 2. Removing translationY in recentsView and setting the pivot instead 3. Using TaskViewSimulator for swipe handler. This allows using similar animation creation as Launcher window animation. Change-Id: I0b7b16c367d9d8cd8dd0ed59061e46853e2f8c83 --- .../LauncherAppTransitionManagerImpl.java | 12 +- .../states/BackgroundAppState.java | 15 +- .../uioverrides/states/OverviewPeekState.java | 14 +- .../uioverrides/states/OverviewState.java | 5 +- .../NoButtonQuickSwitchTouchController.java | 57 +--- .../android/quickstep/BaseSwipeUpHandler.java | 21 +- .../quickstep/FallbackSwipeHandler.java | 1 + .../quickstep/LauncherActivityInterface.java | 110 ++----- .../quickstep/LauncherSwipeHandler.java | 71 +++- .../fallback/FallbackRecentsView.java | 10 +- .../util/AppWindowAnimationHelper.java | 25 +- .../quickstep/util/TaskViewSimulator.java | 284 ++++++++++++++++ .../quickstep/views/LauncherRecentsView.java | 21 -- .../android/quickstep/views/RecentsView.java | 83 +++-- .../quickstep/views/TaskThumbnailView.java | 310 ++++++++++-------- .../com/android/quickstep/views/TaskView.java | 106 +++--- .../launcher3/BaseQuickstepLauncher.java | 19 +- .../BaseRecentsViewStateController.java | 32 +- .../uioverrides/states/AllAppsState.java | 5 +- .../quickstep/BaseActivityInterface.java | 2 - .../android/quickstep/util/LayoutUtils.java | 31 +- .../quickstep/util/RecentsOrientedState.java | 27 +- src/com/android/launcher3/Launcher.java | 16 +- src/com/android/launcher3/LauncherState.java | 17 +- .../touch/LandscapePagedViewHandler.java | 17 - .../touch/PagedOrientationHandler.java | 8 +- .../touch/PortraitPagedViewHandler.java | 17 - 27 files changed, 796 insertions(+), 540 deletions(-) create mode 100644 quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java 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;