diff --git a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt index 658975c4a9..88ef0a8bcb 100644 --- a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt +++ b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt @@ -453,6 +453,10 @@ open class LandscapePagedViewHandler : RecentsPagedOrientationHandler { } } + /** + * @param inSplitSelection Whether user currently has a task from this task group staged for + * split screen. Currently this state is not reachable in fake landscape. + */ override fun measureGroupedTaskViewThumbnailBounds( primarySnapshot: View, secondarySnapshot: View, @@ -460,7 +464,8 @@ open class LandscapePagedViewHandler : RecentsPagedOrientationHandler { parentHeight: Int, splitBoundsConfig: SplitBounds, dp: DeviceProfile, - isRtl: Boolean + isRtl: Boolean, + inSplitSelection: Boolean ) { val primaryParams = primarySnapshot.layoutParams as FrameLayout.LayoutParams val secondaryParams = secondarySnapshot.layoutParams as FrameLayout.LayoutParams @@ -569,6 +574,10 @@ open class LandscapePagedViewHandler : RecentsPagedOrientationHandler { iconAppChipView.setRotation(degreesRotated) } + /** + * @param inSplitSelection Whether user currently has a task from this task group staged for + * split screen. Currently this state is not reachable in fake landscape. + */ override fun setSplitIconParams( primaryIconView: View, secondaryIconView: View, @@ -579,7 +588,8 @@ open class LandscapePagedViewHandler : RecentsPagedOrientationHandler { groupedTaskViewWidth: Int, isRtl: Boolean, deviceProfile: DeviceProfile, - splitConfig: SplitBounds + splitConfig: SplitBounds, + inSplitSelection: Boolean ) { val spaceAboveSnapshot = deviceProfile.overviewTaskThumbnailTopMarginPx val totalThumbnailHeight = groupedTaskViewHeight - spaceAboveSnapshot diff --git a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java index cc022b202e..c0b697daf8 100644 --- a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java +++ b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java @@ -530,10 +530,16 @@ public class PortraitPagedViewHandler extends DefaultPagedViewHandler implements } } + /** + * @param inSplitSelection Whether user currently has a task from this task group staged for + * split screen. If true, we have custom translations/scaling in place + * for the remaining snapshot, so we'll skip setting translation/scale + * here. + */ @Override public void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot, int parentWidth, int parentHeight, SplitBounds splitBoundsConfig, - DeviceProfile dp, boolean isRtl) { + DeviceProfile dp, boolean isRtl, boolean inSplitSelection) { int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx; FrameLayout.LayoutParams primaryParams = @@ -541,11 +547,10 @@ public class PortraitPagedViewHandler extends DefaultPagedViewHandler implements FrameLayout.LayoutParams secondaryParams = (FrameLayout.LayoutParams) secondarySnapshot.getLayoutParams(); - // Reset margin and translations that aren't used in this method, but are used in other + // Reset margins that aren't used in this method, but are used in other // `RecentsPagedOrientationHandler` variants. secondaryParams.topMargin = 0; primaryParams.topMargin = spaceAboveSnapshot; - primarySnapshot.setTranslationY(0); int totalThumbnailHeight = parentHeight - spaceAboveSnapshot; float dividerScale = splitBoundsConfig.appsStackedVertically @@ -553,28 +558,35 @@ public class PortraitPagedViewHandler extends DefaultPagedViewHandler implements : splitBoundsConfig.dividerWidthPercent; Pair taskViewSizes = getGroupedTaskViewSizes(dp, splitBoundsConfig, parentWidth, parentHeight); - if (dp.isLeftRightSplit) { - int scaledDividerBar = Math.round(parentWidth * dividerScale); - if (isRtl) { - int translationX = taskViewSizes.second.x + scaledDividerBar; - primarySnapshot.setTranslationX(-translationX); - secondarySnapshot.setTranslationX(0); + if (!inSplitSelection) { + // Reset translations that aren't used in this method, but are used in other + // `RecentsPagedOrientationHandler` variants. + primarySnapshot.setTranslationY(0); + + if (dp.isLeftRightSplit) { + int scaledDividerBar = Math.round(parentWidth * dividerScale); + if (isRtl) { + int translationX = taskViewSizes.second.x + scaledDividerBar; + primarySnapshot.setTranslationX(-translationX); + secondarySnapshot.setTranslationX(0); + } else { + int translationX = taskViewSizes.first.x + scaledDividerBar; + secondarySnapshot.setTranslationX(translationX); + primarySnapshot.setTranslationX(0); + } + secondarySnapshot.setTranslationY(spaceAboveSnapshot); } else { - int translationX = taskViewSizes.first.x + scaledDividerBar; - secondarySnapshot.setTranslationX(translationX); + float finalDividerHeight = Math.round(totalThumbnailHeight * dividerScale); + float translationY = + taskViewSizes.first.y + spaceAboveSnapshot + finalDividerHeight; + secondarySnapshot.setTranslationY(translationY); + + // Reset unused translations. + secondarySnapshot.setTranslationX(0); primarySnapshot.setTranslationX(0); } - - secondarySnapshot.setTranslationY(spaceAboveSnapshot); - } else { - float finalDividerHeight = Math.round(totalThumbnailHeight * dividerScale); - float translationY = taskViewSizes.first.y + spaceAboveSnapshot + finalDividerHeight; - secondarySnapshot.setTranslationY(translationY); - - // Reset unused translations. - secondarySnapshot.setTranslationX(0); - primarySnapshot.setTranslationX(0); } + primarySnapshot.measure( View.MeasureSpec.makeMeasureSpec(taskViewSizes.first.x, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(taskViewSizes.first.y, View.MeasureSpec.EXACTLY)); @@ -582,10 +594,6 @@ public class PortraitPagedViewHandler extends DefaultPagedViewHandler implements View.MeasureSpec.makeMeasureSpec(taskViewSizes.second.x, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(taskViewSizes.second.y, View.MeasureSpec.EXACTLY)); - primarySnapshot.setScaleX(1); - secondarySnapshot.setScaleX(1); - primarySnapshot.setScaleY(1); - secondarySnapshot.setScaleY(1); } @Override @@ -662,11 +670,16 @@ public class PortraitPagedViewHandler extends DefaultPagedViewHandler implements iconAppChipView.setRotation(getDegreesRotated()); } + /** + * @param inSplitSelection Whether user currently has a task from this task group staged for + * split screen. If true, we have custom translations in place for the + * remaining icon, so we'll skip setting translations here. + */ @Override public void setSplitIconParams(View primaryIconView, View secondaryIconView, int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight, int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl, - DeviceProfile deviceProfile, SplitBounds splitConfig) { + DeviceProfile deviceProfile, SplitBounds splitConfig, boolean inSplitSelection) { FrameLayout.LayoutParams primaryIconParams = (FrameLayout.LayoutParams) primaryIconView.getLayoutParams(); FrameLayout.LayoutParams secondaryIconParams = enableOverviewIconMenu() @@ -680,20 +693,23 @@ public class PortraitPagedViewHandler extends DefaultPagedViewHandler implements secondaryIconParams.gravity = TOP | START; secondaryIconParams.topMargin = primaryIconParams.topMargin; secondaryIconParams.setMarginStart(primaryIconParams.getMarginStart()); - if (deviceProfile.isLeftRightSplit) { - if (isRtl) { - int secondarySnapshotWidth = groupedTaskViewWidth - primarySnapshotWidth; - primaryAppChipView.setSplitTranslationX(-secondarySnapshotWidth); + if (!inSplitSelection) { + if (deviceProfile.isLeftRightSplit) { + if (isRtl) { + int secondarySnapshotWidth = groupedTaskViewWidth - primarySnapshotWidth; + primaryAppChipView.setSplitTranslationX(-secondarySnapshotWidth); + } else { + secondaryAppChipView.setSplitTranslationX(primarySnapshotWidth); + } } else { - secondaryAppChipView.setSplitTranslationX(primarySnapshotWidth); + primaryAppChipView.setSplitTranslationX(0); + secondaryAppChipView.setSplitTranslationX(0); + int dividerThickness = Math.min(splitConfig.visualDividerBounds.width(), + splitConfig.visualDividerBounds.height()); + secondaryAppChipView.setSplitTranslationY( + primarySnapshotHeight + (deviceProfile.isTablet ? 0 + : dividerThickness)); } - } else { - primaryAppChipView.setSplitTranslationX(0); - secondaryAppChipView.setSplitTranslationX(0); - int dividerThickness = Math.min(splitConfig.visualDividerBounds.width(), - splitConfig.visualDividerBounds.height()); - secondaryAppChipView.setSplitTranslationY( - primarySnapshotHeight + (deviceProfile.isTablet ? 0 : dividerThickness)); } } else if (deviceProfile.isLeftRightSplit) { // We calculate the "midpoint" of the thumbnail area, and place the icons there. @@ -716,46 +732,53 @@ public class PortraitPagedViewHandler extends DefaultPagedViewHandler implements if (deviceProfile.isSeascape()) { primaryIconParams.gravity = TOP | (isRtl ? END : START); secondaryIconParams.gravity = TOP | (isRtl ? END : START); - if (splitConfig.initiatedFromSeascape) { - // if the split was initiated from seascape, - // the task on the right (secondary) is slightly larger - primaryIconView.setTranslationX(bottomToMidpointOffset - taskIconHeight); - secondaryIconView.setTranslationX(bottomToMidpointOffset); - } else { - // if not, - // the task on the left (primary) is slightly larger - primaryIconView.setTranslationX(bottomToMidpointOffset + insetOffset - - taskIconHeight); - secondaryIconView.setTranslationX(bottomToMidpointOffset + insetOffset); + if (!inSplitSelection) { + if (splitConfig.initiatedFromSeascape) { + // if the split was initiated from seascape, + // the task on the right (secondary) is slightly larger + primaryIconView.setTranslationX(bottomToMidpointOffset - taskIconHeight); + secondaryIconView.setTranslationX(bottomToMidpointOffset); + } else { + // if not, + // the task on the left (primary) is slightly larger + primaryIconView.setTranslationX(bottomToMidpointOffset + insetOffset + - taskIconHeight); + secondaryIconView.setTranslationX(bottomToMidpointOffset + insetOffset); + } } } else { primaryIconParams.gravity = TOP | (isRtl ? START : END); secondaryIconParams.gravity = TOP | (isRtl ? START : END); - if (!splitConfig.initiatedFromSeascape) { - // if the split was initiated from landscape, - // the task on the left (primary) is slightly larger - primaryIconView.setTranslationX(-bottomToMidpointOffset); - secondaryIconView.setTranslationX(-bottomToMidpointOffset + taskIconHeight); - } else { - // if not, - // the task on the right (secondary) is slightly larger - primaryIconView.setTranslationX(-bottomToMidpointOffset - insetOffset); - secondaryIconView.setTranslationX(-bottomToMidpointOffset - insetOffset - + taskIconHeight); + if (!inSplitSelection) { + if (!splitConfig.initiatedFromSeascape) { + // if the split was initiated from landscape, + // the task on the left (primary) is slightly larger + primaryIconView.setTranslationX(-bottomToMidpointOffset); + secondaryIconView.setTranslationX(-bottomToMidpointOffset + taskIconHeight); + } else { + // if not, + // the task on the right (secondary) is slightly larger + primaryIconView.setTranslationX(-bottomToMidpointOffset - insetOffset); + secondaryIconView.setTranslationX(-bottomToMidpointOffset - insetOffset + + taskIconHeight); + } } } } else { primaryIconParams.gravity = TOP | CENTER_HORIZONTAL; - // shifts icon half a width left (height is used here since icons are square) - primaryIconView.setTranslationX(-(taskIconHeight / 2f)); secondaryIconParams.gravity = TOP | CENTER_HORIZONTAL; - secondaryIconView.setTranslationX(taskIconHeight / 2f); + if (!inSplitSelection) { + // shifts icon half a width left (height is used here since icons are square) + primaryIconView.setTranslationX(-(taskIconHeight / 2f)); + secondaryIconView.setTranslationX(taskIconHeight / 2f); + } } - if (!enableOverviewIconMenu()) { + if (!enableOverviewIconMenu() && !inSplitSelection) { primaryIconView.setTranslationY(0); secondaryIconView.setTranslationY(0); } + primaryIconView.setLayoutParams(primaryIconParams); secondaryIconView.setLayoutParams(secondaryIconParams); } diff --git a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt index 06a0685d6c..b8d0412eff 100644 --- a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt +++ b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt @@ -184,7 +184,8 @@ interface RecentsPagedOrientationHandler : PagedOrientationHandler { parentHeight: Int, splitBoundsConfig: SplitConfigurationOptions.SplitBounds, dp: DeviceProfile, - isRtl: Boolean + isRtl: Boolean, + inSplitSelection: Boolean ) /** @@ -235,7 +236,8 @@ interface RecentsPagedOrientationHandler : PagedOrientationHandler { groupedTaskViewWidth: Int, isRtl: Boolean, deviceProfile: DeviceProfile, - splitConfig: SplitConfigurationOptions.SplitBounds + splitConfig: SplitConfigurationOptions.SplitBounds, + inSplitSelection: Boolean ) /* diff --git a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt index a972e8c1ef..bc91911749 100644 --- a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt +++ b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt @@ -277,6 +277,10 @@ class SeascapePagedViewHandler : LandscapePagedViewHandler() { iconAppChipView.setRotation(degreesRotated) } + /** + * @param inSplitSelection Whether user currently has a task from this task group staged for + * split screen. Currently this state is not reachable in fake seascape. + */ override fun measureGroupedTaskViewThumbnailBounds( primarySnapshot: View, secondarySnapshot: View, @@ -284,7 +288,8 @@ class SeascapePagedViewHandler : LandscapePagedViewHandler() { parentHeight: Int, splitBoundsConfig: SplitBounds, dp: DeviceProfile, - isRtl: Boolean + isRtl: Boolean, + inSplitSelection: Boolean ) { val primaryParams = primarySnapshot.layoutParams as FrameLayout.LayoutParams val secondaryParams = secondarySnapshot.layoutParams as FrameLayout.LayoutParams diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt index 256e29e79a..3449cf2034 100644 --- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt +++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt @@ -42,6 +42,8 @@ import android.window.TransitionInfo import android.window.TransitionInfo.Change import android.window.WindowContainerToken import androidx.annotation.VisibleForTesting +import androidx.core.util.component1 +import androidx.core.util.component2 import com.android.app.animation.Interpolators import com.android.launcher3.DeviceProfile import com.android.launcher3.Flags.enableOverviewIconMenu @@ -225,10 +227,22 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC ObjectAnimator.ofFloat(iconView.splitTranslationY, MULTI_PROPERTY_VALUE, 0f) ) } + + val splitBoundsConfig = + (taskContainer.taskView as? GroupedTaskView)?.splitBoundsConfig ?: return + val (primarySnapshotViewSize, secondarySnapshotViewSize) = + taskContainer.taskView.pagedOrientationHandler.getGroupedTaskViewSizes( + deviceProfile, + splitBoundsConfig, + taskViewWidth, + taskViewHeight, + ) + val snapshotViewSize = + if (isPrimaryTaskSplitting) primarySnapshotViewSize else secondarySnapshotViewSize if (deviceProfile.isLeftRightSplit) { // Center view first so scaling happens uniformly, alternatively we can move pivotX to 0 - val centerThumbnailTranslationX: Float = (taskViewWidth - snapshot.width) / 2f - val finalScaleX: Float = taskViewWidth.toFloat() / snapshot.width + val centerThumbnailTranslationX: Float = (taskViewWidth - snapshotViewSize.x) / 2f + val finalScaleX: Float = taskViewWidth.toFloat() / snapshotViewSize.x builder.add( ObjectAnimator.ofFloat(snapshot, View.TRANSLATION_X, centerThumbnailTranslationX) ) @@ -262,13 +276,13 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC // thumbnail needs to take that into account. We should migrate to only using // translations otherwise this asymmetry causes problems.. if (isPrimaryTaskSplitting) { - centerThumbnailTranslationY = (thumbnailSize - snapshot.height) / 2f + centerThumbnailTranslationY = (thumbnailSize - snapshotViewSize.y) / 2f centerThumbnailTranslationY += deviceProfile.overviewTaskThumbnailTopMarginPx.toFloat() } else { - centerThumbnailTranslationY = (thumbnailSize - snapshot.height) / 2f + centerThumbnailTranslationY = (thumbnailSize - snapshotViewSize.y) / 2f } - val finalScaleY: Float = thumbnailSize.toFloat() / snapshot.height + val finalScaleY: Float = thumbnailSize.toFloat() / snapshotViewSize.y builder.add( ObjectAnimator.ofFloat(snapshot, View.TRANSLATION_Y, centerThumbnailTranslationY) ) diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt index 3fd1a6bb60..92c1e9396f 100644 --- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt +++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt @@ -65,31 +65,18 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu val heightSize = MeasureSpec.getSize(heightMeasureSpec) setMeasuredDimension(widthSize, heightSize) val splitBoundsConfig = splitBoundsConfig ?: return - val initSplitTaskId = getThisTaskCurrentlyInSplitSelection() - if (initSplitTaskId == INVALID_TASK_ID) { - pagedOrientationHandler.measureGroupedTaskViewThumbnailBounds( - taskContainers[0].snapshotView, - taskContainers[1].snapshotView, - widthSize, - heightSize, - splitBoundsConfig, - container.deviceProfile, - layoutDirection == LAYOUT_DIRECTION_RTL - ) - } else { - // Currently being split with this taskView, let the non-split selected thumbnail - // take up full thumbnail area - taskContainers - .firstOrNull { it.task.key.id != initSplitTaskId } - ?.snapshotView - ?.measure( - widthMeasureSpec, - MeasureSpec.makeMeasureSpec( - heightSize - container.deviceProfile.overviewTaskThumbnailTopMarginPx, - MeasureSpec.EXACTLY - ) - ) - } + val inSplitSelection = getThisTaskCurrentlyInSplitSelection() != INVALID_TASK_ID + pagedOrientationHandler.measureGroupedTaskViewThumbnailBounds( + taskContainers[0].snapshotView, + taskContainers[1].snapshotView, + widthSize, + heightSize, + splitBoundsConfig, + container.deviceProfile, + layoutDirection == LAYOUT_DIRECTION_RTL, + inSplitSelection, + ) + if (!enableOverviewIconMenu()) { updateIconPlacement() } @@ -173,6 +160,8 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu val splitBoundsConfig = splitBoundsConfig ?: return val taskIconHeight = container.deviceProfile.overviewTaskIconSizePx val isRtl = layoutDirection == LAYOUT_DIRECTION_RTL + val inSplitSelection = getThisTaskCurrentlyInSplitSelection() != INVALID_TASK_ID + if (enableOverviewIconMenu()) { val groupedTaskViewSizes = pagedOrientationHandler.getGroupedTaskViewSizes( @@ -191,7 +180,8 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu layoutParams.width, isRtl, container.deviceProfile, - splitBoundsConfig + splitBoundsConfig, + inSplitSelection ) } else { pagedOrientationHandler.setSplitIconParams( @@ -204,7 +194,8 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu measuredWidth, isRtl, container.deviceProfile, - splitBoundsConfig + splitBoundsConfig, + inSplitSelection ) } } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index e37e036857..e07333a461 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -4985,7 +4985,8 @@ public abstract class RecentsView< mSplitSelectStateController.getSplitAnimationController() .addInitialSplitFromPair(taskContainer, builder, mContainer.getDeviceProfile(), - mSplitHiddenTaskView.getWidth(), mSplitHiddenTaskView.getHeight(), + mSplitHiddenTaskView.getLayoutParams().width, + mSplitHiddenTaskView.getLayoutParams().height, primaryTaskSelected); builder.addOnFrameCallback(() -> { if (!enableRefactorTaskThumbnail()) { diff --git a/quickstep/src/com/android/quickstep/views/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt index 13c4f78487..57d68a092e 100644 --- a/quickstep/src/com/android/quickstep/views/TaskContainer.kt +++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt @@ -160,6 +160,8 @@ class TaskContainer( if (enableRefactorTaskThumbnail()) { taskView.removeView(thumbnailView) } + snapshotView.scaleX = 1f + snapshotView.scaleY = 1f overlay.destroy() }