diff options
6 files changed, 81 insertions, 13 deletions
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 3ba55ed2c4dc..83b6a52e33e8 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -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() diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index f6b94af4b954..3d11dcbf14bf 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -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(); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ee1f28f4cb43..99c3f2c2e872 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -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); } diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 54082ea55b7d..0e36c55be8a1 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -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); } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index da7dc7d8b0ee..b31f577f6829 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -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 { diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index 40a895210480..a947b4106794 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -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; |