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}
}
/**
+ * @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()
*/
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) {
&& presentationDeadlineNanos == other.presentationDeadlineNanos
&& state == other.state
&& ownerUid == other.ownerUid
- && Objects.equal(ownerPackageName, other.ownerPackageName);
+ && Objects.equal(ownerPackageName, other.ownerPackageName)
+ && removeMode == other.removeMode;
}
@Override
state = other.state;
ownerUid = other.ownerUid;
ownerPackageName = other.ownerPackageName;
+ removeMode = other.removeMode;
}
public void readFromParcel(Parcel source) {
ownerUid = source.readInt();
ownerPackageName = source.readString();
uniqueId = source.readString();
+ removeMode = source.readInt();
}
@Override
dest.writeInt(ownerUid);
dest.writeString(ownerPackageName);
dest.writeString(uniqueId);
+ dest.writeInt(removeMode);
}
@Override
sb.append(" (uid ").append(ownerUid).append(")");
}
sb.append(flagsToString(flags));
+ sb.append(", removeMode ");
+ sb.append(removeMode);
sb.append("}");
return sb.toString();
}
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);
}
mTmpRect2.setEmpty();
mWindowContainerController.reparent(activityDisplay.mDisplayId, mTmpRect2);
postAddToDisplay(activityDisplay, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop);
+ adjustFocusToNextFocusableStackLocked("reparent", true /* allowFocusSelf */);
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
/**
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;
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);
}
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;
* 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="
+ " 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.");
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);
}
/**
* 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));
removeFromDisplayLocked();
mActivityDisplay = activityDisplay;
- mStack.reparent(activityDisplay, ON_TOP);
+ mStack.reparent(activityDisplay, onTop);
}
@Override
/** 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 */
}
return mDisplayAccessUIDs;
}
+
+ boolean shouldDestroyContentOnRemove() {
+ return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
+ }
}
class VirtualActivityDisplay extends ActivityDisplay {
}
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;