OSDN Git Service

Allow destroying display content on removal
authorAndrii Kulian <akulian@google.com>
Thu, 9 Feb 2017 07:30:45 +0000 (23:30 -0800)
committerAndrii Kulian <akulian@google.com>
Fri, 10 Feb 2017 06:45:19 +0000 (22:45 -0800)
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

core/java/android/view/Display.java
core/java/android/view/DisplayInfo.java
services/core/java/com/android/server/am/ActivityManagerService.java
services/core/java/com/android/server/am/ActivityStack.java
services/core/java/com/android/server/am/ActivityStackSupervisor.java
services/core/java/com/android/server/display/LogicalDisplay.java

index 3ba55ed..83b6a52 100644 (file)
@@ -339,6 +339,21 @@ public final class Display {
     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.
      * Applications should use {@link android.view.WindowManager#getDefaultDisplay()}
      * or {@link android.hardware.display.DisplayManager#getDisplay}
@@ -770,6 +785,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.
      *
      * @see #isHdr()
index f6b94af..3d11dcb 100644 (file)
@@ -238,6 +238,15 @@ public final class DisplayInfo implements Parcelable {
      */
     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>() {
         @Override
         public DisplayInfo createFromParcel(Parcel source) {
@@ -298,7 +307,8 @@ public final class DisplayInfo implements Parcelable {
                 && presentationDeadlineNanos == other.presentationDeadlineNanos
                 && state == other.state
                 && ownerUid == other.ownerUid
-                && Objects.equal(ownerPackageName, other.ownerPackageName);
+                && Objects.equal(ownerPackageName, other.ownerPackageName)
+                && removeMode == other.removeMode;
     }
 
     @Override
@@ -341,6 +351,7 @@ public final class DisplayInfo implements Parcelable {
         state = other.state;
         ownerUid = other.ownerUid;
         ownerPackageName = other.ownerPackageName;
+        removeMode = other.removeMode;
     }
 
     public void readFromParcel(Parcel source) {
@@ -385,6 +396,7 @@ public final class DisplayInfo implements Parcelable {
         ownerUid = source.readInt();
         ownerPackageName = source.readString();
         uniqueId = source.readString();
+        removeMode = source.readInt();
     }
 
     @Override
@@ -428,6 +440,7 @@ public final class DisplayInfo implements Parcelable {
         dest.writeInt(ownerUid);
         dest.writeString(ownerPackageName);
         dest.writeString(uniqueId);
+        dest.writeInt(removeMode);
     }
 
     @Override
@@ -637,6 +650,8 @@ public final class DisplayInfo implements Parcelable {
             sb.append(" (uid ").append(ownerUid).append(")");
         }
         sb.append(flagsToString(flags));
+        sb.append(", removeMode ");
+        sb.append(removeMode);
         sb.append("}");
         return sb.toString();
     }
index ee1f28f..99c3f2c 100644 (file)
@@ -9878,7 +9878,7 @@ public class ActivityManagerService extends IActivityManager.Stub
             try {
                 if (DEBUG_STACK) Slog.d(TAG_STACK, "moveStackToDisplay: moving stackId=" + stackId
                         + " to displayId=" + displayId);
-                mStackSupervisor.moveStackToDisplayLocked(stackId, displayId);
+                mStackSupervisor.moveStackToDisplayLocked(stackId, displayId, ON_TOP);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
index 54082ea..0e36c55 100644 (file)
@@ -477,6 +477,8 @@ final class ActivityStack extends ConfigurationContainer implements StackWindowL
         mTmpRect2.setEmpty();
         mWindowContainerController.reparent(activityDisplay.mDisplayId, mTmpRect2);
         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);
     }
 
+    /** Find next proper focusable stack and make it focused. */
     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";
         if (stack == null) {
             return false;
@@ -3246,7 +3258,8 @@ final class ActivityStack extends ConfigurationContainer implements StackWindowL
 
         if (stack.isHomeOrRecentsStack() && (top == null || !top.visible)) {
             // 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);
         }
 
index da7dc7d..b31f577 100644 (file)
@@ -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.FLAG_PRIVATE;
 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_CONTAINERS;
@@ -2616,8 +2617,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
      * Move stack with all its existing content to specified display.
      * @param stackId Id of stack to move.
      * @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);
         if (activityDisplay == null) {
             throw new IllegalArgumentException("moveStackToDisplayLocked: Unknown displayId="
@@ -2631,7 +2633,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
                             + " to its current displayId=" + displayId);
                 }
 
-                activityContainer.moveToDisplayLocked(activityDisplay);
+                activityContainer.moveToDisplayLocked(activityDisplay, onTop);
             } else {
                 throw new IllegalStateException("moveStackToDisplayLocked: Stack with stackId="
                         + stackId + " is not attached to any display.");
@@ -3777,12 +3779,16 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
         synchronized (mService) {
             ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
             if (activityDisplay != null) {
+                final boolean destroyContentOnRemoval
+                        = activityDisplay.shouldDestroyContentOnRemove();
                 ArrayList<ActivityStack> stacks = activityDisplay.mStacks;
                 for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                     final ActivityStack stack = stacks.get(stackNdx);
-                    // TODO: Implement proper stack removal and ability to choose the behavior -
-                    // remove stack completely or move it to other display.
-                    moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY);
+                    moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY,
+                            !destroyContentOnRemoval /* onTop */);
+                    if (destroyContentOnRemoval) {
+                        stack.finishAllActivitiesLocked(true /* immediately */);
+                    }
                 }
                 mActivityDisplays.remove(displayId);
             }
@@ -4451,8 +4457,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
         /**
          * Move the stack to specified display.
          * @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="
                     + mActivityDisplay + " to display=" + activityDisplay
                     + " Callers=" + Debug.getCallers(2));
@@ -4460,7 +4467,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
             removeFromDisplayLocked();
 
             mActivityDisplay = activityDisplay;
-            mStack.reparent(activityDisplay, ON_TOP);
+            mStack.reparent(activityDisplay, onTop);
         }
 
         @Override
@@ -4642,8 +4649,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
         /** Actual Display this object tracks. */
         int mDisplayId;
         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
          * stacks, bottommost behind. Accessed directly by ActivityManager package classes */
@@ -4737,6 +4742,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
             }
             return mDisplayAccessUIDs;
         }
+
+        boolean shouldDestroyContentOnRemove() {
+            return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
+        }
     }
 
     class VirtualActivityDisplay extends ActivityDisplay {
index 40a8952..a947b41 100644 (file)
@@ -216,6 +216,8 @@ final class LogicalDisplay {
             }
             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_PRIVATE) != 0) {
                 mBaseDisplayInfo.flags |= Display.FLAG_PRIVATE;
+                // For private displays by default content is destroyed on removal.
+                mBaseDisplayInfo.removeMode = Display.REMOVE_MODE_DESTROY_CONTENT;
             }
             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_PRESENTATION) != 0) {
                 mBaseDisplayInfo.flags |= Display.FLAG_PRESENTATION;