diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java index d9f668dd1b..b9615abf1d 100644 --- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java +++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java @@ -271,7 +271,8 @@ public class GroupedTaskView extends TaskView { getPagedOrientationHandler().setSplitIconParams(mIconView, mIconView2, taskIconHeight, mSnapshotView.getMeasuredWidth(), mSnapshotView.getMeasuredHeight(), - isRtl, deviceProfile, mSplitBoundsConfig); + getMeasuredHeight(), getMeasuredWidth(), isRtl, deviceProfile, + mSplitBoundsConfig); } private void updateSecondaryDwbPlacement() { diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java index 2609e549a5..d1f54cea29 100644 --- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java @@ -16,6 +16,7 @@ package com.android.launcher3.touch; +import static android.view.Gravity.BOTTOM; import static android.view.Gravity.CENTER_VERTICAL; import static android.view.Gravity.END; import static android.view.Gravity.START; @@ -468,18 +469,42 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { @Override public void setSplitIconParams(View primaryIconView, View secondaryIconView, int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight, - boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig) { + int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl, + DeviceProfile deviceProfile, StagedSplitBounds splitConfig) { FrameLayout.LayoutParams primaryIconParams = (FrameLayout.LayoutParams) primaryIconView.getLayoutParams(); FrameLayout.LayoutParams secondaryIconParams = new FrameLayout.LayoutParams(primaryIconParams); - primaryIconParams.gravity = CENTER_VERTICAL | (isRtl ? START : END); + // We calculate the "midpoint" of the thumbnail area, and place the icons there. + // This is the place where the thumbnail area splits by default, in a near-50/50 split. + // It is usually not exactly 50/50, due to insets/screen cutouts. + int fullscreenInsetThickness = deviceProfile.getInsets().top; + int fullscreenMidpointFromBottom = ((deviceProfile.heightPx - fullscreenInsetThickness) + / 2); + float midpointFromBottomPct = (float) fullscreenMidpointFromBottom / deviceProfile.heightPx; + float insetPct = (float) fullscreenInsetThickness / deviceProfile.heightPx; + int spaceAboveSnapshots = deviceProfile.overviewTaskThumbnailTopMarginPx; + int overviewThumbnailAreaThickness = groupedTaskViewHeight - spaceAboveSnapshots; + int bottomToMidpointOffset = (int) (overviewThumbnailAreaThickness * midpointFromBottomPct); + int insetOffset = (int) (overviewThumbnailAreaThickness * insetPct); + + primaryIconParams.gravity = BOTTOM | (isRtl ? START : END); + secondaryIconParams.gravity = BOTTOM | (isRtl ? START : END); primaryIconView.setTranslationX(0); - primaryIconView.setTranslationY(-(taskIconHeight / 2f)); - secondaryIconParams.gravity = CENTER_VERTICAL | (isRtl ? START : END); secondaryIconView.setTranslationX(0); - secondaryIconView.setTranslationY(taskIconHeight / 2f); + if (splitConfig.initiatedFromSeascape) { + // if the split was initiated from seascape, + // the task on the right (secondary) is slightly larger + primaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset); + secondaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset + + taskIconHeight); + } else { + // if not, + // the task on the left (primary) is slightly larger + primaryIconView.setTranslationY(-bottomToMidpointOffset); + secondaryIconView.setTranslationY(-bottomToMidpointOffset + taskIconHeight); + } primaryIconView.setLayoutParams(primaryIconParams); secondaryIconView.setLayoutParams(secondaryIconParams); diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java index 6e594e9cc6..1b171266fa 100644 --- a/src/com/android/launcher3/touch/PagedOrientationHandler.java +++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java @@ -146,7 +146,8 @@ public interface PagedOrientationHandler { int taskIconMargin, int taskIconHeight, int thumbnailTopMargin, boolean isRtl); void setSplitIconParams(View primaryIconView, View secondaryIconView, int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight, - boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig); + int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl, + DeviceProfile deviceProfile, StagedSplitBounds splitConfig); /* * The following two methods try to center the TaskMenuView in landscape by finding the center diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java index 926946ba7f..88c3bfe206 100644 --- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java +++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java @@ -18,6 +18,7 @@ package com.android.launcher3.touch; import static android.view.Gravity.BOTTOM; import static android.view.Gravity.CENTER_HORIZONTAL; +import static android.view.Gravity.END; import static android.view.Gravity.START; import static android.view.Gravity.TOP; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; @@ -565,18 +566,70 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { @Override public void setSplitIconParams(View primaryIconView, View secondaryIconView, int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight, - boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig) { + int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl, + DeviceProfile deviceProfile, StagedSplitBounds splitConfig) { FrameLayout.LayoutParams primaryIconParams = (FrameLayout.LayoutParams) primaryIconView.getLayoutParams(); FrameLayout.LayoutParams secondaryIconParams = new FrameLayout.LayoutParams(primaryIconParams); - primaryIconParams.gravity = TOP | CENTER_HORIZONTAL; - // shifts icon half a width left (height is used conveniently here since icons are square) - primaryIconView.setTranslationX(-(taskIconHeight / 2f)); + if (deviceProfile.isLandscape) { + // We calculate the "midpoint" of the thumbnail area, and place the icons there. + // This is the place where the thumbnail area splits by default, in a near-50/50 split. + // It is usually not exactly 50/50, due to insets/screen cutouts. + int fullscreenInsetThickness = deviceProfile.isSeascape() + ? deviceProfile.getInsets().right + : deviceProfile.getInsets().left; + int fullscreenMidpointFromBottom = ((deviceProfile.widthPx + - fullscreenInsetThickness) / 2); + float midpointFromBottomPct = (float) fullscreenMidpointFromBottom + / deviceProfile.widthPx; + float insetPct = (float) fullscreenInsetThickness / deviceProfile.widthPx; + int spaceAboveSnapshots = 0; + int overviewThumbnailAreaThickness = groupedTaskViewWidth - spaceAboveSnapshots; + int bottomToMidpointOffset = (int) (overviewThumbnailAreaThickness + * midpointFromBottomPct); + int insetOffset = (int) (overviewThumbnailAreaThickness * insetPct); + + 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); + } + } 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); + } + } + } 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); + } primaryIconView.setTranslationY(0); - secondaryIconParams.gravity = TOP | CENTER_HORIZONTAL; - secondaryIconView.setTranslationX(taskIconHeight / 2f); secondaryIconView.setTranslationY(0); primaryIconView.setLayoutParams(primaryIconParams); diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java index 9151796fc5..74b6a5b28e 100644 --- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java @@ -178,16 +178,46 @@ public class SeascapePagedViewHandler extends LandscapePagedViewHandler { @Override public void setSplitIconParams(View primaryIconView, View secondaryIconView, int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight, - boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig) { + int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl, + DeviceProfile deviceProfile, StagedSplitBounds splitConfig) { super.setSplitIconParams(primaryIconView, secondaryIconView, taskIconHeight, - primarySnapshotWidth, primarySnapshotHeight, isRtl, deviceProfile, splitConfig); + primarySnapshotWidth, primarySnapshotHeight, groupedTaskViewHeight, + groupedTaskViewWidth, isRtl, deviceProfile, splitConfig); FrameLayout.LayoutParams primaryIconParams = (FrameLayout.LayoutParams) primaryIconView.getLayoutParams(); FrameLayout.LayoutParams secondaryIconParams = (FrameLayout.LayoutParams) secondaryIconView.getLayoutParams(); - primaryIconParams.gravity = CENTER_VERTICAL | (isRtl ? END : START); - secondaryIconParams.gravity = CENTER_VERTICAL | (isRtl ? END : START); + // We calculate the "midpoint" of the thumbnail area, and place the icons there. + // This is the place where the thumbnail area splits by default, in a near-50/50 split. + // It is usually not exactly 50/50, due to insets/screen cutouts. + int fullscreenInsetThickness = deviceProfile.getInsets().top; + int fullscreenMidpointFromBottom = ((deviceProfile.heightPx + - fullscreenInsetThickness) / 2); + float midpointFromBottomPct = (float) fullscreenMidpointFromBottom / deviceProfile.heightPx; + float insetPct = (float) fullscreenInsetThickness / deviceProfile.heightPx; + int spaceAboveSnapshots = deviceProfile.overviewTaskThumbnailTopMarginPx; + int overviewThumbnailAreaThickness = groupedTaskViewHeight - spaceAboveSnapshots; + int bottomToMidpointOffset = (int) (overviewThumbnailAreaThickness * midpointFromBottomPct); + int insetOffset = (int) (overviewThumbnailAreaThickness * insetPct); + + primaryIconParams.gravity = BOTTOM | (isRtl ? END : START); + secondaryIconParams.gravity = BOTTOM | (isRtl ? END : START); + primaryIconView.setTranslationX(0); + secondaryIconView.setTranslationX(0); + if (splitConfig.initiatedFromSeascape) { + // if the split was initiated from seascape, + // the task on the right (secondary) is slightly larger + primaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset); + secondaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset + + taskIconHeight); + } else { + // if not, + // the task on the left (primary) is slightly larger + primaryIconView.setTranslationY(-bottomToMidpointOffset); + secondaryIconView.setTranslationY(-bottomToMidpointOffset + taskIconHeight); + } + primaryIconView.setLayoutParams(primaryIconParams); secondaryIconView.setLayoutParams(secondaryIconParams); } diff --git a/src/com/android/launcher3/util/SplitConfigurationOptions.java b/src/com/android/launcher3/util/SplitConfigurationOptions.java index cb714b2a8f..b40493ac25 100644 --- a/src/com/android/launcher3/util/SplitConfigurationOptions.java +++ b/src/com/android/launcher3/util/SplitConfigurationOptions.java @@ -113,6 +113,14 @@ public final class SplitConfigurationOptions { * the bounds were originally in */ public final boolean appsStackedVertically; + /** + * If {@code true}, that means at the time of creation of this object, the phone was in + * seascape orientation. This is important on devices with insets, because they do not split + * evenly -- one of the insets must be slightly larger to account for the inset. + * From landscape, it is the leftTop task that expands slightly. + * From seascape, it is the rightBottom task that expands slightly. + */ + public final boolean initiatedFromSeascape; public final int leftTopTaskId; public final int rightBottomTaskId; @@ -128,11 +136,22 @@ public final class SplitConfigurationOptions { this.visualDividerBounds = new Rect(leftTopBounds.left, leftTopBounds.bottom, leftTopBounds.right, rightBottomBounds.top); appsStackedVertically = true; + initiatedFromSeascape = false; } else { // horizontal apps, vertical divider this.visualDividerBounds = new Rect(leftTopBounds.right, leftTopBounds.top, rightBottomBounds.left, leftTopBounds.bottom); appsStackedVertically = false; + // The following check is unreliable on devices without insets + // (initiatedFromSeascape will always be set to false.) This happens to be OK for + // all our current uses, but should be refactored. + // TODO: Create a more reliable check, or refactor how splitting works on devices + // with insets. + if (rightBottomBounds.width() > leftTopBounds.width()) { + initiatedFromSeascape = true; + } else { + initiatedFromSeascape = false; + } } leftTaskPercent = this.leftTopBounds.width() / (float) rightBottomBounds.right;