Apply SplitAttributesCalculator to SplitController
This CL implements SplitController#set(clear)SplitAttributesCalculator, and also invokes #computeSplitAttributesForParams in #computeSplitAttributes to compute the split attributes based on the current device state. fixes: 241043111 fixes: 241043028 Bug: 207494880 Test: atest WMJetpackUnitTests Change-Id: I0e3aadba451f2e585b048bfe2417239ed2f3ba3c
This commit is contained in:
@@ -103,6 +103,23 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
// Currently applied split configuration.
|
||||
@GuardedBy("mLock")
|
||||
private final List<EmbeddingRule> mSplitRules = new ArrayList<>();
|
||||
/**
|
||||
* A developer-defined {@link SplitAttributes} calculator to compute the current
|
||||
* {@link SplitAttributes} with the current device and window states.
|
||||
* It is registered via {@link #setSplitAttributesCalculator(SplitAttributesCalculator)}
|
||||
* and unregistered via {@link #clearSplitAttributesCalculator()}.
|
||||
* This is called when:
|
||||
* <ul>
|
||||
* <li>{@link SplitPresenter#updateSplitContainer(SplitContainer, TaskFragmentContainer,
|
||||
* WindowContainerTransaction)}</li>
|
||||
* <li>There's a started Activity which matches {@link SplitPairRule} </li>
|
||||
* <li>Checking whether the place holder should be launched if there's a Activity matches
|
||||
* {@link SplitPlaceholderRule} </li>
|
||||
* </ul>
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
@Nullable
|
||||
private SplitAttributesCalculator mSplitAttributesCalculator;
|
||||
/**
|
||||
* Map from Task id to {@link TaskContainer} which contains all TaskFragment and split pair info
|
||||
* below it.
|
||||
@@ -188,12 +205,22 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
|
||||
@Override
|
||||
public void setSplitAttributesCalculator(@NonNull SplitAttributesCalculator calculator) {
|
||||
// TODO: Implement this method
|
||||
synchronized (mLock) {
|
||||
mSplitAttributesCalculator = calculator;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearSplitAttributesCalculator() {
|
||||
// TODO: Implement this method
|
||||
synchronized (mLock) {
|
||||
mSplitAttributesCalculator = null;
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@Nullable
|
||||
SplitAttributesCalculator getSplitAttributesCalculator() {
|
||||
return mSplitAttributesCalculator;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -613,6 +640,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
if (taskContainer.isInPictureInPicture()) {
|
||||
return false;
|
||||
}
|
||||
// Always assume the TaskContainer if SplitAttributesCalculator is set
|
||||
if (mSplitAttributesCalculator != null) {
|
||||
return true;
|
||||
}
|
||||
// Check if the parent container bounds can support any split rule.
|
||||
for (EmbeddingRule rule : mSplitRules) {
|
||||
if (!(rule instanceof SplitRule)) {
|
||||
@@ -2005,8 +2036,17 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
}
|
||||
|
||||
/** Whether the two rules have the same presentation. */
|
||||
private static boolean haveSamePresentation(@NonNull SplitPairRule rule1,
|
||||
@VisibleForTesting
|
||||
static boolean haveSamePresentation(@NonNull SplitPairRule rule1,
|
||||
@NonNull SplitPairRule rule2, @NonNull WindowMetrics parentWindowMetrics) {
|
||||
if (rule1.getTag() != null || rule2.getTag() != null) {
|
||||
// Tag must be unique if it is set. We don't want to reuse the container if the rules
|
||||
// have different tags because they can have different SplitAttributes later through
|
||||
// SplitAttributesCalculator.
|
||||
return Objects.equals(rule1.getTag(), rule2.getTag());
|
||||
}
|
||||
// If both rules don't have tag, compare all SplitRules' properties that may affect their
|
||||
// SplitAttributes.
|
||||
// TODO(b/231655482): add util method to do the comparison in SplitPairRule.
|
||||
return rule1.getDefaultSplitAttributes().equals(rule2.getDefaultSplitAttributes())
|
||||
&& rule1.checkParentMetrics(parentWindowMetrics)
|
||||
|
||||
@@ -46,6 +46,7 @@ import androidx.window.extensions.embedding.SplitAttributes.SplitType;
|
||||
import androidx.window.extensions.embedding.SplitAttributes.SplitType.ExpandContainersSplitType;
|
||||
import androidx.window.extensions.embedding.SplitAttributes.SplitType.HingeSplitType;
|
||||
import androidx.window.extensions.embedding.SplitAttributes.SplitType.RatioSplitType;
|
||||
import androidx.window.extensions.embedding.SplitAttributesCalculator.SplitAttributesCalculatorParams;
|
||||
import androidx.window.extensions.embedding.TaskContainer.TaskProperties;
|
||||
import androidx.window.extensions.layout.DisplayFeature;
|
||||
import androidx.window.extensions.layout.FoldingFeature;
|
||||
@@ -126,7 +127,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
|
||||
})
|
||||
private @interface ResultCode {}
|
||||
|
||||
private static final SplitAttributes EXPAND_CONTAINERS_ATTRIBUTES =
|
||||
@VisibleForTesting
|
||||
static final SplitAttributes EXPAND_CONTAINERS_ATTRIBUTES =
|
||||
new SplitAttributes.Builder()
|
||||
.setSplitType(new ExpandContainersSplitType())
|
||||
.build();
|
||||
@@ -502,18 +504,29 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
|
||||
return !(splitAttributes.getSplitType() instanceof ExpandContainersSplitType);
|
||||
}
|
||||
|
||||
// TODO: expand this method to apply SplitLayoutCalculator#computeSplitAttributesForState
|
||||
@GuardedBy("mController.mLock")
|
||||
@NonNull
|
||||
SplitAttributes computeSplitAttributes(@NonNull TaskProperties taskProperties,
|
||||
@NonNull SplitRule rule, @Nullable Pair<Size, Size> minDimensionsPair) {
|
||||
final WindowMetrics taskWindowMetrics = getTaskWindowMetrics(
|
||||
taskProperties.getConfiguration());
|
||||
final SplitAttributes splitAttributes;
|
||||
if (rule.checkParentMetrics(taskWindowMetrics)) {
|
||||
splitAttributes = rule.getDefaultSplitAttributes();
|
||||
} else {
|
||||
splitAttributes = EXPAND_CONTAINERS_ATTRIBUTES;
|
||||
final Configuration taskConfiguration = taskProperties.getConfiguration();
|
||||
final WindowMetrics taskWindowMetrics = getTaskWindowMetrics(taskConfiguration);
|
||||
final SplitAttributesCalculator calculator = mController.getSplitAttributesCalculator();
|
||||
final SplitAttributes defaultSplitAttributes = rule.getDefaultSplitAttributes();
|
||||
final boolean isDefaultMinSizeSatisfied = rule.checkParentMetrics(taskWindowMetrics);
|
||||
if (calculator == null) {
|
||||
if (!isDefaultMinSizeSatisfied) {
|
||||
return EXPAND_CONTAINERS_ATTRIBUTES;
|
||||
}
|
||||
return sanitizeSplitAttributes(taskProperties, defaultSplitAttributes,
|
||||
minDimensionsPair);
|
||||
}
|
||||
final WindowLayoutInfo windowLayoutInfo = mController.mWindowLayoutComponent
|
||||
.getCurrentWindowLayoutInfo(taskProperties.getDisplayId(),
|
||||
taskConfiguration.windowConfiguration);
|
||||
final SplitAttributesCalculatorParams params = new SplitAttributesCalculatorParams(
|
||||
taskWindowMetrics, taskConfiguration, defaultSplitAttributes,
|
||||
isDefaultMinSizeSatisfied, windowLayoutInfo, rule.getTag());
|
||||
final SplitAttributes splitAttributes = calculator.computeSplitAttributesForParams(params);
|
||||
return sanitizeSplitAttributes(taskProperties, splitAttributes, minDimensionsPair);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,9 +28,12 @@ import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_I
|
||||
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
|
||||
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.DEFAULT_FINISH_PRIMARY_WITH_SECONDARY;
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.DEFAULT_FINISH_SECONDARY_WITH_PRIMARY;
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.SPLIT_ATTRIBUTES;
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_BOUNDS;
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TEST_TAG;
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createActivityInfoWithMinDimensions;
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createMockTaskFragmentInfo;
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitRule;
|
||||
@@ -76,6 +79,8 @@ import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowMetrics;
|
||||
import android.window.TaskFragmentInfo;
|
||||
import android.window.TaskFragmentOrganizer;
|
||||
import android.window.TaskFragmentParentInfo;
|
||||
@@ -1105,6 +1110,47 @@ public class SplitControllerTest {
|
||||
anyInt(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHasSamePresentation() {
|
||||
SplitPairRule splitRule1 = new SplitPairRule.Builder(
|
||||
activityPair -> true,
|
||||
activityIntentPair -> true,
|
||||
windowMetrics -> true)
|
||||
.setFinishSecondaryWithPrimary(DEFAULT_FINISH_SECONDARY_WITH_PRIMARY)
|
||||
.setFinishPrimaryWithSecondary(DEFAULT_FINISH_PRIMARY_WITH_SECONDARY)
|
||||
.setDefaultSplitAttributes(SPLIT_ATTRIBUTES)
|
||||
.build();
|
||||
SplitPairRule splitRule2 = new SplitPairRule.Builder(
|
||||
activityPair -> true,
|
||||
activityIntentPair -> true,
|
||||
windowMetrics -> true)
|
||||
.setFinishSecondaryWithPrimary(DEFAULT_FINISH_SECONDARY_WITH_PRIMARY)
|
||||
.setFinishPrimaryWithSecondary(DEFAULT_FINISH_PRIMARY_WITH_SECONDARY)
|
||||
.setDefaultSplitAttributes(SPLIT_ATTRIBUTES)
|
||||
.build();
|
||||
|
||||
assertTrue("Rules must have same presentation if tags are null and has same properties.",
|
||||
SplitController.haveSamePresentation(splitRule1, splitRule2,
|
||||
new WindowMetrics(TASK_BOUNDS, WindowInsets.CONSUMED)));
|
||||
|
||||
splitRule2 = new SplitPairRule.Builder(
|
||||
activityPair -> true,
|
||||
activityIntentPair -> true,
|
||||
windowMetrics -> true)
|
||||
.setFinishSecondaryWithPrimary(DEFAULT_FINISH_SECONDARY_WITH_PRIMARY)
|
||||
.setFinishPrimaryWithSecondary(DEFAULT_FINISH_PRIMARY_WITH_SECONDARY)
|
||||
.setDefaultSplitAttributes(SPLIT_ATTRIBUTES)
|
||||
.setTag(TEST_TAG)
|
||||
.build();
|
||||
|
||||
assertFalse("Rules must have different presentations if tags are not equal regardless"
|
||||
+ "of other properties",
|
||||
SplitController.haveSamePresentation(splitRule1, splitRule2,
|
||||
new WindowMetrics(TASK_BOUNDS, WindowInsets.CONSUMED)));
|
||||
|
||||
|
||||
}
|
||||
|
||||
/** Creates a mock activity in the organizer process. */
|
||||
private Activity createMockActivity() {
|
||||
final Activity activity = mock(Activity.class);
|
||||
|
||||
@@ -20,6 +20,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.DEFAULT_FINISH_PRIMARY_WITH_SECONDARY;
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.DEFAULT_FINISH_SECONDARY_WITH_PRIMARY;
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.SPLIT_ATTRIBUTES;
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_BOUNDS;
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
|
||||
@@ -28,6 +30,7 @@ import static androidx.window.extensions.embedding.EmbeddingTestUtils.createMock
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitRule;
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.createWindowLayoutInfo;
|
||||
import static androidx.window.extensions.embedding.EmbeddingTestUtils.getSplitBounds;
|
||||
import static androidx.window.extensions.embedding.SplitPresenter.EXPAND_CONTAINERS_ATTRIBUTES;
|
||||
import static androidx.window.extensions.embedding.SplitPresenter.POSITION_END;
|
||||
import static androidx.window.extensions.embedding.SplitPresenter.POSITION_FILL;
|
||||
import static androidx.window.extensions.embedding.SplitPresenter.POSITION_START;
|
||||
@@ -60,6 +63,7 @@ import android.content.res.Resources;
|
||||
import android.graphics.Rect;
|
||||
import android.os.IBinder;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.util.Pair;
|
||||
import android.util.Size;
|
||||
import android.window.TaskFragmentInfo;
|
||||
import android.window.WindowContainerTransaction;
|
||||
@@ -485,6 +489,49 @@ public class SplitPresenterTest {
|
||||
assertTrue(secondaryTf.isAbove(primaryTf));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComputeSplitAttributes() {
|
||||
final SplitPairRule splitPairRule = new SplitPairRule.Builder(
|
||||
activityPair -> true,
|
||||
activityIntentPair -> true,
|
||||
windowMetrics -> windowMetrics.getBounds().equals(TASK_BOUNDS))
|
||||
.setFinishSecondaryWithPrimary(DEFAULT_FINISH_SECONDARY_WITH_PRIMARY)
|
||||
.setFinishPrimaryWithSecondary(DEFAULT_FINISH_PRIMARY_WITH_SECONDARY)
|
||||
.setDefaultSplitAttributes(SPLIT_ATTRIBUTES)
|
||||
.build();
|
||||
final TaskContainer.TaskProperties taskProperties = getTaskProperty();
|
||||
|
||||
assertEquals(SPLIT_ATTRIBUTES, mPresenter.computeSplitAttributes(taskProperties,
|
||||
splitPairRule, null /* minDimensionsPair */));
|
||||
|
||||
final Pair<Size, Size> minDimensionsPair = new Pair<>(
|
||||
new Size(TASK_BOUNDS.width(), TASK_BOUNDS.height()), null);
|
||||
|
||||
assertEquals(EXPAND_CONTAINERS_ATTRIBUTES, mPresenter.computeSplitAttributes(taskProperties,
|
||||
splitPairRule, minDimensionsPair));
|
||||
|
||||
taskProperties.getConfiguration().windowConfiguration.setBounds(new Rect(
|
||||
TASK_BOUNDS.left + 1, TASK_BOUNDS.top + 1, TASK_BOUNDS.right + 1,
|
||||
TASK_BOUNDS.bottom + 1));
|
||||
|
||||
assertEquals(EXPAND_CONTAINERS_ATTRIBUTES, mPresenter.computeSplitAttributes(taskProperties,
|
||||
splitPairRule, null /* minDimensionsPair */));
|
||||
|
||||
final SplitAttributes splitAttributes = new SplitAttributes.Builder()
|
||||
.setSplitType(
|
||||
new SplitAttributes.SplitType.HingeSplitType(
|
||||
SplitAttributes.SplitType.RatioSplitType.splitEqually()
|
||||
)
|
||||
).build();
|
||||
|
||||
mController.setSplitAttributesCalculator(params -> {
|
||||
return splitAttributes;
|
||||
});
|
||||
|
||||
assertEquals(splitAttributes, mPresenter.computeSplitAttributes(taskProperties,
|
||||
splitPairRule, null /* minDimensionsPair */));
|
||||
}
|
||||
|
||||
private Activity createMockActivity() {
|
||||
final Activity activity = mock(Activity.class);
|
||||
final Configuration activityConfig = new Configuration();
|
||||
|
||||
Reference in New Issue
Block a user