Merge "Add enforcement for unique displayarea id"

This commit is contained in:
Chris Li
2020-12-03 20:24:22 +00:00
committed by Android (Google) Code Review
2 changed files with 235 additions and 20 deletions

View File

@@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_LAST;
import android.annotation.Nullable;
import android.os.Bundle;
@@ -166,32 +167,48 @@ class DisplayAreaPolicyBuilder {
return this;
}
/** Makes sure the setting meets the requirement. */
/**
* Makes sure the setting meets the requirement:
* 1. {@link mRootHierarchyBuilder} must be set.
* 2. {@link RootDisplayArea} and {@link TaskDisplayArea} must have unique ids.
* 3. {@link Feature} below the same {@link RootDisplayArea} must have unique ids.
* 4. There must be exactly one {@link HierarchyBuilder} that contains the IME container.
* 5. There must be exactly one {@link HierarchyBuilder} that contains the default
* {@link TaskDisplayArea} with id {@link FEATURE_DEFAULT_TASK_CONTAINER}.
* 6. None of the ids is greater than {@link FEATURE_VENDOR_LAST}.
*/
private void validate() {
if (mRootHierarchyBuilder == null) {
throw new IllegalStateException("Root must be set for the display area policy.");
}
final Set<Integer> rootIdSet = new ArraySet<>();
rootIdSet.add(mRootHierarchyBuilder.mRoot.mFeatureId);
final Set<Integer> uniqueIdSet = new ArraySet<>();
final Set<Integer> allIdSet = new ArraySet<>();
validateIds(mRootHierarchyBuilder, uniqueIdSet, allIdSet);
boolean containsImeContainer = mRootHierarchyBuilder.mImeContainer != null;
boolean containsDefaultTda = containsDefaultTaskDisplayArea(mRootHierarchyBuilder);
for (int i = 0; i < mDisplayAreaGroupHierarchyBuilders.size(); i++) {
HierarchyBuilder hierarchyBuilder = mDisplayAreaGroupHierarchyBuilders.get(i);
if (!rootIdSet.add(hierarchyBuilder.mRoot.mFeatureId)) {
throw new IllegalStateException("There should not be two RootDisplayAreas with id "
+ hierarchyBuilder.mRoot.mFeatureId);
}
validateIds(hierarchyBuilder, uniqueIdSet, allIdSet);
if (hierarchyBuilder.mTaskDisplayAreas.isEmpty()) {
throw new IllegalStateException(
"DisplayAreaGroup must contain at least one TaskDisplayArea.");
}
containsImeContainer = containsImeContainer || hierarchyBuilder.mImeContainer != null;
if (containsImeContainer) {
if (hierarchyBuilder.mImeContainer != null) {
throw new IllegalStateException(
"Only one DisplayArea hierarchy can contain the IME container");
}
} else {
containsImeContainer = hierarchyBuilder.mImeContainer != null;
}
if (containsDefaultTda) {
if (containsDefaultTaskDisplayArea(hierarchyBuilder)) {
throw new IllegalStateException("Only one TaskDisplayArea can have the feature "
+ "of FEATURE_DEFAULT_TASK_CONTAINER");
+ "id of FEATURE_DEFAULT_TASK_CONTAINER");
}
} else {
containsDefaultTda = containsDefaultTaskDisplayArea(hierarchyBuilder);
@@ -203,7 +220,8 @@ class DisplayAreaPolicyBuilder {
}
if (!containsDefaultTda) {
throw new IllegalStateException("There must be a default TaskDisplayArea.");
throw new IllegalStateException("There must be a default TaskDisplayArea with id of "
+ "FEATURE_DEFAULT_TASK_CONTAINER.");
}
}
@@ -218,6 +236,67 @@ class DisplayAreaPolicyBuilder {
return false;
}
/**
* Makes sure that ids meet requirement.
* {@link RootDisplayArea} and {@link TaskDisplayArea} must have unique ids.
* {@link Feature} below the same {@link RootDisplayArea} must have unique ids, but
* {@link Feature} below different {@link RootDisplayArea} can have the same id so that we can
* organize them together.
* None of the ids is greater than {@link FEATURE_VENDOR_LAST}
*
* @param uniqueIdSet ids of {@link RootDisplayArea} and {@link TaskDisplayArea} that must be
* unique,
* @param allIdSet ids of {@link RootDisplayArea}, {@link TaskDisplayArea} and {@link Feature}.
*/
private static void validateIds(HierarchyBuilder displayAreaHierarchy,
Set<Integer> uniqueIdSet, Set<Integer> allIdSet) {
// Root must have unique id.
final int rootId = displayAreaHierarchy.mRoot.mFeatureId;
if (!allIdSet.add(rootId) || !uniqueIdSet.add(rootId)) {
throw new IllegalStateException(
"RootDisplayArea must have unique id, but id=" + rootId + " is not unique.");
}
if (rootId > FEATURE_VENDOR_LAST) {
throw new IllegalStateException(
"RootDisplayArea should not have an id greater than FEATURE_VENDOR_LAST.");
}
// TDAs must have unique id.
for (int i = 0; i < displayAreaHierarchy.mTaskDisplayAreas.size(); i++) {
final int taskDisplayAreaId = displayAreaHierarchy.mTaskDisplayAreas.get(i).mFeatureId;
if (!allIdSet.add(taskDisplayAreaId) || !uniqueIdSet.add(taskDisplayAreaId)) {
throw new IllegalStateException("TaskDisplayArea must have unique id, but id="
+ taskDisplayAreaId + " is not unique.");
}
if (taskDisplayAreaId > FEATURE_VENDOR_LAST) {
throw new IllegalStateException("TaskDisplayArea declared in the policy should not"
+ "have an id greater than FEATURE_VENDOR_LAST.");
}
}
// Features below the same root must have unique ids.
final Set<Integer> featureIdSet = new ArraySet<>();
for (int i = 0; i < displayAreaHierarchy.mFeatures.size(); i++) {
final int featureId = displayAreaHierarchy.mFeatures.get(i).getId();
if (uniqueIdSet.contains(featureId)) {
throw new IllegalStateException("Feature must not have same id with any "
+ "RootDisplayArea or TaskDisplayArea, but id=" + featureId + " is used");
}
if (!featureIdSet.add(featureId)) {
throw new IllegalStateException("Feature below the same root must have unique id, "
+ "but id=" + featureId + " is not unique.");
}
if (featureId > FEATURE_VENDOR_LAST) {
throw new IllegalStateException(
"Feature should not have an id greater than FEATURE_VENDOR_LAST.");
}
}
// Features below different roots can have the same id so that we can organize them
// together.
allIdSet.addAll(featureIdSet);
}
Result build(WindowManagerService wmService) {
validate();

View File

@@ -32,6 +32,7 @@ import static android.window.DisplayAreaOrganizer.FEATURE_IME_PLACEHOLDER;
import static android.window.DisplayAreaOrganizer.FEATURE_ONE_HANDED;
import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_LAST;
import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION;
import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
@@ -114,11 +115,13 @@ public class DisplayAreaPolicyBuilderTest {
final Feature bar;
DisplayAreaPolicyBuilder.HierarchyBuilder rootHierarchy =
new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
.addFeature(foo = new Feature.Builder(mPolicy, "Foo", 0)
.addFeature(foo = new Feature.Builder(mPolicy, "Foo",
FEATURE_VENDOR_FIRST)
.upTo(TYPE_STATUS_BAR)
.and(TYPE_NAVIGATION_BAR)
.build())
.addFeature(bar = new Feature.Builder(mPolicy, "Bar", 1)
.addFeature(bar = new Feature.Builder(mPolicy, "Bar",
FEATURE_VENDOR_FIRST + 1)
.all()
.except(TYPE_STATUS_BAR)
.build())
@@ -240,12 +243,14 @@ public class DisplayAreaPolicyBuilderTest {
final Feature other;
DisplayAreaPolicyBuilder.HierarchyBuilder rootHierarchy =
new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
.addFeature(dimmable = new Feature.Builder(mPolicy, "Dimmable", 0)
.addFeature(dimmable = new Feature.Builder(mPolicy, "Dimmable",
FEATURE_VENDOR_FIRST)
.upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
.except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
.setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
.build())
.addFeature(other = new Feature.Builder(mPolicy, "Other", 1)
.addFeature(other = new Feature.Builder(mPolicy, "Other",
FEATURE_VENDOR_FIRST + 1)
.all()
.build())
.setImeContainer(mImeContainer)
@@ -313,9 +318,7 @@ public class DisplayAreaPolicyBuilderTest {
builder2.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
mGroupRoot1)
.setImeContainer(mImeContainer)
.setTaskDisplayAreas(Lists.newArrayList(
new TaskDisplayArea(mDisplayContent, mWms, "testTda",
FEATURE_VENDOR_FIRST + 1))));
.setTaskDisplayAreas(Lists.newArrayList(mTda1)));
assertThrows(IllegalStateException.class, () -> builder2.build(mWms));
@@ -340,13 +343,146 @@ public class DisplayAreaPolicyBuilderTest {
.setTaskDisplayAreas(mTaskDisplayAreaList));
builder4.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
mGroupRoot2)
.setTaskDisplayAreas(Lists.newArrayList(
new TaskDisplayArea(mDisplayContent, mWms, "testTda",
FEATURE_VENDOR_FIRST + 1))));
.setTaskDisplayAreas(Lists.newArrayList(mTda1)));
builder4.build(mWms);
}
@Test
public void testBuilder_rootHasUniqueId() {
// Root must have different id from all roots.
final DisplayAreaPolicyBuilder builder1 = new DisplayAreaPolicyBuilder();
builder1.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
.setImeContainer(mImeContainer)
.setTaskDisplayAreas(mTaskDisplayAreaList));
final RootDisplayArea groupRoot1 = new SurfacelessDisplayAreaRoot(mWms, "group1",
mRoot.mFeatureId);
builder1.addDisplayAreaGroupHierarchy(
new DisplayAreaPolicyBuilder.HierarchyBuilder(groupRoot1)
.setTaskDisplayAreas(Lists.newArrayList(mTda1)));
assertThrows(IllegalStateException.class, () -> builder1.build(mWms));
// Root must have different id from all TDAs.
final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder();
builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
.setImeContainer(mImeContainer)
.setTaskDisplayAreas(Lists.newArrayList(
mDefaultTaskDisplayArea,
new TaskDisplayArea(mDisplayContent, mWms, "testTda",
mRoot.mFeatureId))));
assertThrows(IllegalStateException.class, () -> builder2.build(mWms));
// Root must have different id from all features.
final DisplayAreaPolicyBuilder builder3 = new DisplayAreaPolicyBuilder();
builder3.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
.setImeContainer(mImeContainer)
.setTaskDisplayAreas(mTaskDisplayAreaList)
.addFeature(new Feature.Builder(mPolicy, "testFeature", mRoot.mFeatureId)
.all()
.build()));
assertThrows(IllegalStateException.class, () -> builder3.build(mWms));
}
@Test
public void testBuilder_taskDisplayAreaHasUniqueId() {
// TDA must have different id from all TDAs.
final DisplayAreaPolicyBuilder builder = new DisplayAreaPolicyBuilder();
final List<TaskDisplayArea> tdaList = Lists.newArrayList(
mDefaultTaskDisplayArea,
mTda1,
new TaskDisplayArea(mDisplayContent, mWms, "tda2", mTda1.mFeatureId));
builder.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
.setImeContainer(mImeContainer)
.setTaskDisplayAreas(tdaList));
assertThrows(IllegalStateException.class, () -> builder.build(mWms));
// TDA must have different id from all features.
final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder();
builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
.setImeContainer(mImeContainer)
.setTaskDisplayAreas(Lists.newArrayList(
mDefaultTaskDisplayArea,
mTda1))
.addFeature(new Feature.Builder(mPolicy, "testFeature", mTda1.mFeatureId)
.all()
.build()));
assertThrows(IllegalStateException.class, () -> builder2.build(mWms));
}
@Test
public void testBuilder_featureHasUniqueId() {
// Feature must have different id from features below the same root.
final DisplayAreaPolicyBuilder builder = new DisplayAreaPolicyBuilder();
builder.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
.setImeContainer(mImeContainer)
.setTaskDisplayAreas(mTaskDisplayAreaList)
.addFeature(new Feature.Builder(mPolicy, "feature1", FEATURE_VENDOR_FIRST + 10)
.all()
.build())
.addFeature(new Feature.Builder(mPolicy, "feature2", FEATURE_VENDOR_FIRST + 10)
.upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
.build()));
assertThrows(IllegalStateException.class, () -> builder.build(mWms));
// Features below different root can have the same id.
final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder();
builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
.setImeContainer(mImeContainer)
.setTaskDisplayAreas(mTaskDisplayAreaList)
.addFeature(new Feature.Builder(mPolicy, "feature1", FEATURE_VENDOR_FIRST + 10)
.all()
.build()));
builder2.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
mGroupRoot1)
.setTaskDisplayAreas(Lists.newArrayList(mTda1))
.addFeature(new Feature.Builder(mPolicy, "feature2", FEATURE_VENDOR_FIRST + 10)
.all()
.build()));
builder2.build(mWms);
}
@Test
public void testBuilder_idsNotGreaterThanFeatureVendorLast() {
// Root id should not be greater than FEATURE_VENDOR_LAST.
final DisplayAreaPolicyBuilder builder1 = new DisplayAreaPolicyBuilder();
final RootDisplayArea root = new SurfacelessDisplayAreaRoot(mWms, "testRoot",
FEATURE_VENDOR_LAST + 1);
builder1.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(root)
.setImeContainer(mImeContainer)
.setTaskDisplayAreas(mTaskDisplayAreaList));
assertThrows(IllegalStateException.class, () -> builder1.build(mWms));
// TDA id should not be greater than FEATURE_VENDOR_LAST.
final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder();
builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(root)
.setImeContainer(mImeContainer)
.setTaskDisplayAreas(Lists.newArrayList(
mDefaultTaskDisplayArea,
new TaskDisplayArea(mDisplayContent, mWms, "testTda",
FEATURE_VENDOR_LAST + 1))));
assertThrows(IllegalStateException.class, () -> builder2.build(mWms));
// Feature id should not be greater than FEATURE_VENDOR_LAST.
final DisplayAreaPolicyBuilder builder3 = new DisplayAreaPolicyBuilder();
builder3.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
.setImeContainer(mImeContainer)
.setTaskDisplayAreas(mTaskDisplayAreaList)
.addFeature(new Feature.Builder(mPolicy, "testFeature", FEATURE_VENDOR_LAST + 1)
.all()
.build()));
assertThrows(IllegalStateException.class, () -> builder3.build(mWms));
}
@Test
public void testBuilder_displayAreaGroup_attachDisplayAreas() {
final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()