summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Andrii Kulian <akulian@google.com> 2017-02-08 23:30:45 -0800
committer Andrii Kulian <akulian@google.com> 2017-02-09 22:45:19 -0800
commit250d653325ffeeb8ef75e51e3a3d08d6abb8cf9c (patch)
tree933514d2f0bf7985be2e8735bb8eb5f3756fb7d6
parentf2ca8e030c4e65dcd9d7d021cca296fec85320b7 (diff)
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
-rw-r--r--core/java/android/view/Display.java29
-rw-r--r--core/java/android/view/DisplayInfo.java17
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java2
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java17
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java27
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java2
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;