Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a0077ffa authored by Chris Li's avatar Chris Li Committed by Android (Google) Code Review
Browse files

Merge "Add enforcement for unique displayarea id"

parents 25080800 9e44bf21
Loading
Loading
Loading
Loading
+89 −10
Original line number Diff line number Diff line
@@ -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();

+145 −9
Original line number Diff line number Diff line
@@ -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,11 +343,144 @@ public class DisplayAreaPolicyBuilderTest {
                .setTaskDisplayAreas(mTaskDisplayAreaList));
        builder4.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
                mGroupRoot2)
                .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",
                                FEATURE_VENDOR_FIRST + 1))));
                                mRoot.mFeatureId))));

        builder4.build(mWms);
        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