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

Commit 250d6533 authored by Andrii Kulian's avatar Andrii Kulian
Browse files

Allow destroying display content on removal

This CL sets the behavior for displays when they are removed.
For public displays by default all content will be moved to the
primary display and become focused. For private displays default
behavior is to destroy all content - first it moves stacks from
the secondary display to the primary display to the bottom, then
it destroys all activities in those stacks.

This CL adds two specified behaviors as modes, so in future these
rules might be altered if needed.

Bug: 34263289
Test: android.server.cts.ActivityManagerDisplayTests
Test: #testContentDestroyOnDisplayRemoved
Change-Id: I3f89f06ff82cb4b487df58a86ba3b146a32cbd00
parent f2ca8e03
Loading
Loading
Loading
Loading
+29 −0
Original line number Original line Diff line number Diff line
@@ -338,6 +338,21 @@ public final class Display {
    /** @hide */
    /** @hide */
    public static final int COLOR_MODE_DISPLAY_P3 = 9;
    public static final int COLOR_MODE_DISPLAY_P3 = 9;


    /**
     * Indicates that when display is removed, all its activities will be moved to the primary
     * display and the topmost activity should become focused.
     *
     * @hide
     */
    public static final int REMOVE_MODE_MOVE_CONTENT_TO_PRIMARY = 0;
    /**
     * Indicates that when display is removed, all its stacks and tasks will be removed, all
     * activities will be destroyed according to the usual lifecycle.
     *
     * @hide
     */
    public static final int REMOVE_MODE_DESTROY_CONTENT = 1;

    /**
    /**
     * Internal method to create a display.
     * Internal method to create a display.
     * Applications should use {@link android.view.WindowManager#getDefaultDisplay()}
     * Applications should use {@link android.view.WindowManager#getDefaultDisplay()}
@@ -769,6 +784,20 @@ public final class Display {
        }
        }
    }
    }


    /**
     * @hide
     * Get current remove mode of the display - what actions should be performed with the display's
     * content when it is removed. Default behavior for public displays in this case is to move all
     * activities to the primary display and make it focused. For private display - destroy all
     * activities.
     *
     * @see #REMOVE_MODE_MOVE_CONTENT_TO_PRIMARY
     * @see #REMOVE_MODE_DESTROY_CONTENT
     */
    public int getRemoveMode() {
        return mDisplayInfo.removeMode;
    }

    /**
    /**
     * Returns the display's HDR capabilities.
     * Returns the display's HDR capabilities.
     *
     *
+16 −1
Original line number Original line Diff line number Diff line
@@ -238,6 +238,15 @@ public final class DisplayInfo implements Parcelable {
     */
     */
    public String ownerPackageName;
    public String ownerPackageName;


    /**
     * @hide
     * Get current remove mode of the display - what actions should be performed with the display's
     * content when it is removed.
     *
     * @see Display#getRemoveMode()
     */
    public int removeMode = Display.REMOVE_MODE_MOVE_CONTENT_TO_PRIMARY;

    public static final Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
    public static final Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
        @Override
        @Override
        public DisplayInfo createFromParcel(Parcel source) {
        public DisplayInfo createFromParcel(Parcel source) {
@@ -298,7 +307,8 @@ public final class DisplayInfo implements Parcelable {
                && presentationDeadlineNanos == other.presentationDeadlineNanos
                && presentationDeadlineNanos == other.presentationDeadlineNanos
                && state == other.state
                && state == other.state
                && ownerUid == other.ownerUid
                && ownerUid == other.ownerUid
                && Objects.equal(ownerPackageName, other.ownerPackageName);
                && Objects.equal(ownerPackageName, other.ownerPackageName)
                && removeMode == other.removeMode;
    }
    }


    @Override
    @Override
@@ -341,6 +351,7 @@ public final class DisplayInfo implements Parcelable {
        state = other.state;
        state = other.state;
        ownerUid = other.ownerUid;
        ownerUid = other.ownerUid;
        ownerPackageName = other.ownerPackageName;
        ownerPackageName = other.ownerPackageName;
        removeMode = other.removeMode;
    }
    }


    public void readFromParcel(Parcel source) {
    public void readFromParcel(Parcel source) {
@@ -385,6 +396,7 @@ public final class DisplayInfo implements Parcelable {
        ownerUid = source.readInt();
        ownerUid = source.readInt();
        ownerPackageName = source.readString();
        ownerPackageName = source.readString();
        uniqueId = source.readString();
        uniqueId = source.readString();
        removeMode = source.readInt();
    }
    }


    @Override
    @Override
@@ -428,6 +440,7 @@ public final class DisplayInfo implements Parcelable {
        dest.writeInt(ownerUid);
        dest.writeInt(ownerUid);
        dest.writeString(ownerPackageName);
        dest.writeString(ownerPackageName);
        dest.writeString(uniqueId);
        dest.writeString(uniqueId);
        dest.writeInt(removeMode);
    }
    }


    @Override
    @Override
@@ -637,6 +650,8 @@ public final class DisplayInfo implements Parcelable {
            sb.append(" (uid ").append(ownerUid).append(")");
            sb.append(" (uid ").append(ownerUid).append(")");
        }
        }
        sb.append(flagsToString(flags));
        sb.append(flagsToString(flags));
        sb.append(", removeMode ");
        sb.append(removeMode);
        sb.append("}");
        sb.append("}");
        return sb.toString();
        return sb.toString();
    }
    }
+1 −1
Original line number Original line Diff line number Diff line
@@ -9878,7 +9878,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            try {
            try {
                if (DEBUG_STACK) Slog.d(TAG_STACK, "moveStackToDisplay: moving stackId=" + stackId
                if (DEBUG_STACK) Slog.d(TAG_STACK, "moveStackToDisplay: moving stackId=" + stackId
                        + " to displayId=" + displayId);
                        + " to displayId=" + displayId);
                mStackSupervisor.moveStackToDisplayLocked(stackId, displayId);
                mStackSupervisor.moveStackToDisplayLocked(stackId, displayId, ON_TOP);
            } finally {
            } finally {
                Binder.restoreCallingIdentity(ident);
                Binder.restoreCallingIdentity(ident);
            }
            }
+15 −2
Original line number Original line Diff line number Diff line
@@ -477,6 +477,8 @@ final class ActivityStack extends ConfigurationContainer implements StackWindowL
        mTmpRect2.setEmpty();
        mTmpRect2.setEmpty();
        mWindowContainerController.reparent(activityDisplay.mDisplayId, mTmpRect2);
        mWindowContainerController.reparent(activityDisplay.mDisplayId, mTmpRect2);
        postAddToDisplay(activityDisplay, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop);
        postAddToDisplay(activityDisplay, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop);
        adjustFocusToNextFocusableStackLocked("reparent", true /* allowFocusSelf */);
        mStackSupervisor.resumeFocusedStackTopActivityLocked();
    }
    }


    /**
    /**
@@ -3235,8 +3237,18 @@ final class ActivityStack extends ConfigurationContainer implements StackWindowL
                mStackSupervisor.topRunningActivityLocked(), myReason);
                mStackSupervisor.topRunningActivityLocked(), myReason);
    }
    }


    /** Find next proper focusable stack and make it focused. */
    private boolean adjustFocusToNextFocusableStackLocked(String reason) {
    private boolean adjustFocusToNextFocusableStackLocked(String reason) {
        final ActivityStack stack = mStackSupervisor.getNextFocusableStackLocked(this);
        return adjustFocusToNextFocusableStackLocked(reason, false /* allowFocusSelf */);
    }

    /**
     * Find next proper focusable stack and make it focused.
     * @param allowFocusSelf Is the focus allowed to remain on the same stack.
     */
    private boolean adjustFocusToNextFocusableStackLocked(String reason, boolean allowFocusSelf) {
        final ActivityStack stack = mStackSupervisor.getNextFocusableStackLocked(
                allowFocusSelf ? null : this);
        final String myReason = reason + " adjustFocusToNextFocusableStack";
        final String myReason = reason + " adjustFocusToNextFocusableStack";
        if (stack == null) {
        if (stack == null) {
            return false;
            return false;
@@ -3246,7 +3258,8 @@ final class ActivityStack extends ConfigurationContainer implements StackWindowL


        if (stack.isHomeOrRecentsStack() && (top == null || !top.visible)) {
        if (stack.isHomeOrRecentsStack() && (top == null || !top.visible)) {
            // If we will be focusing on the home stack next and its current top activity isn't
            // If we will be focusing on the home stack next and its current top activity isn't
            // visible, then use the task return to value to determine the home task to display next.
            // visible, then use the task return to value to determine the home task to display
            // next.
            return mStackSupervisor.moveHomeStackTaskToTop(reason);
            return mStackSupervisor.moveHomeStackTaskToTop(reason);
        }
        }


+18 −9
Original line number Original line Diff line number Diff line
@@ -40,6 +40,7 @@ import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_PRIVATE;
import static android.view.Display.FLAG_PRIVATE;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT;


import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS;
@@ -2616,8 +2617,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
     * Move stack with all its existing content to specified display.
     * Move stack with all its existing content to specified display.
     * @param stackId Id of stack to move.
     * @param stackId Id of stack to move.
     * @param displayId Id of display to move stack to.
     * @param displayId Id of display to move stack to.
     * @param onTop Indicates whether container should be place on top or on bottom.
     */
     */
    void moveStackToDisplayLocked(int stackId, int displayId) {
    void moveStackToDisplayLocked(int stackId, int displayId, boolean onTop) {
        final ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
        final ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
        if (activityDisplay == null) {
        if (activityDisplay == null) {
            throw new IllegalArgumentException("moveStackToDisplayLocked: Unknown displayId="
            throw new IllegalArgumentException("moveStackToDisplayLocked: Unknown displayId="
@@ -2631,7 +2633,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
                            + " to its current displayId=" + displayId);
                            + " to its current displayId=" + displayId);
                }
                }


                activityContainer.moveToDisplayLocked(activityDisplay);
                activityContainer.moveToDisplayLocked(activityDisplay, onTop);
            } else {
            } else {
                throw new IllegalStateException("moveStackToDisplayLocked: Stack with stackId="
                throw new IllegalStateException("moveStackToDisplayLocked: Stack with stackId="
                        + stackId + " is not attached to any display.");
                        + stackId + " is not attached to any display.");
@@ -3777,12 +3779,16 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        synchronized (mService) {
        synchronized (mService) {
            ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
            ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
            if (activityDisplay != null) {
            if (activityDisplay != null) {
                final boolean destroyContentOnRemoval
                        = activityDisplay.shouldDestroyContentOnRemove();
                ArrayList<ActivityStack> stacks = activityDisplay.mStacks;
                ArrayList<ActivityStack> stacks = activityDisplay.mStacks;
                for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                    final ActivityStack stack = stacks.get(stackNdx);
                    final ActivityStack stack = stacks.get(stackNdx);
                    // TODO: Implement proper stack removal and ability to choose the behavior -
                    moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY,
                    // remove stack completely or move it to other display.
                            !destroyContentOnRemoval /* onTop */);
                    moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY);
                    if (destroyContentOnRemoval) {
                        stack.finishAllActivitiesLocked(true /* immediately */);
                    }
                }
                }
                mActivityDisplays.remove(displayId);
                mActivityDisplays.remove(displayId);
            }
            }
@@ -4451,8 +4457,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        /**
        /**
         * Move the stack to specified display.
         * Move the stack to specified display.
         * @param activityDisplay Target display to move the stack to.
         * @param activityDisplay Target display to move the stack to.
         * @param onTop Indicates whether container should be place on top or on bottom.
         */
         */
        void moveToDisplayLocked(ActivityDisplay activityDisplay) {
        void moveToDisplayLocked(ActivityDisplay activityDisplay, boolean onTop) {
            if (DEBUG_STACK) Slog.d(TAG_STACK, "moveToDisplayLocked: " + this + " from display="
            if (DEBUG_STACK) Slog.d(TAG_STACK, "moveToDisplayLocked: " + this + " from display="
                    + mActivityDisplay + " to display=" + activityDisplay
                    + mActivityDisplay + " to display=" + activityDisplay
                    + " Callers=" + Debug.getCallers(2));
                    + " Callers=" + Debug.getCallers(2));
@@ -4460,7 +4467,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            removeFromDisplayLocked();
            removeFromDisplayLocked();


            mActivityDisplay = activityDisplay;
            mActivityDisplay = activityDisplay;
            mStack.reparent(activityDisplay, ON_TOP);
            mStack.reparent(activityDisplay, onTop);
        }
        }


        @Override
        @Override
@@ -4642,8 +4649,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        /** Actual Display this object tracks. */
        /** Actual Display this object tracks. */
        int mDisplayId;
        int mDisplayId;
        Display mDisplay;
        Display mDisplay;
        private final DisplayMetrics mRealMetrics = new DisplayMetrics();
        private final Point mRealSize = new Point();


        /** All of the stacks on this display. Order matters, topmost stack is in front of all other
        /** All of the stacks on this display. Order matters, topmost stack is in front of all other
         * stacks, bottommost behind. Accessed directly by ActivityManager package classes */
         * stacks, bottommost behind. Accessed directly by ActivityManager package classes */
@@ -4737,6 +4742,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            }
            }
            return mDisplayAccessUIDs;
            return mDisplayAccessUIDs;
        }
        }

        boolean shouldDestroyContentOnRemove() {
            return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
        }
    }
    }


    class VirtualActivityDisplay extends ActivityDisplay {
    class VirtualActivityDisplay extends ActivityDisplay {
Loading