From 2dbdddb4bad483d2eb98b5582861c6b8a7817800 Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Thu, 29 Apr 2021 18:37:48 -0700 Subject: [PATCH] Add funtional animation for SplitSelect from Grid. Long ways to go to final UI - TODO(b/186800707) Add comments to grid layout code, no functional changes at all. Bug: 181705607 Test: Enter split screen from overview task menu in grid and carousel. Able to select all items and enter split. Change-Id: Ib62f1b286acf0781ec47862fa31b670e6ff1892a --- quickstep/res/layout/overview_panel.xml | 13 +- .../BaseRecentsViewStateController.java | 10 +- .../util/SplitSelectStateController.java | 11 +- .../quickstep/views/LauncherRecentsView.java | 4 +- .../android/quickstep/views/RecentsView.java | 191 ++++++++++++------ .../com/android/quickstep/views/TaskView.java | 58 +++++- .../touch/LandscapePagedViewHandler.java | 13 ++ .../touch/PagedOrientationHandler.java | 11 + .../touch/PortraitPagedViewHandler.java | 19 ++ 9 files changed, 255 insertions(+), 75 deletions(-) diff --git a/quickstep/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml index d7bcd9e932..f303f31199 100644 --- a/quickstep/res/layout/overview_panel.xml +++ b/quickstep/res/layout/overview_panel.xml @@ -15,12 +15,6 @@ --> - + + diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java index 01616d45ec..b3374f33b9 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java @@ -22,12 +22,12 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FA import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MODAL; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X; -import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y; import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW; import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET; import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS; import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY; -import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_TRANSLATION; +import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_SPLIT_TRANSLATION; +import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_SPLIT_TRANSLATION; import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION; import android.util.FloatProperty; @@ -97,10 +97,10 @@ public abstract class BaseRecentsViewStateController PagedOrientationHandler orientationHandler = ((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler(); FloatProperty taskViewsFloat = orientationHandler.getSplitSelectTaskOffset( - TASK_PRIMARY_TRANSLATION, TASK_SECONDARY_TRANSLATION, mLauncher.getDeviceProfile()); + TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION, + mLauncher.getDeviceProfile()); setter.setFloat(mRecentsView, taskViewsFloat, - toState.getOverviewSecondaryTranslation(mLauncher), - config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR)); + toState.getOverviewSecondaryTranslation(mLauncher), 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/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java index 01d51f82cb..3d33e57a36 100644 --- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java +++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java @@ -25,6 +25,7 @@ import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITIO import android.animation.AnimatorSet; import android.app.ActivityOptions; import android.content.res.Resources; +import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -64,6 +65,7 @@ public class SplitSelectStateController { private final SystemUiProxy mSystemUiProxy; private TaskView mInitialTaskView; private SplitPositionOption mInitialPosition; + private Rect mInitialBounds; private final Handler mHandler; public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy) { @@ -74,9 +76,11 @@ public class SplitSelectStateController { /** * To be called after first task selected */ - public void setInitialTaskSelect(TaskView taskView, SplitPositionOption positionOption) { + public void setInitialTaskSelect(TaskView taskView, SplitPositionOption positionOption, + Rect initialBounds) { mInitialTaskView = taskView; mInitialPosition = positionOption; + mInitialBounds = initialBounds; } /** @@ -220,9 +224,14 @@ public class SplitSelectStateController { public void resetState() { mInitialTaskView = null; mInitialPosition = null; + mInitialBounds = null; } public boolean isSplitSelectActive() { return mInitialTaskView != null; } + + public Rect getInitialBounds() { + return mInitialBounds; + } } diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java index f5a8ff8170..2c5f66170b 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -245,8 +245,8 @@ public class LauncherRecentsView extends RecentsView TASK_PRIMARY_TRANSLATION = - new FloatProperty("taskPrimaryTranslation") { + public static final FloatProperty TASK_PRIMARY_SPLIT_TRANSLATION = + new FloatProperty("taskPrimarySplitTranslation") { @Override public void setValue(RecentsView recentsView, float v) { - recentsView.setTaskViewsPrimaryTranslation(v); + recentsView.setTaskViewsPrimarySplitTranslation(v); } @Override public Float get(RecentsView recentsView) { - return recentsView.mTaskViewsPrimaryTranslation; + return recentsView.mTaskViewsPrimarySplitTranslation; + } + }; + + public static final FloatProperty TASK_SECONDARY_SPLIT_TRANSLATION = + new FloatProperty("taskSecondarySplitTranslation") { + @Override + public void setValue(RecentsView recentsView, float v) { + recentsView.setTaskViewsSecondarySplitTranslation(v); + } + + @Override + public Float get(RecentsView recentsView) { + return recentsView.mTaskViewsSecondarySplitTranslation; } }; @@ -279,7 +292,6 @@ public abstract class RecentsView secondaryViewTranslate = - taskView.getSecondaryDissmissTranslationProperty(); - int secondaryTaskDimension = mOrientationHandler.getSecondaryDimension(taskView); - int verticalFactor = mOrientationHandler.getSecondaryTranslationDirectionFactor(); + SplitSelectStateController splitController = mSplitPlaceholderView.getSplitController(); ResourceProvider rp = DynamicResource.provider(mActivity); SpringProperty sp = new SpringProperty(SpringProperty.FLAG_CAN_SPRING_ON_START) .setDampingRatio(rp.getFloat(R.dimen.dismiss_task_trans_y_damping_ratio)) .setStiffness(rp.getFloat(R.dimen.dismiss_task_trans_y_stiffness)); + FloatProperty dismissingTaskViewTranslate = + taskView.getSecondaryDissmissTranslationProperty();; + // TODO(b/186800707) translate entire grid size distance + int translateDistance = mOrientationHandler.getSecondaryDimension(taskView); + int positiveNegativeFactor = mOrientationHandler.getSecondaryTranslationDirectionFactor(); + if (splitController.isSplitSelectActive()) { + // Have the task translate towards whatever side was just pinned + int dir = mOrientationHandler.getSplitTaskViewDismissDirection(splitController + .getActiveSplitPositionOption(), mActivity.getDeviceProfile()); + switch (dir) { + case PagedOrientationHandler.SPLIT_TRANSLATE_SECONDARY_NEGATIVE: + dismissingTaskViewTranslate = taskView + .getSecondaryDissmissTranslationProperty(); + positiveNegativeFactor = -1; + break; - anim.add(ObjectAnimator.ofFloat(taskView, secondaryViewTranslate, - verticalFactor * secondaryTaskDimension).setDuration(duration), LINEAR, sp); + case PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_POSITIVE: + dismissingTaskViewTranslate = taskView.getPrimaryDismissTranslationProperty(); + positiveNegativeFactor = 1; + break; + + case PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_NEGATIVE: + dismissingTaskViewTranslate = taskView.getPrimaryDismissTranslationProperty(); + positiveNegativeFactor = -1; + break; + default: + throw new IllegalStateException("Invalid split task translation: " + dir); + } + } + anim.add(ObjectAnimator.ofFloat(taskView, dismissingTaskViewTranslate, + positiveNegativeFactor * translateDistance).setDuration(duration), LINEAR, sp); if (LIVE_TILE.get() && taskView.isRunningTask()) { anim.addOnFrameCallback(() -> { @@ -2206,18 +2255,6 @@ public abstract class RecentsView view.getVisibility() != GONE && view != mSplitHiddenTaskView); - // x is correct, y is before tasks move up - int[] locationOnScreen = mSplitHiddenTaskView.getLocationOnScreen(); int[] newScroll = new int[getChildCount()]; getPageScrolls(newScroll, false, SIMPLE_SCROLL_LOGIC); @@ -2842,20 +2888,42 @@ public abstract class RecentsView= 0; i--) { View child = getChildAt(i); if (child == mSplitHiddenTaskView) { + TaskView taskView = (TaskView) child; - int left = newScroll[i] + getPaddingStart(); - int topMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx; - int top = -mSplitHiddenTaskView.getHeight() - locationOnScreen[1]; - mSplitHiddenTaskView.layout(left, top, - left + mSplitHiddenTaskView.getWidth(), - top + mSplitHiddenTaskView.getHeight()); - pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView, TRANSLATION_Y, - -top + mSplitPlaceholderView.getHeight() - topMargin)); + int dir = mOrientationHandler.getSplitTaskViewDismissDirection(splitOption, + mActivity.getDeviceProfile()); + FloatProperty dismissingTaskViewTranslate; + Rect hiddenBounds = new Rect(taskView.getLeft(), taskView.getTop(), + taskView.getRight(), taskView.getBottom()); + int distanceDelta = 0; + if (dir == PagedOrientationHandler.SPLIT_TRANSLATE_SECONDARY_NEGATIVE) { + dismissingTaskViewTranslate = taskView + .getSecondaryDissmissTranslationProperty(); + distanceDelta = initialBounds.top - hiddenBounds.top; + taskView.layout(initialBounds.left, hiddenBounds.top, initialBounds.right, + hiddenBounds.bottom); + } else { + dismissingTaskViewTranslate = taskView + .getPrimaryDismissTranslationProperty(); + distanceDelta = initialBounds.left - hiddenBounds.left; + taskView.layout(hiddenBounds.left, initialBounds.top, hiddenBounds.right, + initialBounds.bottom); + if (dir == PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_POSITIVE) { + distanceDelta *= -1; + } + } + pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView, + dismissingTaskViewTranslate, + distanceDelta)); pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView, ALPHA, 1)); } else { // If insertion is on last index (furthest from clear all), we directly add the view // else we translate all views to the right of insertion index further right, // ignore views to left + if (showAsGrid()) { + // TODO(b/186800707) handle more elegantly for grid + continue; + } int scrollDiff = newScroll[i] - oldScroll[i]; if (scrollDiff != 0) { FloatProperty translationProperty = child instanceof TaskView @@ -2881,6 +2949,12 @@ public abstract class RecentsView SPLIT_SELECT_TRANSLATION_X = + new FloatProperty("splitSelectTranslationX") { + @Override + public void setValue(TaskView taskView, float v) { + taskView.setSplitSelectTranslationX(v); + } + + @Override + public Float get(TaskView taskView) { + return taskView.mSplitSelectTranslationX; + } + }; + + private static final FloatProperty SPLIT_SELECT_TRANSLATION_Y = + new FloatProperty("splitSelectTranslationY") { + @Override + public void setValue(TaskView taskView, float v) { + taskView.setSplitSelectTranslationY(v); + } + + @Override + public Float get(TaskView taskView) { + return taskView.mSplitSelectTranslationY; + } + }; + private static final FloatProperty DISMISS_TRANSLATION_X = new FloatProperty("dismissTranslationX") { @Override @@ -345,6 +371,9 @@ public class TaskView extends FrameLayout implements Reusable { // The following grid translations scales with mGridProgress. private float mGridTranslationX; private float mGridTranslationY; + // Used when in SplitScreenSelectState + private float mSplitSelectTranslationY; + private float mSplitSelectTranslationX; private ObjectAnimator mIconAndDimAnimator; private float mIconScaleAnimStartProgress = 0; @@ -825,8 +854,10 @@ public class TaskView extends FrameLayout implements Reusable { protected void resetViewTransforms() { // fullscreenTranslation and accumulatedTranslation should not be reset, as // resetViewTransforms is called during Quickswitch scrolling. - mDismissTranslationX = mTaskOffsetTranslationX = mTaskResistanceTranslationX = 0f; - mDismissTranslationY = mTaskOffsetTranslationY = mTaskResistanceTranslationY = 0f; + mDismissTranslationX = mTaskOffsetTranslationX = mTaskResistanceTranslationX = + mSplitSelectTranslationX = 0f; + mDismissTranslationY = mTaskOffsetTranslationY = mTaskResistanceTranslationY = + mSplitSelectTranslationY = 0f; applyTranslationX(); applyTranslationY(); setTranslationZ(0); @@ -956,6 +987,15 @@ public class TaskView extends FrameLayout implements Reusable { setScaleY(scale); } + private void setSplitSelectTranslationX(float x) { + mSplitSelectTranslationX = x; + applyTranslationX(); + } + + private void setSplitSelectTranslationY(float y) { + mSplitSelectTranslationY = y; + applyTranslationY(); + } private void setDismissTranslationX(float x) { mDismissTranslationX = x; applyTranslationX(); @@ -1056,12 +1096,12 @@ public class TaskView extends FrameLayout implements Reusable { private void applyTranslationX() { setTranslationX(mDismissTranslationX + mTaskOffsetTranslationX + mTaskResistanceTranslationX - + getPersistentTranslationX()); + + mSplitSelectTranslationX + getPersistentTranslationX()); } private void applyTranslationY() { setTranslationY(mDismissTranslationY + mTaskOffsetTranslationY + mTaskResistanceTranslationY - + getPersistentTranslationY()); + + mSplitSelectTranslationY + getPersistentTranslationY()); } /** @@ -1085,6 +1125,16 @@ public class TaskView extends FrameLayout implements Reusable { + getGridTrans(mGridTranslationY); } + public FloatProperty getPrimarySplitTranslationProperty() { + return getPagedOrientationHandler().getPrimaryValue( + SPLIT_SELECT_TRANSLATION_X, SPLIT_SELECT_TRANSLATION_Y); + } + + public FloatProperty getSecondarySplitTranslationProperty() { + return getPagedOrientationHandler().getSecondaryValue( + SPLIT_SELECT_TRANSLATION_X, SPLIT_SELECT_TRANSLATION_Y); + } + public FloatProperty getPrimaryDismissTranslationProperty() { return getPagedOrientationHandler().getPrimaryValue( DISMISS_TRANSLATION_X, DISMISS_TRANSLATION_Y); diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java index 2fd5efc3f6..44e55e102c 100644 --- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java @@ -159,6 +159,19 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { return VIEW_TRANSLATE_X; } + @Override + public int getSplitTaskViewDismissDirection(SplitPositionOption splitPosition, + DeviceProfile dp) { + // Don't use device profile here because we know we're in fake landscape, only split option + // available is top/left + if (splitPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT) { + // Top (visually left) side + return SPLIT_TRANSLATE_PRIMARY_NEGATIVE; + } + throw new IllegalStateException("Invalid split stage position: " + + splitPosition.mStagePosition); + } + @Override public int getPrimaryScroll(View view) { return view.getScrollY(); diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java index 6c2f17ee34..d8e5a485fd 100644 --- a/src/com/android/launcher3/touch/PagedOrientationHandler.java +++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java @@ -42,6 +42,10 @@ import java.util.List; */ public interface PagedOrientationHandler { + int SPLIT_TRANSLATE_PRIMARY_POSITIVE = 0; + int SPLIT_TRANSLATE_PRIMARY_NEGATIVE = 1; + int SPLIT_TRANSLATE_SECONDARY_NEGATIVE = 2; + PagedOrientationHandler PORTRAIT = new PortraitPagedViewHandler(); PagedOrientationHandler LANDSCAPE = new LandscapePagedViewHandler(); PagedOrientationHandler SEASCAPE = new SeascapePagedViewHandler(); @@ -71,6 +75,13 @@ public interface PagedOrientationHandler { int getSecondaryDimension(View view); FloatProperty getPrimaryViewTranslate(); FloatProperty getSecondaryViewTranslate(); + + /** + * @param splitPosition The position where the view to be split will go + * @return {@link #SPLIT_TRANSLATE_*} constants to indicate which direction the + * dismissal should happen + */ + int getSplitTaskViewDismissDirection(SplitPositionOption splitPosition, DeviceProfile dp); int getPrimaryScroll(View view); float getPrimaryScale(View view); int getChildStart(View view); diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java index f6a6448602..01897d727d 100644 --- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java +++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java @@ -155,6 +155,25 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { return VIEW_TRANSLATE_Y; } + @Override + public int getSplitTaskViewDismissDirection(SplitPositionOption splitPosition, + DeviceProfile dp) { + if (splitPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT) { + if (dp.isLandscape) { + // Left side + return SPLIT_TRANSLATE_PRIMARY_NEGATIVE; + } else { + // Top side + return SPLIT_TRANSLATE_SECONDARY_NEGATIVE; + } + } else if (splitPosition.mStagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) { + // We don't have a bottom option, so should be right + return SPLIT_TRANSLATE_PRIMARY_POSITIVE; + } + throw new IllegalStateException("Invalid split stage position: " + + splitPosition.mStagePosition); + } + @Override public int getPrimaryScroll(View view) { return view.getScrollX();