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

Commit a85b3f18 authored by Evan Rosky's avatar Evan Rosky Committed by Android (Google) Code Review
Browse files

Merge "Add hierarchy operations to container transaction"

parents 7f659825 a8fde159
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -51,6 +51,9 @@ interface ITaskOrganizerController {
    /** Deletes a persistent root task in WM */
    boolean deleteRootTask(IWindowContainer task);

    /** Gets direct child tasks (ordered from top-to-bottom) */
    List<ActivityManager.RunningTaskInfo> getChildTasks(in IWindowContainer parent);

    /** Get the root task which contains the current ime target */
    IWindowContainer getImeTarget(int display);

+122 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.view;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -25,6 +27,8 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArrayMap;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
@@ -36,10 +40,14 @@ import java.util.Map;
public class WindowContainerTransaction implements Parcelable {
    private final ArrayMap<IBinder, Change> mChanges = new ArrayMap<>();

    // Flat list because re-order operations are order-dependent
    private final ArrayList<HierarchyOp> mHierarchyOps = new ArrayList<>();

    public WindowContainerTransaction() {}

    protected WindowContainerTransaction(Parcel in) {
        in.readMap(mChanges, null /* loader */);
        in.readList(mHierarchyOps, null /* loader */);
    }

    private Change getOrCreateChange(IBinder token) {
@@ -97,10 +105,39 @@ public class WindowContainerTransaction implements Parcelable {
        return this;
    }

    /**
     * Reparents a container into another one. The effect of a {@code null} parent can vary. For
     * example, reparenting a stack to {@code null} will reparent it to its display.
     *
     * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
     *              the bottom.
     */
    public WindowContainerTransaction reparent(@NonNull IWindowContainer child,
            @Nullable IWindowContainer parent, boolean onTop) {
        mHierarchyOps.add(new HierarchyOp(child.asBinder(),
                parent == null ? null : parent.asBinder(), onTop));
        return this;
    }

    /**
     * Reorders a container within its parent.
     *
     * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
     *              the bottom.
     */
    public WindowContainerTransaction reorder(@NonNull IWindowContainer child, boolean onTop) {
        mHierarchyOps.add(new HierarchyOp(child.asBinder(), onTop));
        return this;
    }

    public Map<IBinder, Change> getChanges() {
        return mChanges;
    }

    public List<HierarchyOp> getHierarchyOps() {
        return mHierarchyOps;
    }

    @Override
    public String toString() {
        return "WindowContainerTransaction { changes = " + mChanges + " }";
@@ -109,6 +146,7 @@ public class WindowContainerTransaction implements Parcelable {
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeMap(mChanges);
        dest.writeList(mHierarchyOps);
    }

    @Override
@@ -249,4 +287,88 @@ public class WindowContainerTransaction implements Parcelable {
            }
        };
    }

    /**
     * Holds information about a reparent/reorder operation in the hierarchy. This is separate from
     * Changes because they must be executed in the same order that they are added.
     */
    public static class HierarchyOp implements Parcelable {
        private final IBinder mContainer;

        // If this is same as mContainer, then only change position, don't reparent.
        private final IBinder mReparent;

        // Moves/reparents to top of parent when {@code true}, otherwise moves/reparents to bottom.
        private final boolean mToTop;

        public HierarchyOp(@NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {
            mContainer = container;
            mReparent = reparent;
            mToTop = toTop;
        }

        public HierarchyOp(@NonNull IBinder container, boolean toTop) {
            mContainer = container;
            mReparent = container;
            mToTop = toTop;
        }

        protected HierarchyOp(Parcel in) {
            mContainer = in.readStrongBinder();
            mReparent = in.readStrongBinder();
            mToTop = in.readBoolean();
        }

        public boolean isReparent() {
            return mContainer != mReparent;
        }

        @Nullable
        public IBinder getNewParent() {
            return mReparent;
        }

        @NonNull
        public IBinder getContainer() {
            return mContainer;
        }

        public boolean getToTop() {
            return mToTop;
        }

        @Override
        public String toString() {
            if (isReparent()) {
                return "{reparent: " + mContainer + " to " + (mToTop ? "top of " : "bottom of ")
                        + mReparent + "}";
            } else {
                return "{reorder: " + mContainer + " to " + (mToTop ? "top" : "bottom") + "}";
            }
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeStrongBinder(mContainer);
            dest.writeStrongBinder(mReparent);
            dest.writeBoolean(mToTop);
        }

        @Override
        public int describeContents() {
            return 0;
        }

        public static final Creator<HierarchyOp> CREATOR = new Creator<HierarchyOp>() {
            @Override
            public HierarchyOp createFromParcel(Parcel in) {
                return new HierarchyOp(in);
            }

            @Override
            public HierarchyOp[] newArray(int size) {
                return new HierarchyOp[size];
            }
        };
    }
}
+5 −7
Original line number Diff line number Diff line
@@ -79,11 +79,6 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS
import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK;
import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.server.wm.TaskProto.DISPLAYED_BOUNDS;
import static com.android.server.wm.TaskProto.FILLS_PARENT;
import static com.android.server.wm.TaskProto.SURFACE_HEIGHT;
import static com.android.server.wm.TaskProto.SURFACE_WIDTH;
import static com.android.server.wm.TaskProto.WINDOW_CONTAINER;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
@@ -125,7 +120,6 @@ import android.provider.Settings;
import android.service.voice.IVoiceInteractionSession;
import android.util.DisplayMetrics;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
import android.view.ITaskOrganizer;
import android.view.RemoteAnimationTarget;
@@ -3195,12 +3189,16 @@ class Task extends WindowContainer<WindowContainer> {
        info.lastActiveTime = lastActiveTime;
        info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
        info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
        info.resizeMode = mResizeMode;
        info.configuration.setTo(getConfiguration());
        info.token = mRemoteToken;
        // Get's the first non-undefined activity type among this and children. Can't use
        // configuration.windowConfiguration because that would only be this level.
        info.topActivityType = getActivityType();

        //TODO (AM refactor): Just use local once updateEffectiveIntent is run during all child
        //                    order changes.
        final Task top = getTopMostTask();
        info.resizeMode = top != null ? top.mResizeMode : mResizeMode;
    }

    /**
+98 −2
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;

import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;

import android.annotation.Nullable;
import android.app.ActivityManager.RunningTaskInfo;
@@ -47,6 +49,7 @@ import com.android.internal.util.function.pooled.PooledLambda;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

@@ -375,6 +378,45 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub
        }
    }

    @Override
    public List<RunningTaskInfo> getChildTasks(IWindowContainer parent) {
        enforceStackPermission("getChildTasks()");
        final long ident = Binder.clearCallingIdentity();
        try {
            synchronized (mGlobalLock) {
                if (parent == null) {
                    throw new IllegalArgumentException("Can't get children of null parent");
                }
                final WindowContainer container = WindowContainer.fromBinder(parent.asBinder());
                if (container == null) {
                    Slog.e(TAG, "Can't get children of " + parent + " because it is not valid.");
                    return null;
                }
                // For now, only support returning children of persistent root tasks (of which the
                // only current implementation is TaskTile).
                if (!(container instanceof TaskTile)) {
                    Slog.w(TAG, "Can only get children of root tasks created via createRootTask");
                    return null;
                }
                ArrayList<RunningTaskInfo> out = new ArrayList<>();
                // Tiles aren't real parents, so we need to go through stacks on the display to
                // ensure correct ordering.
                final DisplayContent dc = container.getDisplayContent();
                for (int i = dc.getStackCount() - 1; i >= 0; --i) {
                    final ActivityStack as = dc.getStackAt(i);
                    if (as.getTile() == container) {
                        final RunningTaskInfo info = new RunningTaskInfo();
                        as.fillTaskInfo(info);
                        out.add(info);
                    }
                }
                return out;
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

    private int sanitizeAndApplyChange(WindowContainer container,
            WindowContainerTransaction.Change change) {
        if (!(container instanceof Task)) {
@@ -405,6 +447,54 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub
        return effects;
    }

    private int sanitizeAndApplyHierarchyOp(WindowContainer container,
            WindowContainerTransaction.HierarchyOp hop) {
        if (!(container instanceof Task)) {
            throw new IllegalArgumentException("Invalid container in hierarchy op");
        }
        if (hop.isReparent()) {
            // special case for tiles since they are "virtual" parents
            if (container instanceof ActivityStack && ((ActivityStack) container).isRootTask()) {
                ActivityStack as = (ActivityStack) container;
                TaskTile newParent = hop.getNewParent() == null ? null
                        : (TaskTile) WindowContainer.fromBinder(hop.getNewParent());
                if (as.getTile() != newParent) {
                    if (as.getTile() != null) {
                        as.getTile().removeChild(as);
                    }
                    if (newParent != null) {
                        if (!as.affectedBySplitScreenResize()) {
                            return 0;
                        }
                        newParent.addChild(as, POSITION_TOP);
                    }
                }
                if (hop.getToTop()) {
                    as.getDisplay().positionStackAtTop(as, false /* includingParents */);
                } else {
                    as.getDisplay().positionStackAtBottom(as);
                }
            } else if (container instanceof Task) {
                throw new RuntimeException("Reparenting leaf Tasks is not supported now.");
            }
        } else {
            // Ugh, of course ActivityStack has its own special reorder logic...
            if (container instanceof ActivityStack && ((ActivityStack) container).isRootTask()) {
                ActivityStack as = (ActivityStack) container;
                if (hop.getToTop()) {
                    as.getDisplay().positionStackAtTop(as, false /* includingParents */);
                } else {
                    as.getDisplay().positionStackAtBottom(as);
                }
            } else {
                container.getParent().positionChildAt(
                        hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM,
                        container, false /* includingParents */);
            }
        }
        return TRANSACT_EFFECTS_LIFECYCLE;
    }

    private void resizePinnedStackIfNeeded(ConfigurationContainer container, int configMask,
            int windowMask, Configuration config) {
        if ((container instanceof ActivityStack)
@@ -470,8 +560,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub
                    while (entries.hasNext()) {
                        final Map.Entry<IBinder, WindowContainerTransaction.Change> entry =
                                entries.next();
                        final WindowContainer wc = WindowContainer.RemoteToken.fromBinder(
                                entry.getKey()).getContainer();
                        final WindowContainer wc = WindowContainer.fromBinder(entry.getKey());
                        int containerEffect = applyWindowContainerChange(wc, entry.getValue());
                        effects |= containerEffect;

@@ -484,6 +573,13 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub
                            mBLASTSyncEngine.addToSyncSet(syncId, wc);
                        }
                    }
                    // Hierarchy changes
                    final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
                    for (int i = 0, n = hops.size(); i < n; ++i) {
                        final WindowContainerTransaction.HierarchyOp hop = hops.get(i);
                        final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
                        effects |= sanitizeAndApplyHierarchyOp(wc, hop);
                    }
                    if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) {
                        // Already calls ensureActivityConfig
                        mService.mRootWindowContainer.ensureActivitiesVisible(
+4 −0
Original line number Diff line number Diff line
@@ -2296,6 +2296,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
        return mRemoteToken;
    }

    static WindowContainer fromBinder(IBinder binder) {
        return RemoteToken.fromBinder(binder).getContainer();
    }

    static class RemoteToken extends IWindowContainer.Stub {
        final WeakReference<WindowContainer> mWeakRef;

Loading