Fix icon positioning for flexible split in Overview

In flexible split ratios like 90:10 and 10:90, we hide the Overview icon of the smaller app completely. This resulted in a bug where the single remaining visible icon was positioned badly.

Fixed this by adding a check in updateIconPlacement() so that we can skip the two-icon positioning and center the visible icon alone. Also fixed the cases where split select is initiated on a split tile (from Taskbar). Now the correct icon should be shown and centered.

Fixes: 391865942
Flag: com.android.wm.shell.enable_flexible_two_app_split
Test: Single icon is positioned correctly in the middle. When split select is initiated, the right icon is shown and centered. When app chip menus are enabled, the (existing) correct behavior is not changed.
Change-Id: I79842222fc325a7661cbabbb54d277389a317504
This commit is contained in:
Jeremy Sim
2025-02-20 12:50:02 -08:00
parent b392f61ced
commit 633b94abf1
7 changed files with 121 additions and 42 deletions

View File

@@ -577,7 +577,8 @@ open class LandscapePagedViewHandler : RecentsPagedOrientationHandler {
isRtl: Boolean,
deviceProfile: DeviceProfile,
splitConfig: SplitBounds,
inSplitSelection: Boolean
inSplitSelection: Boolean,
oneIconHiddenDueToSmallWidth: Boolean,
) {
val spaceAboveSnapshot = deviceProfile.overviewTaskThumbnailTopMarginPx
val totalThumbnailHeight = groupedTaskViewHeight - spaceAboveSnapshot
@@ -590,7 +591,8 @@ open class LandscapePagedViewHandler : RecentsPagedOrientationHandler {
totalThumbnailHeight,
isRtl,
deviceProfile.overviewTaskMarginPx,
dividerBar
dividerBar,
oneIconHiddenDueToSmallWidth,
)
updateSplitIconsPosition(primaryIconView, topLeftY, isRtl)
@@ -647,6 +649,7 @@ open class LandscapePagedViewHandler : RecentsPagedOrientationHandler {
isRtl: Boolean,
overviewTaskMarginPx: Int,
dividerSize: Int,
oneIconHiddenDueToSmallWidth: Boolean,
): SplitIconPositions {
return if (Flags.enableOverviewIconMenu()) {
if (isRtl) {
@@ -655,11 +658,21 @@ open class LandscapePagedViewHandler : RecentsPagedOrientationHandler {
SplitIconPositions(0, primarySnapshotHeight + dividerSize)
}
} else {
val topLeftY = primarySnapshotHeight + overviewTaskMarginPx
SplitIconPositions(
topLeftY = topLeftY,
bottomRightY = topLeftY + dividerSize + taskIconHeight
)
if (oneIconHiddenDueToSmallWidth) {
// Center both icons
val centerY = primarySnapshotHeight + overviewTaskMarginPx +
((taskIconHeight + dividerSize) / 2)
SplitIconPositions(
topLeftY = centerY,
bottomRightY = centerY,
)
} else {
val topLeftY = primarySnapshotHeight + overviewTaskMarginPx
SplitIconPositions(
topLeftY = topLeftY,
bottomRightY = topLeftY + dividerSize + taskIconHeight,
)
}
}
}

View File

@@ -671,7 +671,8 @@ public class PortraitPagedViewHandler extends DefaultPagedViewHandler implements
public void setSplitIconParams(View primaryIconView, View secondaryIconView,
int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
DeviceProfile deviceProfile, SplitBounds splitConfig, boolean inSplitSelection) {
DeviceProfile deviceProfile, SplitBounds splitConfig, boolean inSplitSelection,
boolean oneIconHiddenDueToSmallWidth) {
FrameLayout.LayoutParams primaryIconParams =
(FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
FrameLayout.LayoutParams secondaryIconParams = enableOverviewIconMenu()
@@ -726,16 +727,30 @@ public class PortraitPagedViewHandler extends DefaultPagedViewHandler implements
secondaryIconParams.gravity = TOP | (isRtl ? END : START);
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);
if (oneIconHiddenDueToSmallWidth) {
// Center both icons
float centerX = bottomToMidpointOffset - (taskIconHeight / 2f);
primaryIconView.setTranslationX(centerX);
secondaryIconView.setTranslationX(centerX);
} else {
// 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 (oneIconHiddenDueToSmallWidth) {
// Center both icons
float centerX =
bottomToMidpointOffset + insetOffset - (taskIconHeight / 2f);
primaryIconView.setTranslationX(centerX);
secondaryIconView.setTranslationX(centerX);
} else {
// the task on the left (primary) is slightly larger
primaryIconView.setTranslationX(bottomToMidpointOffset + insetOffset
- taskIconHeight);
secondaryIconView.setTranslationX(bottomToMidpointOffset + insetOffset);
}
}
}
} else {
@@ -743,16 +758,30 @@ public class PortraitPagedViewHandler extends DefaultPagedViewHandler implements
secondaryIconParams.gravity = TOP | (isRtl ? START : END);
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);
if (oneIconHiddenDueToSmallWidth) {
// Center both icons
float centerX = -bottomToMidpointOffset + (taskIconHeight / 2f);
primaryIconView.setTranslationX(centerX);
secondaryIconView.setTranslationX(centerX);
} else {
// 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 (oneIconHiddenDueToSmallWidth) {
// Center both icons
float centerX =
-bottomToMidpointOffset - insetOffset + (taskIconHeight / 2f);
primaryIconView.setTranslationX(centerX);
secondaryIconView.setTranslationX(centerX);
} else {
// the task on the right (secondary) is slightly larger
primaryIconView.setTranslationX(-bottomToMidpointOffset - insetOffset);
secondaryIconView.setTranslationX(-bottomToMidpointOffset - insetOffset
+ taskIconHeight);
}
}
}
}
@@ -760,9 +789,15 @@ public class PortraitPagedViewHandler extends DefaultPagedViewHandler implements
primaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
secondaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
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 (oneIconHiddenDueToSmallWidth) {
// Center both icons
primaryIconView.setTranslationX(0);
secondaryIconView.setTranslationX(0);
} else {
// shifts icon half a width left (height is used here since icons are square)
primaryIconView.setTranslationX(-(taskIconHeight / 2f));
secondaryIconView.setTranslationX(taskIconHeight / 2f);
}
}
}
if (!enableOverviewIconMenu() && !inSplitSelection) {

View File

@@ -237,7 +237,8 @@ interface RecentsPagedOrientationHandler : PagedOrientationHandler {
isRtl: Boolean,
deviceProfile: DeviceProfile,
splitConfig: SplitConfigurationOptions.SplitBounds,
inSplitSelection: Boolean
inSplitSelection: Boolean,
oneIconHiddenDueToSmallWidth: Boolean,
)
/*

View File

@@ -353,17 +353,18 @@ class SeascapePagedViewHandler : LandscapePagedViewHandler() {
isRtl: Boolean,
overviewTaskMarginPx: Int,
dividerSize: Int,
oneIconHiddenDueToSmallWidth: Boolean,
): SplitIconPositions {
return if (Flags.enableOverviewIconMenu()) {
if (isRtl) {
SplitIconPositions(
topLeftY = totalThumbnailHeight - primarySnapshotHeight,
bottomRightY = 0
bottomRightY = 0,
)
} else {
SplitIconPositions(
topLeftY = 0,
bottomRightY = -(primarySnapshotHeight + dividerSize)
bottomRightY = -(primarySnapshotHeight + dividerSize),
)
}
} else {
@@ -372,10 +373,19 @@ class SeascapePagedViewHandler : LandscapePagedViewHandler() {
// from the bottom to the almost-center of the screen using the bottom margin.
// The primary snapshot is placed at the bottom, thus we translate the icons using
// the size of the primary snapshot minus the icon size for the top-left icon.
SplitIconPositions(
topLeftY = primarySnapshotHeight - taskIconHeight,
bottomRightY = primarySnapshotHeight + dividerSize
)
if (oneIconHiddenDueToSmallWidth) {
// Center both icons
val centerY = primarySnapshotHeight + ((dividerSize - taskIconHeight) / 2)
SplitIconPositions(
topLeftY = centerY,
bottomRightY = centerY,
)
} else {
SplitIconPositions(
topLeftY = primarySnapshotHeight - taskIconHeight,
bottomRightY = primarySnapshotHeight + dividerSize,
)
}
}
}

View File

@@ -187,14 +187,30 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu
val taskIconHeight = deviceProfile.overviewTaskIconSizePx
val isRtl = layoutDirection == LAYOUT_DIRECTION_RTL
val inSplitSelection = getThisTaskCurrentlyInSplitSelection() != INVALID_TASK_ID
var oneIconHiddenDueToSmallWidth = false
if (enableFlexibleTwoAppSplit()) {
val topLeftTaskPercent = splitBoundsConfig.leftTopTaskPercent
val bottomRightTaskPercent = splitBoundsConfig.rightBottomTaskPercent
val hideTopLeftIcon = topLeftTaskPercent < MINIMUM_RATIO_TO_SHOW_ICON
val hideBottomRightIcon = bottomRightTaskPercent < MINIMUM_RATIO_TO_SHOW_ICON
leftTopTaskContainer.iconView.setFlexSplitAlpha(if (hideTopLeftIcon) 0f else 1f)
rightBottomTaskContainer.iconView.setFlexSplitAlpha(if (hideBottomRightIcon) 0f else 1f)
// Update values for both icons' setFlexSplitAlpha. Mainly, we want to hide an icon if
// its app tile is too small. But we also have to set the alphas back if we go to
// split selection.
val hideLeftTopIcon: Boolean
val hideRightBottomIcon: Boolean
if (inSplitSelection) {
hideLeftTopIcon =
getThisTaskCurrentlyInSplitSelection() == splitBoundsConfig.leftTopTaskId
hideRightBottomIcon =
getThisTaskCurrentlyInSplitSelection() == splitBoundsConfig.rightBottomTaskId
} else {
hideLeftTopIcon = splitBoundsConfig.leftTopTaskPercent < MINIMUM_RATIO_TO_SHOW_ICON
hideRightBottomIcon =
splitBoundsConfig.rightBottomTaskPercent < MINIMUM_RATIO_TO_SHOW_ICON
if (hideLeftTopIcon || hideRightBottomIcon) {
oneIconHiddenDueToSmallWidth = true
}
}
leftTopTaskContainer.iconView.setFlexSplitAlpha(if (hideLeftTopIcon) 0f else 1f)
rightBottomTaskContainer.iconView.setFlexSplitAlpha(if (hideRightBottomIcon) 0f else 1f)
}
if (enableOverviewIconMenu()) {
@@ -217,6 +233,7 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu
deviceProfile,
splitBoundsConfig,
inSplitSelection,
oneIconHiddenDueToSmallWidth,
)
} else {
pagedOrientationHandler.setSplitIconParams(
@@ -231,6 +248,7 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu
deviceProfile,
splitBoundsConfig,
inSplitSelection,
oneIconHiddenDueToSmallWidth,
)
}
}

View File

@@ -62,6 +62,7 @@ class LandscapePagedViewHandlerTest {
isRTL,
OVERVIEW_TASK_MARGIN_PX,
DIVIDER_SIZE_PX,
oneIconHiddenDueToSmallWidth = false,
)
}

View File

@@ -62,6 +62,7 @@ class SeascapePagedViewHandlerTest {
isRTL,
OVERVIEW_TASK_MARGIN_PX,
DIVIDER_SIZE_PX,
oneIconHiddenDueToSmallWidth = false,
)
}