Fix NPE when using hinge split type without FoldingFeature

Before this CL, we only compute SplitType in getRelBounds.
However, we actually obtain the bounds to check minimum
dimensions in #computeSplitAttributes.

This CL moves the splitType calculation to
 #getPrimaryBounds and #getSecondaryBounds to cover the
minimum dimensions to fix NPE.

Test: atest ActivityEmbeddingBoundsTests
          on device without foldingFeature
Test: atest SplitPresenterTest
Bug: 263565586
Change-Id: Ibb826c25f072cdffd5b5adcd19571fe446d64f51
This commit is contained in:
Charles Chen
2023-03-29 19:20:25 +08:00
parent 6745428bc6
commit a296b769b2
2 changed files with 92 additions and 52 deletions

View File

@@ -710,24 +710,16 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
@NonNull SplitAttributes splitAttributes) { @NonNull SplitAttributes splitAttributes) {
final Configuration taskConfiguration = taskProperties.getConfiguration(); final Configuration taskConfiguration = taskProperties.getConfiguration();
final FoldingFeature foldingFeature = getFoldingFeature(taskProperties); final FoldingFeature foldingFeature = getFoldingFeature(taskProperties);
final SplitType splitType = computeSplitType(splitAttributes, taskConfiguration, if (!shouldShowSplit(splitAttributes)) {
foldingFeature);
final SplitAttributes computedSplitAttributes = new SplitAttributes.Builder()
.setSplitType(splitType)
.setLayoutDirection(splitAttributes.getLayoutDirection())
.build();
if (!shouldShowSplit(computedSplitAttributes)) {
return new Rect(); return new Rect();
} }
final Rect bounds; final Rect bounds;
switch (position) { switch (position) {
case POSITION_START: case POSITION_START:
bounds = getPrimaryBounds(taskConfiguration, computedSplitAttributes, bounds = getPrimaryBounds(taskConfiguration, splitAttributes, foldingFeature);
foldingFeature);
break; break;
case POSITION_END: case POSITION_END:
bounds = getSecondaryBounds(taskConfiguration, computedSplitAttributes, bounds = getSecondaryBounds(taskConfiguration, splitAttributes, foldingFeature);
foldingFeature);
break; break;
case POSITION_FILL: case POSITION_FILL:
default: default:
@@ -742,29 +734,76 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
@NonNull @NonNull
private Rect getPrimaryBounds(@NonNull Configuration taskConfiguration, private Rect getPrimaryBounds(@NonNull Configuration taskConfiguration,
@NonNull SplitAttributes splitAttributes, @Nullable FoldingFeature foldingFeature) { @NonNull SplitAttributes splitAttributes, @Nullable FoldingFeature foldingFeature) {
if (!shouldShowSplit(splitAttributes)) { final SplitAttributes computedSplitAttributes = updateSplitAttributesType(splitAttributes,
computeSplitType(splitAttributes, taskConfiguration, foldingFeature));
if (!shouldShowSplit(computedSplitAttributes)) {
return new Rect(); return new Rect();
} }
switch (splitAttributes.getLayoutDirection()) { switch (computedSplitAttributes.getLayoutDirection()) {
case SplitAttributes.LayoutDirection.LEFT_TO_RIGHT: { case SplitAttributes.LayoutDirection.LEFT_TO_RIGHT: {
return getLeftContainerBounds(taskConfiguration, splitAttributes, foldingFeature); return getLeftContainerBounds(taskConfiguration, computedSplitAttributes,
foldingFeature);
} }
case SplitAttributes.LayoutDirection.RIGHT_TO_LEFT: { case SplitAttributes.LayoutDirection.RIGHT_TO_LEFT: {
return getRightContainerBounds(taskConfiguration, splitAttributes, foldingFeature); return getRightContainerBounds(taskConfiguration, computedSplitAttributes,
foldingFeature);
} }
case SplitAttributes.LayoutDirection.LOCALE: { case SplitAttributes.LayoutDirection.LOCALE: {
final boolean isLtr = taskConfiguration.getLayoutDirection() final boolean isLtr = taskConfiguration.getLayoutDirection()
== View.LAYOUT_DIRECTION_LTR; == View.LAYOUT_DIRECTION_LTR;
return isLtr return isLtr
? getLeftContainerBounds(taskConfiguration, splitAttributes, foldingFeature) ? getLeftContainerBounds(taskConfiguration, computedSplitAttributes,
: getRightContainerBounds(taskConfiguration, splitAttributes, foldingFeature)
: getRightContainerBounds(taskConfiguration, computedSplitAttributes,
foldingFeature); foldingFeature);
} }
case SplitAttributes.LayoutDirection.TOP_TO_BOTTOM: { case SplitAttributes.LayoutDirection.TOP_TO_BOTTOM: {
return getTopContainerBounds(taskConfiguration, splitAttributes, foldingFeature); return getTopContainerBounds(taskConfiguration, computedSplitAttributes,
foldingFeature);
} }
case SplitAttributes.LayoutDirection.BOTTOM_TO_TOP: { case SplitAttributes.LayoutDirection.BOTTOM_TO_TOP: {
return getBottomContainerBounds(taskConfiguration, splitAttributes, foldingFeature); return getBottomContainerBounds(taskConfiguration, computedSplitAttributes,
foldingFeature);
}
default:
throw new IllegalArgumentException("Unknown layout direction:"
+ computedSplitAttributes.getLayoutDirection());
}
}
@NonNull
private Rect getSecondaryBounds(@NonNull Configuration taskConfiguration,
@NonNull SplitAttributes splitAttributes, @Nullable FoldingFeature foldingFeature) {
final SplitAttributes computedSplitAttributes = updateSplitAttributesType(splitAttributes,
computeSplitType(splitAttributes, taskConfiguration, foldingFeature));
if (!shouldShowSplit(computedSplitAttributes)) {
return new Rect();
}
switch (computedSplitAttributes.getLayoutDirection()) {
case SplitAttributes.LayoutDirection.LEFT_TO_RIGHT: {
return getRightContainerBounds(taskConfiguration, computedSplitAttributes,
foldingFeature);
}
case SplitAttributes.LayoutDirection.RIGHT_TO_LEFT: {
return getLeftContainerBounds(taskConfiguration, computedSplitAttributes,
foldingFeature);
}
case SplitAttributes.LayoutDirection.LOCALE: {
final boolean isLtr = taskConfiguration.getLayoutDirection()
== View.LAYOUT_DIRECTION_LTR;
return isLtr
? getRightContainerBounds(taskConfiguration, computedSplitAttributes,
foldingFeature)
: getLeftContainerBounds(taskConfiguration, computedSplitAttributes,
foldingFeature);
}
case SplitAttributes.LayoutDirection.TOP_TO_BOTTOM: {
return getBottomContainerBounds(taskConfiguration, computedSplitAttributes,
foldingFeature);
}
case SplitAttributes.LayoutDirection.BOTTOM_TO_TOP: {
return getTopContainerBounds(taskConfiguration, computedSplitAttributes,
foldingFeature);
} }
default: default:
throw new IllegalArgumentException("Unknown layout direction:" throw new IllegalArgumentException("Unknown layout direction:"
@@ -772,38 +811,17 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
} }
} }
@NonNull /**
private Rect getSecondaryBounds(@NonNull Configuration taskConfiguration, * Returns the {@link SplitAttributes} that update the {@link SplitType} to
@NonNull SplitAttributes splitAttributes, @Nullable FoldingFeature foldingFeature) { * {@code splitTypeToUpdate}.
if (!shouldShowSplit(splitAttributes)) { */
return new Rect(); private static SplitAttributes updateSplitAttributesType(
} @NonNull SplitAttributes splitAttributes, @NonNull SplitType splitTypeToUpdate) {
switch (splitAttributes.getLayoutDirection()) { return new SplitAttributes.Builder()
case SplitAttributes.LayoutDirection.LEFT_TO_RIGHT: { .setSplitType(splitTypeToUpdate)
return getRightContainerBounds(taskConfiguration, splitAttributes, foldingFeature); .setLayoutDirection(splitAttributes.getLayoutDirection())
} .setAnimationBackgroundColor(splitAttributes.getAnimationBackgroundColor())
case SplitAttributes.LayoutDirection.RIGHT_TO_LEFT: { .build();
return getLeftContainerBounds(taskConfiguration, splitAttributes, foldingFeature);
}
case SplitAttributes.LayoutDirection.LOCALE: {
final boolean isLtr = taskConfiguration.getLayoutDirection()
== View.LAYOUT_DIRECTION_LTR;
return isLtr
? getRightContainerBounds(taskConfiguration, splitAttributes,
foldingFeature)
: getLeftContainerBounds(taskConfiguration, splitAttributes,
foldingFeature);
}
case SplitAttributes.LayoutDirection.TOP_TO_BOTTOM: {
return getBottomContainerBounds(taskConfiguration, splitAttributes, foldingFeature);
}
case SplitAttributes.LayoutDirection.BOTTOM_TO_TOP: {
return getTopContainerBounds(taskConfiguration, splitAttributes, foldingFeature);
}
default:
throw new IllegalArgumentException("Unknown layout direction:"
+ splitAttributes.getLayoutDirection());
}
} }
@NonNull @NonNull
@@ -898,7 +916,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
} }
@Nullable @Nullable
private FoldingFeature getFoldingFeature(@NonNull TaskProperties taskProperties) { @VisibleForTesting
FoldingFeature getFoldingFeature(@NonNull TaskProperties taskProperties) {
final int displayId = taskProperties.getDisplayId(); final int displayId = taskProperties.getDisplayId();
final WindowConfiguration windowConfiguration = taskProperties.getConfiguration() final WindowConfiguration windowConfiguration = taskProperties.getConfiguration()
.windowConfiguration; .windowConfiguration;

View File

@@ -729,6 +729,27 @@ public class SplitPresenterTest {
splitPairRule, SPLIT_ATTRIBUTES, null /* minDimensionsPair */)); splitPairRule, SPLIT_ATTRIBUTES, null /* minDimensionsPair */));
} }
@Test
public void testComputeSplitAttributesOnHingeSplitTypeOnDeviceWithoutFoldingFeature() {
final SplitAttributes hingeSplitAttrs = new SplitAttributes.Builder()
.setSplitType(new SplitAttributes.SplitType.HingeSplitType(
SplitAttributes.SplitType.RatioSplitType.splitEqually()))
.build();
final SplitPairRule splitPairRule = createSplitPairRuleBuilder(
activityPair -> true,
activityIntentPair -> true,
windowMetrics -> windowMetrics.getBounds().equals(TASK_BOUNDS))
.setFinishSecondaryWithPrimary(DEFAULT_FINISH_SECONDARY_WITH_PRIMARY)
.setFinishPrimaryWithSecondary(DEFAULT_FINISH_PRIMARY_WITH_SECONDARY)
.setDefaultSplitAttributes(hingeSplitAttrs)
.build();
final TaskContainer.TaskProperties taskProperties = getTaskProperties();
doReturn(null).when(mPresenter).getFoldingFeature(any());
assertEquals(hingeSplitAttrs, mPresenter.computeSplitAttributes(taskProperties,
splitPairRule, hingeSplitAttrs, null /* minDimensionsPair */));
}
@Test @Test
public void testGetTaskWindowMetrics() { public void testGetTaskWindowMetrics() {
final Configuration taskConfig = new Configuration(); final Configuration taskConfig = new Configuration();