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

Commit a7050d47 authored by Adrian Roos's avatar Adrian Roos Committed by Android (Google) Code Review
Browse files

Merge "WM: Introduce DisplayArea (3/n)"

parents b66d2263 22a20a81
Loading
Loading
Loading
Loading
+28 −3
Original line number Diff line number Diff line
@@ -150,9 +150,9 @@ message DisplayContentProto {
    // Will be removed soon.
    optional PinnedStackControllerProto pinned_stack_controller = 5 [deprecated=true];
    /* non app windows */
    repeated WindowTokenProto above_app_windows = 6;
    repeated WindowTokenProto below_app_windows = 7;
    repeated WindowTokenProto ime_windows = 8;
    repeated WindowTokenProto above_app_windows = 6 [deprecated=true];
    repeated WindowTokenProto below_app_windows = 7 [deprecated=true];
    repeated WindowTokenProto ime_windows = 8 [deprecated=true];
    optional int32 dpi = 9;
    optional .android.view.DisplayInfoProto display_info = 10;
    optional int32 rotation = 11;
@@ -165,8 +165,33 @@ message DisplayContentProto {
    repeated IdentifierProto closing_apps = 18;
    repeated IdentifierProto changing_apps = 19;
    repeated WindowTokenProto overlay_windows = 20;
    optional DisplayAreaProto root_display_area = 21;
}

/* represents DisplayArea object */
message DisplayAreaProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    optional WindowContainerProto window_container = 1;
    optional string name = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
    repeated DisplayAreaChildProto children = 3;
}

/* represents a generic child of a DisplayArea */
message DisplayAreaChildProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    /* At most one of the following should be present: */

    /* represents a DisplayArea child */
    optional DisplayAreaProto display_area = 1;
    /* represents a WindowToken child */
    optional WindowTokenProto window = 2;
    /* represents an unknown child - the class name is recorded */
    repeated string unknown = 3;
}


/* represents DisplayFrames */
message DisplayFramesProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+12 −6
Original line number Diff line number Diff line
@@ -1573,12 +1573,6 @@
      "group": "WM_ERROR",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "1004585481": {
      "message": "%s forcing orientation to %d for display id=%d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_ORIENTATION",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "1051545910": {
      "message": "Exit animation finished in %s: remove=%b",
      "level": "VERBOSE",
@@ -1717,6 +1711,12 @@
      "group": "WM_DEBUG_IME",
      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
    },
    "1389009035": {
      "message": "NonAppWindowContainer cannot set orientation: %s",
      "level": "WARN",
      "group": "WM_DEBUG_ORIENTATION",
      "at": "com\/android\/server\/wm\/DisplayContent.java"
    },
    "1401700824": {
      "message": "Window drawn win=%s",
      "level": "DEBUG",
@@ -1891,6 +1891,12 @@
      "group": "WM_DEBUG_STARTING_WINDOW",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "1674747211": {
      "message": "%s forcing orientation to %d for display id=%d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_ORIENTATION",
      "at": "com\/android\/server\/wm\/DisplayArea.java"
    },
    "1677260366": {
      "message": "Finish starting %s: first real window is shown, no animation",
      "level": "VERBOSE",
+265 −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.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;

import static com.android.internal.util.Preconditions.checkState;
import static com.android.server.wm.DisplayAreaChildProto.DISPLAY_AREA;
import static com.android.server.wm.DisplayAreaChildProto.UNKNOWN;
import static com.android.server.wm.DisplayAreaChildProto.WINDOW;
import static com.android.server.wm.DisplayAreaProto.CHILDREN;
import static com.android.server.wm.DisplayAreaProto.NAME;
import static com.android.server.wm.DisplayAreaProto.WINDOW_CONTAINER;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;

import android.graphics.Rect;
import android.util.proto.ProtoOutputStream;

import com.android.server.policy.WindowManagerPolicy;
import com.android.server.protolog.common.ProtoLog;

import java.util.Comparator;
import java.util.function.Predicate;

/**
 * Container for grouping WindowContainer below DisplayContent.
 *
 * DisplayAreas are managed by a {@link DisplayAreaPolicy}, and can override configurations and
 * can be leashed.
 *
 * DisplayAreas can contain nested DisplayAreas.
 *
 * DisplayAreas come in three flavors, to ensure that windows have the right Z-Order:
 * - BELOW_TASKS: Can only contain BELOW_TASK DisplayAreas and WindowTokens that go below tasks.
 * - ABOVE_TASKS: Can only contain ABOVE_TASK DisplayAreas and WindowTokens that go above tasks.
 * - ANY: Can contain any kind of DisplayArea, and any kind of WindowToken or the Task container.
 *        Cannot have a sibling that is of type ANY.
 *
 * @param <T> type of the children of the DisplayArea.
 */
public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {

    protected final Type mType;
    private final String mName;

    DisplayArea(WindowManagerService wms, Type type, String name) {
        super(wms);
        // TODO(display-area): move this up to ConfigurationContainer
        mOrientation = SCREEN_ORIENTATION_UNSET;
        mType = type;
        mName = name;
    }

    @Override
    void onChildPositionChanged(WindowContainer child) {
        super.onChildPositionChanged(child);

        // Verify that we have proper ordering
        Type.checkChild(mType, Type.typeOf(child));

        if (child instanceof ActivityStack) {
            // TODO(display-area): ActivityStacks are type ANY, but are allowed to have siblings.
            //                     They might need a separate type.
            return;
        }

        for (int i = 1; i < getChildCount(); i++) {
            final WindowContainer top = getChildAt(i - 1);
            final WindowContainer bottom = getChildAt(i);
            if (child == top || child == bottom) {
                Type.checkSiblings(Type.typeOf(top), Type.typeOf(bottom));
            }
        }
    }

    @Override
    boolean fillsParent() {
        return true;
    }

    @Override
    String getName() {
        return mName;
    }

    @Override
    public final void dumpDebug(ProtoOutputStream proto, long fieldId, int logLevel) {
        final long token = proto.start(fieldId);
        super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
        proto.write(NAME, mName);
        for (int i = 0; i < getChildCount(); i++) {
            final long childToken = proto.start(CHILDREN);
            final T child = getChildAt(i);
            if (child instanceof ActivityStack) {
                // TODO(display-area): Dump stacks & tasks here, instead of in DisplayContent's
                //  dumpDebug. For now, skip them here to avoid dumping them as UNKNOWN.
            } else if (child instanceof WindowToken) {
                ((WindowToken) child).dumpDebug(proto, WINDOW, logLevel);
            } else if (child instanceof DisplayArea) {
                child.dumpDebug(proto, DISPLAY_AREA, logLevel);
            } else {
                proto.write(UNKNOWN, child.getClass().getSimpleName());
            }
            proto.end(childToken);
        }
        proto.end(token);
    }

    /**
     * DisplayArea that contains WindowTokens, and orders them according to their type.
     */
    public static class Tokens extends DisplayArea<WindowToken> {
        int mLastKeyguardForcedOrientation = SCREEN_ORIENTATION_UNSPECIFIED;

        private final Comparator<WindowToken> mWindowComparator =
                Comparator.comparingInt(WindowToken::getWindowLayerFromType);

        private final Predicate<WindowState> mGetOrientingWindow = w -> {
            final WindowManagerPolicy policy = mWmService.mPolicy;
            if (policy.isKeyguardHostWindow(w.mAttrs)) {
                if (mWmService.mKeyguardGoingAway) {
                    return false;
                }
                // Consider unoccluding only when all unknown visibilities have been
                // resolved, as otherwise we just may be starting another occluding activity.
                final boolean isUnoccluding =
                        mDisplayContent.mAppTransition.getAppTransition()
                                == TRANSIT_KEYGUARD_UNOCCLUDE
                                && mDisplayContent.mUnknownAppVisibilityController.allResolved();
                // If keyguard is showing, or we're unoccluding, force the keyguard's orientation,
                // even if SystemUI hasn't updated the attrs yet.
                if (policy.isKeyguardShowingAndNotOccluded() || isUnoccluding) {
                    return true;
                }
            }
            final int req = w.mAttrs.screenOrientation;
            if (req == SCREEN_ORIENTATION_UNSPECIFIED || req == SCREEN_ORIENTATION_BEHIND
                    || req == SCREEN_ORIENTATION_UNSET) {
                return false;
            }
            return true;
        };

        Tokens(WindowManagerService wms, Type type, String name) {
            super(wms, type, name);
        }

        void addChild(WindowToken token) {
            addChild(token, mWindowComparator);
        }

        @Override
        int getOrientation(int candidate) {
            // Find a window requesting orientation.
            final WindowState win = getWindow(mGetOrientingWindow);

            if (win == null) {
                return candidate;
            }
            int req = win.mAttrs.screenOrientation;
            ProtoLog.v(WM_DEBUG_ORIENTATION, "%s forcing orientation to %d for display id=%d",
                    win, req, mDisplayContent.getDisplayId());
            if (mWmService.mPolicy.isKeyguardHostWindow(win.mAttrs)) {
                // SystemUI controls the Keyguard orientation asynchronously, and mAttrs may be
                // stale. We record / use the last known override.
                if (req != SCREEN_ORIENTATION_UNSET && req != SCREEN_ORIENTATION_UNSPECIFIED) {
                    mLastKeyguardForcedOrientation = req;
                } else {
                    req = mLastKeyguardForcedOrientation;
                }
            }
            return req;
        }
    }

    /**
     * Top-most DisplayArea under DisplayContent.
     */
    public static class Root extends DisplayArea<DisplayArea> {
        private final Dimmer mDimmer = new Dimmer(this);
        private final Rect mTmpDimBoundsRect = new Rect();

        Root(WindowManagerService wms) {
            super(wms, Type.ANY, "DisplayArea.Root");
        }

        @Override
        Dimmer getDimmer() {
            return mDimmer;
        }

        @Override
        void prepareSurfaces() {
            mDimmer.resetDimStates();
            super.prepareSurfaces();
            getBounds(mTmpDimBoundsRect);

            if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) {
                scheduleAnimation();
            }
        }
    }

    enum Type {
        /** Can only contain WindowTokens above the APPLICATION_LAYER. */
        ABOVE_TASKS,
        /** Can only contain WindowTokens below the APPLICATION_LAYER. */
        BELOW_TASKS,
        /** Can contain anything. */
        ANY;

        static void checkSiblings(Type bottom, Type top) {
            checkState(!(bottom == ANY && top == ANY), "ANY cannot be a sibling of ANY");
            checkState(!(bottom != BELOW_TASKS && top == BELOW_TASKS),
                    bottom + " must be above BELOW_TASKS");
            checkState(!(bottom == ABOVE_TASKS && top != ABOVE_TASKS),
                    top + " must be below ABOVE_TASKS");
        }

        static void checkChild(Type parent, Type child) {
            switch (parent) {
                case ABOVE_TASKS:
                    checkState(child == ABOVE_TASKS, "ABOVE_TASKS can only contain ABOVE_TASKS");
                    break;
                case BELOW_TASKS:
                    checkState(child == BELOW_TASKS, "BELOW_TASKS can only contain BELOW_TASKS");
                    break;
            }
        }

        static Type typeOf(WindowContainer c) {
            if (c instanceof DisplayArea) {
                return ((DisplayArea) c).mType;
            } else if (c instanceof WindowToken && !(c instanceof ActivityRecord)) {
                return typeOf((WindowToken) c);
            } else if (c instanceof ActivityStack) {
                return ANY;
            } else {
                throw new IllegalArgumentException("Unknown container: " + c);
            }
        }

        private static Type typeOf(WindowToken c) {
            return c.getWindowLayerFromType() < APPLICATION_LAYER ? BELOW_TASKS : ABOVE_TASKS;
        }
    }
}
+123 −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_INPUT_METHOD;

import com.android.server.wm.DisplayContent.TaskContainers;

/**
 * Policy that manages DisplayAreas.
 */
public abstract class DisplayAreaPolicy {
    protected final WindowManagerService mWmService;
    protected final DisplayContent mContent;

    /**
     * The root DisplayArea. Attach all DisplayAreas to this area (directly or indirectly).
     */
    protected final DisplayArea.Root mRoot;

    /**
     * The IME container. The IME's windows are automatically added to this container.
     */
    protected final DisplayArea<? extends WindowContainer> mImeContainer;

    /**
     * The Tasks container. Tasks etc. are automatically added to this container.
     */
    protected final TaskContainers mTaskContainers;

    DisplayAreaPolicy(WindowManagerService wmService,
            DisplayContent content, DisplayArea.Root root,
            DisplayArea<? extends WindowContainer> imeContainer, TaskContainers taskContainers) {
        mWmService = wmService;
        mContent = content;
        mRoot = root;
        mImeContainer = imeContainer;
        mTaskContainers = taskContainers;
    }

    /**
     * Called to ask the policy to set up the DisplayArea hierarchy. At a minimum this must:
     *
     * - attach mImeContainer to mRoot (or one of its descendants)
     * - attach mTaskStacks to mRoot (or one of its descendants)
     *
     * Additionally, this is the right place to set up any other DisplayAreas as desired.
     */
    public abstract void attachDisplayAreas();

    /**
     * Called to ask the policy to attach the given WindowToken to the DisplayArea hierarchy.
     *
     * This must attach the token to mRoot (or one of its descendants).
     */
    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);
            }
        }
    }
}
+26 −137

File changed.

Preview size limit exceeded, changes collapsed.

Loading