Loading services/core/java/com/android/server/policy/WindowManagerPolicy.java +4 −0 Original line number Diff line number Diff line Loading @@ -866,6 +866,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { } } default int getMaxWindowLayer() { return 35; } /** * Return how to Z-order sub-windows in relation to the window they are attached to. * Return positive to have them ordered in front, negative for behind. Loading services/core/java/com/android/server/wm/DisplayArea.java +5 −0 Original line number Diff line number Diff line Loading @@ -101,6 +101,11 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { return mName; } @Override public String toString() { return mName + "@" + System.identityHashCode(this); } @Override public final void dumpDebug(ProtoOutputStream proto, long fieldId, int logLevel) { final long token = proto.start(fieldId); Loading services/core/java/com/android/server/wm/DisplayAreaPolicy.java +11 −64 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import android.content.res.Resources; import android.text.TextUtils; Loading @@ -43,7 +41,7 @@ public abstract class DisplayAreaPolicy { /** * The Tasks container. Tasks etc. are automatically added to this container. */ protected final TaskContainers mTaskContainers; protected final DisplayArea<? extends ActivityStack> mTaskContainers; /** * Construct a new {@link DisplayAreaPolicy} Loading @@ -58,7 +56,8 @@ public abstract class DisplayAreaPolicy { */ protected DisplayAreaPolicy(WindowManagerService wmService, DisplayContent content, DisplayArea.Root root, DisplayArea<? extends WindowContainer> imeContainer, TaskContainers taskContainers) { DisplayArea<? extends WindowContainer> imeContainer, DisplayArea<? extends ActivityStack> taskContainers) { mWmService = wmService; mContent = content; mRoot = root; Loading @@ -83,67 +82,15 @@ public abstract class DisplayAreaPolicy { */ public abstract void addWindow(WindowToken token); /** * Default policy that has no special features. */ public static class Default extends DisplayAreaPolicy { public Default(WindowManagerService wmService, DisplayContent content, DisplayArea.Root root, DisplayArea<? extends WindowContainer> imeContainer, TaskContainers taskContainers) { super(wmService, content, root, imeContainer, taskContainers); } private final DisplayArea.Tokens mBelow = new DisplayArea.Tokens(mWmService, DisplayArea.Type.BELOW_TASKS, "BelowTasks"); private final DisplayArea<DisplayArea> mAbove = new DisplayArea<>(mWmService, DisplayArea.Type.ABOVE_TASKS, "AboveTasks"); private final DisplayArea.Tokens mAboveBelowIme = new DisplayArea.Tokens(mWmService, DisplayArea.Type.ABOVE_TASKS, "AboveTasksBelowIme"); private final DisplayArea.Tokens mAboveAboveIme = new DisplayArea.Tokens(mWmService, DisplayArea.Type.ABOVE_TASKS, "AboveTasksAboveIme"); @Override public void attachDisplayAreas() { mRoot.addChild(mBelow, 0); mRoot.addChild(mTaskContainers, 1); mRoot.addChild(mAbove, 2); mAbove.addChild(mAboveBelowIme, 0); mAbove.addChild(mImeContainer, 1); mAbove.addChild(mAboveAboveIme, 2); } @Override public void addWindow(WindowToken token) { switch (DisplayArea.Type.typeOf(token)) { case ABOVE_TASKS: if (token.getWindowLayerFromType() < mWmService.mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD)) { mAboveBelowIme.addChild(token); } else { mAboveAboveIme.addChild(token); } break; case BELOW_TASKS: mBelow.addChild(token); break; default: throw new IllegalArgumentException("don't know how to sort " + token); } } /** Provider for {@link DisplayAreaPolicy.Default platform-default display area policy}. */ static class Provider implements DisplayAreaPolicy.Provider { /** Provider for platform-default display area policy. */ static final class DefaultProvider implements DisplayAreaPolicy.Provider { @Override public DisplayAreaPolicy instantiate(WindowManagerService wmService, DisplayContent content, DisplayArea.Root root, DisplayArea<? extends WindowContainer> imeContainer, TaskContainers taskContainers) { return new DisplayAreaPolicy.Default(wmService, content, root, imeContainer, taskContainers); } return new DisplayAreaPolicyBuilder() .build(wmService, content, root, imeContainer, taskContainers); } } Loading Loading @@ -172,7 +119,7 @@ public abstract class DisplayAreaPolicy { String name = res.getString( com.android.internal.R.string.config_deviceSpecificDisplayAreaPolicyProvider); if (TextUtils.isEmpty(name)) { return new DisplayAreaPolicy.Default.Provider(); return new DisplayAreaPolicy.DefaultProvider(); } try { return (Provider) Class.forName(name).newInstance(); Loading services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java 0 → 100644 +371 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; 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 com.android.internal.annotations.VisibleForTesting; import com.android.server.policy.WindowManagerPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; /** * A builder for instantiating a complex {@link DisplayAreaPolicy} * * <p>Given a set of features (that each target a set of window types), it builds the necessary * DisplayArea hierarchy. * * <p>Example: <br /> * * <pre> * // Feature for targeting everything below the magnification overlay: * new DisplayAreaPolicyBuilder(...) * .addFeature(new Feature.Builder(..., "Magnification") * .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY) * .build()) * .build(...) * * // Builds a policy with the following hierarchy: * - DisplayArea.Root * - Magnification * - DisplayArea.Tokens (Wallpapers are attached here) * - TaskContainers * - DisplayArea.Tokens (windows above Tasks up to IME are attached here) * - ImeContainers * - DisplayArea.Tokens (windows above IME up to TYPE_ACCESSIBILITY_OVERLAY attached here) * - DisplayArea.Tokens (TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY and up are attached here) * * </pre> * * // TODO(display-area): document more complex scenarios where we need multiple areas per feature. */ class DisplayAreaPolicyBuilder { private final ArrayList<Feature> mFeatures = new ArrayList<>(); /** * A feature that requires {@link DisplayArea DisplayArea(s)}. */ static class Feature { private final String mName; private final boolean[] mWindowLayers; private Feature(String name, boolean[] windowLayers) { mName = name; mWindowLayers = windowLayers; } static class Builder { private final WindowManagerPolicy mPolicy; private final String mName; private final boolean[] mLayers; /** * Build a new feature that applies to a set of window types as specified by the builder * methods. * * <p>The set of types is updated iteratively in the order of the method invocations. * For example, {@code all().except(TYPE_STATUS_BAR)} expresses that a feature should * apply to all types except TYPE_STATUS_BAR. * * The builder starts out with the feature not applying to any types. * * @param name the name of the feature. */ Builder(WindowManagerPolicy policy, String name) { mPolicy = policy; mName = name; mLayers = new boolean[mPolicy.getMaxWindowLayer()]; } /** * Set that the feature applies to all window types. */ Builder all() { Arrays.fill(mLayers, true); return this; } /** * Set that the feature applies to the given window types. */ Builder and(int... types) { for (int i = 0; i < types.length; i++) { int type = types[i]; set(type, true); } return this; } /** * Set that the feature does not apply to the given window types. */ Builder except(int... types) { for (int i = 0; i < types.length; i++) { int type = types[i]; set(type, false); } return this; } /** * Set that the feature applies window types that are layerd at or below the layer of * the given window type. */ Builder upTo(int typeInclusive) { final int max = layerFromType(typeInclusive, false); for (int i = 0; i < max; i++) { mLayers[i] = true; } set(typeInclusive, true); return this; } Feature build() { return new Feature(mName, mLayers.clone()); } private void set(int type, boolean value) { mLayers[layerFromType(type, true)] = value; if (type == TYPE_APPLICATION_OVERLAY) { mLayers[layerFromType(type, true)] = value; mLayers[layerFromType(TYPE_SYSTEM_ALERT, false)] = value; mLayers[layerFromType(TYPE_SYSTEM_OVERLAY, false)] = value; mLayers[layerFromType(TYPE_SYSTEM_ERROR, false)] = value; } } private int layerFromType(int type, boolean internalWindows) { return mPolicy.getWindowLayerFromTypeLw(type, internalWindows); } } } static class Result extends DisplayAreaPolicy { private static final int LEAF_TYPE_TASK_CONTAINERS = 1; private static final int LEAF_TYPE_IME_CONTAINERS = 2; private static final int LEAF_TYPE_TOKENS = 0; private final int mMaxWindowLayer = mWmService.mPolicy.getMaxWindowLayer(); private final ArrayList<Feature> mFeatures; private final Map<Feature, List<DisplayArea<? extends WindowContainer>>> mAreas; private final DisplayArea.Tokens[] mAreaForLayer = new DisplayArea.Tokens[mMaxWindowLayer]; Result(WindowManagerService wmService, DisplayContent content, DisplayArea.Root root, DisplayArea<? extends WindowContainer> imeContainer, DisplayArea<? extends ActivityStack> taskStacks, ArrayList<Feature> features) { super(wmService, content, root, imeContainer, taskStacks); mFeatures = features; mAreas = new HashMap<>(features.size()); for (int i = 0; i < mFeatures.size(); i++) { mAreas.put(mFeatures.get(i), new ArrayList<>()); } } @Override public void attachDisplayAreas() { // This method constructs the layer hierarchy with the following properties: // (1) Every feature maps to a set of DisplayAreas // (2) After adding a window, for every feature the window's type belongs to, // it is a descendant of one of the corresponding DisplayAreas of the feature. // (3) Z-order is maintained, i.e. if z-range(area) denotes the set of layers of windows // within a DisplayArea: // for every pair of DisplayArea siblings (a,b), where a is below b, it holds that // max(z-range(a)) <= min(z-range(b)) // // The algorithm below iteratively creates such a hierarchy: // - Initially, all windows are attached to the root. // - For each feature we create a set of DisplayAreas, by looping over the layers // - if the feature does apply to the current layer, we need to find a DisplayArea // for it to satisfy (2) // - we can re-use the previous layer's area if: // the current feature also applies to the previous layer, (to satisfy (3)) // and the last feature that applied to the previous layer is the same as // the last feature that applied to the current layer (to satisfy (2)) // - otherwise we create a new DisplayArea below the last feature that applied // to the current layer PendingArea[] areaForLayer = new PendingArea[mMaxWindowLayer]; final PendingArea root = new PendingArea(null, 0, null); Arrays.fill(areaForLayer, root); final int size = mFeatures.size(); for (int i = 0; i < size; i++) { PendingArea featureArea = null; for (int layer = 0; layer < mMaxWindowLayer; layer++) { final Feature feature = mFeatures.get(i); if (feature.mWindowLayers[layer]) { if (featureArea == null || featureArea.mParent != areaForLayer[layer]) { // No suitable DisplayArea - create a new one under the previous area // for this layer. featureArea = new PendingArea(feature, layer, areaForLayer[layer]); areaForLayer[layer].mChildren.add(featureArea); } areaForLayer[layer] = featureArea; } else { featureArea = null; } } } PendingArea leafArea = null; int leafType = LEAF_TYPE_TOKENS; for (int layer = 0; layer < mMaxWindowLayer; layer++) { int type = typeOfLayer(mWmService.mPolicy, layer); if (leafArea == null || leafArea.mParent != areaForLayer[layer] || type != leafType) { leafArea = new PendingArea(null, layer, areaForLayer[layer]); areaForLayer[layer].mChildren.add(leafArea); leafType = type; if (leafType == LEAF_TYPE_TASK_CONTAINERS) { leafArea.mExisting = mTaskContainers; } else if (leafType == LEAF_TYPE_IME_CONTAINERS) { leafArea.mExisting = mImeContainer; } } leafArea.mMaxLayer = layer; } root.computeMaxLayer(); root.instantiateChildren(mRoot, mAreaForLayer, 0, mAreas); } @Override public void addWindow(WindowToken token) { DisplayArea.Tokens area = findAreaForToken(token); area.addChild(token); } @VisibleForTesting DisplayArea.Tokens findAreaForToken(WindowToken token) { int windowLayerFromType = token.getWindowLayerFromType(); if (windowLayerFromType == APPLICATION_LAYER) { // TODO(display-area): Better handle AboveAppWindows in APPLICATION_LAYER windowLayerFromType += 1; } else if (token.mRoundedCornerOverlay) { windowLayerFromType = mMaxWindowLayer - 1; } return mAreaForLayer[windowLayerFromType]; } public List<DisplayArea<? extends WindowContainer>> getDisplayAreas(Feature feature) { return mAreas.get(feature); } private static int typeOfLayer(WindowManagerPolicy policy, int layer) { if (layer == APPLICATION_LAYER) { return LEAF_TYPE_TASK_CONTAINERS; } else if (layer == policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD) || layer == policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD_DIALOG)) { return LEAF_TYPE_IME_CONTAINERS; } else { return LEAF_TYPE_TOKENS; } } } DisplayAreaPolicyBuilder addFeature(Feature feature) { mFeatures.add(feature); return this; } Result build(WindowManagerService wmService, DisplayContent content, DisplayArea.Root root, DisplayArea<? extends WindowContainer> imeContainer, DisplayArea<? extends ActivityStack> taskContainers) { return new Result(wmService, content, root, imeContainer, taskContainers, new ArrayList<>( mFeatures)); } static class PendingArea { final int mMinLayer; final ArrayList<PendingArea> mChildren = new ArrayList<>(); final Feature mFeature; final PendingArea mParent; int mMaxLayer; DisplayArea mExisting; PendingArea(Feature feature, int minLayer, PendingArea parent) { mMinLayer = minLayer; mFeature = feature; mParent = parent; } int computeMaxLayer() { for (int i = 0; i < mChildren.size(); i++) { mMaxLayer = Math.max(mMaxLayer, mChildren.get(i).computeMaxLayer()); } return mMaxLayer; } void instantiateChildren(DisplayArea<DisplayArea> parent, DisplayArea.Tokens[] areaForLayer, int level, Map<Feature, List<DisplayArea<? extends WindowContainer>>> areas) { mChildren.sort(Comparator.comparingInt(pendingArea -> pendingArea.mMinLayer)); for (int i = 0; i < mChildren.size(); i++) { final PendingArea child = mChildren.get(i); final DisplayArea area = child.createArea(parent, areaForLayer); parent.addChild(area, WindowContainer.POSITION_TOP); if (mFeature != null) { areas.get(mFeature).add(area); } child.instantiateChildren(area, areaForLayer, level + 1, areas); } } private DisplayArea createArea(DisplayArea<DisplayArea> parent, DisplayArea.Tokens[] areaForLayer) { if (mExisting != null) { return mExisting; } DisplayArea.Type type; if (mMinLayer > APPLICATION_LAYER) { type = DisplayArea.Type.ABOVE_TASKS; } else if (mMaxLayer < APPLICATION_LAYER) { type = DisplayArea.Type.BELOW_TASKS; } else { type = DisplayArea.Type.ANY; } if (mFeature == null) { final DisplayArea.Tokens leaf = new DisplayArea.Tokens(parent.mWmService, type, "Leaf:" + mMinLayer + ":" + mMaxLayer); for (int i = mMinLayer; i <= mMaxLayer; i++) { areaForLayer[i] = leaf; } return leaf; } else { return new DisplayArea(parent.mWmService, type, mFeature.mName + ":" + mMinLayer + ":" + mMaxLayer); } } } } services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java 0 → 100644 +214 −0 File added.Preview size limit exceeded, changes collapsed. Show changes Loading
services/core/java/com/android/server/policy/WindowManagerPolicy.java +4 −0 Original line number Diff line number Diff line Loading @@ -866,6 +866,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { } } default int getMaxWindowLayer() { return 35; } /** * Return how to Z-order sub-windows in relation to the window they are attached to. * Return positive to have them ordered in front, negative for behind. Loading
services/core/java/com/android/server/wm/DisplayArea.java +5 −0 Original line number Diff line number Diff line Loading @@ -101,6 +101,11 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { return mName; } @Override public String toString() { return mName + "@" + System.identityHashCode(this); } @Override public final void dumpDebug(ProtoOutputStream proto, long fieldId, int logLevel) { final long token = proto.start(fieldId); Loading
services/core/java/com/android/server/wm/DisplayAreaPolicy.java +11 −64 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import android.content.res.Resources; import android.text.TextUtils; Loading @@ -43,7 +41,7 @@ public abstract class DisplayAreaPolicy { /** * The Tasks container. Tasks etc. are automatically added to this container. */ protected final TaskContainers mTaskContainers; protected final DisplayArea<? extends ActivityStack> mTaskContainers; /** * Construct a new {@link DisplayAreaPolicy} Loading @@ -58,7 +56,8 @@ public abstract class DisplayAreaPolicy { */ protected DisplayAreaPolicy(WindowManagerService wmService, DisplayContent content, DisplayArea.Root root, DisplayArea<? extends WindowContainer> imeContainer, TaskContainers taskContainers) { DisplayArea<? extends WindowContainer> imeContainer, DisplayArea<? extends ActivityStack> taskContainers) { mWmService = wmService; mContent = content; mRoot = root; Loading @@ -83,67 +82,15 @@ public abstract class DisplayAreaPolicy { */ public abstract void addWindow(WindowToken token); /** * Default policy that has no special features. */ public static class Default extends DisplayAreaPolicy { public Default(WindowManagerService wmService, DisplayContent content, DisplayArea.Root root, DisplayArea<? extends WindowContainer> imeContainer, TaskContainers taskContainers) { super(wmService, content, root, imeContainer, taskContainers); } private final DisplayArea.Tokens mBelow = new DisplayArea.Tokens(mWmService, DisplayArea.Type.BELOW_TASKS, "BelowTasks"); private final DisplayArea<DisplayArea> mAbove = new DisplayArea<>(mWmService, DisplayArea.Type.ABOVE_TASKS, "AboveTasks"); private final DisplayArea.Tokens mAboveBelowIme = new DisplayArea.Tokens(mWmService, DisplayArea.Type.ABOVE_TASKS, "AboveTasksBelowIme"); private final DisplayArea.Tokens mAboveAboveIme = new DisplayArea.Tokens(mWmService, DisplayArea.Type.ABOVE_TASKS, "AboveTasksAboveIme"); @Override public void attachDisplayAreas() { mRoot.addChild(mBelow, 0); mRoot.addChild(mTaskContainers, 1); mRoot.addChild(mAbove, 2); mAbove.addChild(mAboveBelowIme, 0); mAbove.addChild(mImeContainer, 1); mAbove.addChild(mAboveAboveIme, 2); } @Override public void addWindow(WindowToken token) { switch (DisplayArea.Type.typeOf(token)) { case ABOVE_TASKS: if (token.getWindowLayerFromType() < mWmService.mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD)) { mAboveBelowIme.addChild(token); } else { mAboveAboveIme.addChild(token); } break; case BELOW_TASKS: mBelow.addChild(token); break; default: throw new IllegalArgumentException("don't know how to sort " + token); } } /** Provider for {@link DisplayAreaPolicy.Default platform-default display area policy}. */ static class Provider implements DisplayAreaPolicy.Provider { /** Provider for platform-default display area policy. */ static final class DefaultProvider implements DisplayAreaPolicy.Provider { @Override public DisplayAreaPolicy instantiate(WindowManagerService wmService, DisplayContent content, DisplayArea.Root root, DisplayArea<? extends WindowContainer> imeContainer, TaskContainers taskContainers) { return new DisplayAreaPolicy.Default(wmService, content, root, imeContainer, taskContainers); } return new DisplayAreaPolicyBuilder() .build(wmService, content, root, imeContainer, taskContainers); } } Loading Loading @@ -172,7 +119,7 @@ public abstract class DisplayAreaPolicy { String name = res.getString( com.android.internal.R.string.config_deviceSpecificDisplayAreaPolicyProvider); if (TextUtils.isEmpty(name)) { return new DisplayAreaPolicy.Default.Provider(); return new DisplayAreaPolicy.DefaultProvider(); } try { return (Provider) Class.forName(name).newInstance(); Loading
services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java 0 → 100644 +371 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; 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 com.android.internal.annotations.VisibleForTesting; import com.android.server.policy.WindowManagerPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; /** * A builder for instantiating a complex {@link DisplayAreaPolicy} * * <p>Given a set of features (that each target a set of window types), it builds the necessary * DisplayArea hierarchy. * * <p>Example: <br /> * * <pre> * // Feature for targeting everything below the magnification overlay: * new DisplayAreaPolicyBuilder(...) * .addFeature(new Feature.Builder(..., "Magnification") * .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY) * .build()) * .build(...) * * // Builds a policy with the following hierarchy: * - DisplayArea.Root * - Magnification * - DisplayArea.Tokens (Wallpapers are attached here) * - TaskContainers * - DisplayArea.Tokens (windows above Tasks up to IME are attached here) * - ImeContainers * - DisplayArea.Tokens (windows above IME up to TYPE_ACCESSIBILITY_OVERLAY attached here) * - DisplayArea.Tokens (TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY and up are attached here) * * </pre> * * // TODO(display-area): document more complex scenarios where we need multiple areas per feature. */ class DisplayAreaPolicyBuilder { private final ArrayList<Feature> mFeatures = new ArrayList<>(); /** * A feature that requires {@link DisplayArea DisplayArea(s)}. */ static class Feature { private final String mName; private final boolean[] mWindowLayers; private Feature(String name, boolean[] windowLayers) { mName = name; mWindowLayers = windowLayers; } static class Builder { private final WindowManagerPolicy mPolicy; private final String mName; private final boolean[] mLayers; /** * Build a new feature that applies to a set of window types as specified by the builder * methods. * * <p>The set of types is updated iteratively in the order of the method invocations. * For example, {@code all().except(TYPE_STATUS_BAR)} expresses that a feature should * apply to all types except TYPE_STATUS_BAR. * * The builder starts out with the feature not applying to any types. * * @param name the name of the feature. */ Builder(WindowManagerPolicy policy, String name) { mPolicy = policy; mName = name; mLayers = new boolean[mPolicy.getMaxWindowLayer()]; } /** * Set that the feature applies to all window types. */ Builder all() { Arrays.fill(mLayers, true); return this; } /** * Set that the feature applies to the given window types. */ Builder and(int... types) { for (int i = 0; i < types.length; i++) { int type = types[i]; set(type, true); } return this; } /** * Set that the feature does not apply to the given window types. */ Builder except(int... types) { for (int i = 0; i < types.length; i++) { int type = types[i]; set(type, false); } return this; } /** * Set that the feature applies window types that are layerd at or below the layer of * the given window type. */ Builder upTo(int typeInclusive) { final int max = layerFromType(typeInclusive, false); for (int i = 0; i < max; i++) { mLayers[i] = true; } set(typeInclusive, true); return this; } Feature build() { return new Feature(mName, mLayers.clone()); } private void set(int type, boolean value) { mLayers[layerFromType(type, true)] = value; if (type == TYPE_APPLICATION_OVERLAY) { mLayers[layerFromType(type, true)] = value; mLayers[layerFromType(TYPE_SYSTEM_ALERT, false)] = value; mLayers[layerFromType(TYPE_SYSTEM_OVERLAY, false)] = value; mLayers[layerFromType(TYPE_SYSTEM_ERROR, false)] = value; } } private int layerFromType(int type, boolean internalWindows) { return mPolicy.getWindowLayerFromTypeLw(type, internalWindows); } } } static class Result extends DisplayAreaPolicy { private static final int LEAF_TYPE_TASK_CONTAINERS = 1; private static final int LEAF_TYPE_IME_CONTAINERS = 2; private static final int LEAF_TYPE_TOKENS = 0; private final int mMaxWindowLayer = mWmService.mPolicy.getMaxWindowLayer(); private final ArrayList<Feature> mFeatures; private final Map<Feature, List<DisplayArea<? extends WindowContainer>>> mAreas; private final DisplayArea.Tokens[] mAreaForLayer = new DisplayArea.Tokens[mMaxWindowLayer]; Result(WindowManagerService wmService, DisplayContent content, DisplayArea.Root root, DisplayArea<? extends WindowContainer> imeContainer, DisplayArea<? extends ActivityStack> taskStacks, ArrayList<Feature> features) { super(wmService, content, root, imeContainer, taskStacks); mFeatures = features; mAreas = new HashMap<>(features.size()); for (int i = 0; i < mFeatures.size(); i++) { mAreas.put(mFeatures.get(i), new ArrayList<>()); } } @Override public void attachDisplayAreas() { // This method constructs the layer hierarchy with the following properties: // (1) Every feature maps to a set of DisplayAreas // (2) After adding a window, for every feature the window's type belongs to, // it is a descendant of one of the corresponding DisplayAreas of the feature. // (3) Z-order is maintained, i.e. if z-range(area) denotes the set of layers of windows // within a DisplayArea: // for every pair of DisplayArea siblings (a,b), where a is below b, it holds that // max(z-range(a)) <= min(z-range(b)) // // The algorithm below iteratively creates such a hierarchy: // - Initially, all windows are attached to the root. // - For each feature we create a set of DisplayAreas, by looping over the layers // - if the feature does apply to the current layer, we need to find a DisplayArea // for it to satisfy (2) // - we can re-use the previous layer's area if: // the current feature also applies to the previous layer, (to satisfy (3)) // and the last feature that applied to the previous layer is the same as // the last feature that applied to the current layer (to satisfy (2)) // - otherwise we create a new DisplayArea below the last feature that applied // to the current layer PendingArea[] areaForLayer = new PendingArea[mMaxWindowLayer]; final PendingArea root = new PendingArea(null, 0, null); Arrays.fill(areaForLayer, root); final int size = mFeatures.size(); for (int i = 0; i < size; i++) { PendingArea featureArea = null; for (int layer = 0; layer < mMaxWindowLayer; layer++) { final Feature feature = mFeatures.get(i); if (feature.mWindowLayers[layer]) { if (featureArea == null || featureArea.mParent != areaForLayer[layer]) { // No suitable DisplayArea - create a new one under the previous area // for this layer. featureArea = new PendingArea(feature, layer, areaForLayer[layer]); areaForLayer[layer].mChildren.add(featureArea); } areaForLayer[layer] = featureArea; } else { featureArea = null; } } } PendingArea leafArea = null; int leafType = LEAF_TYPE_TOKENS; for (int layer = 0; layer < mMaxWindowLayer; layer++) { int type = typeOfLayer(mWmService.mPolicy, layer); if (leafArea == null || leafArea.mParent != areaForLayer[layer] || type != leafType) { leafArea = new PendingArea(null, layer, areaForLayer[layer]); areaForLayer[layer].mChildren.add(leafArea); leafType = type; if (leafType == LEAF_TYPE_TASK_CONTAINERS) { leafArea.mExisting = mTaskContainers; } else if (leafType == LEAF_TYPE_IME_CONTAINERS) { leafArea.mExisting = mImeContainer; } } leafArea.mMaxLayer = layer; } root.computeMaxLayer(); root.instantiateChildren(mRoot, mAreaForLayer, 0, mAreas); } @Override public void addWindow(WindowToken token) { DisplayArea.Tokens area = findAreaForToken(token); area.addChild(token); } @VisibleForTesting DisplayArea.Tokens findAreaForToken(WindowToken token) { int windowLayerFromType = token.getWindowLayerFromType(); if (windowLayerFromType == APPLICATION_LAYER) { // TODO(display-area): Better handle AboveAppWindows in APPLICATION_LAYER windowLayerFromType += 1; } else if (token.mRoundedCornerOverlay) { windowLayerFromType = mMaxWindowLayer - 1; } return mAreaForLayer[windowLayerFromType]; } public List<DisplayArea<? extends WindowContainer>> getDisplayAreas(Feature feature) { return mAreas.get(feature); } private static int typeOfLayer(WindowManagerPolicy policy, int layer) { if (layer == APPLICATION_LAYER) { return LEAF_TYPE_TASK_CONTAINERS; } else if (layer == policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD) || layer == policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD_DIALOG)) { return LEAF_TYPE_IME_CONTAINERS; } else { return LEAF_TYPE_TOKENS; } } } DisplayAreaPolicyBuilder addFeature(Feature feature) { mFeatures.add(feature); return this; } Result build(WindowManagerService wmService, DisplayContent content, DisplayArea.Root root, DisplayArea<? extends WindowContainer> imeContainer, DisplayArea<? extends ActivityStack> taskContainers) { return new Result(wmService, content, root, imeContainer, taskContainers, new ArrayList<>( mFeatures)); } static class PendingArea { final int mMinLayer; final ArrayList<PendingArea> mChildren = new ArrayList<>(); final Feature mFeature; final PendingArea mParent; int mMaxLayer; DisplayArea mExisting; PendingArea(Feature feature, int minLayer, PendingArea parent) { mMinLayer = minLayer; mFeature = feature; mParent = parent; } int computeMaxLayer() { for (int i = 0; i < mChildren.size(); i++) { mMaxLayer = Math.max(mMaxLayer, mChildren.get(i).computeMaxLayer()); } return mMaxLayer; } void instantiateChildren(DisplayArea<DisplayArea> parent, DisplayArea.Tokens[] areaForLayer, int level, Map<Feature, List<DisplayArea<? extends WindowContainer>>> areas) { mChildren.sort(Comparator.comparingInt(pendingArea -> pendingArea.mMinLayer)); for (int i = 0; i < mChildren.size(); i++) { final PendingArea child = mChildren.get(i); final DisplayArea area = child.createArea(parent, areaForLayer); parent.addChild(area, WindowContainer.POSITION_TOP); if (mFeature != null) { areas.get(mFeature).add(area); } child.instantiateChildren(area, areaForLayer, level + 1, areas); } } private DisplayArea createArea(DisplayArea<DisplayArea> parent, DisplayArea.Tokens[] areaForLayer) { if (mExisting != null) { return mExisting; } DisplayArea.Type type; if (mMinLayer > APPLICATION_LAYER) { type = DisplayArea.Type.ABOVE_TASKS; } else if (mMaxLayer < APPLICATION_LAYER) { type = DisplayArea.Type.BELOW_TASKS; } else { type = DisplayArea.Type.ANY; } if (mFeature == null) { final DisplayArea.Tokens leaf = new DisplayArea.Tokens(parent.mWmService, type, "Leaf:" + mMinLayer + ":" + mMaxLayer); for (int i = mMinLayer; i <= mMaxLayer; i++) { areaForLayer[i] = leaf; } return leaf; } else { return new DisplayArea(parent.mWmService, type, mFeature.mName + ":" + mMinLayer + ":" + mMaxLayer); } } } }
services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java 0 → 100644 +214 −0 File added.Preview size limit exceeded, changes collapsed. Show changes