From 04a05ac34ab548c334669547b4675f4871d2f2e1 Mon Sep 17 00:00:00 2001 From: Wale Ogunwale Date: Sun, 17 Sep 2017 21:35:02 -0700 Subject: [PATCH 1/2] Ability to getOrCreateStack by windowingMode/activityType in AM. Another step away from using static stack ids for things. Test: Existing tests pass. Test: go/wm-smoke Bug: 64146578 Change-Id: Iac05046c96d10e5b26d444172341f2ecf9efe3ee --- core/java/android/app/ActivityManager.java | 4 +- .../java/android/app/WindowConfiguration.java | 9 +- .../views/RecentsTransitionHelper.java | 6 - .../android/server/am/ActivityDisplay.java | 170 +++++++ .../server/am/ActivityManagerService.java | 112 +++-- .../server/am/ActivityMetricsLogger.java | 6 - .../com/android/server/am/ActivityRecord.java | 21 +- .../com/android/server/am/ActivityStack.java | 92 ++-- .../server/am/ActivityStackSupervisor.java | 439 +++++++++--------- .../android/server/am/ActivityStarter.java | 119 ++--- .../android/server/am/KeyguardController.java | 2 +- .../server/am/PinnedActivityStack.java | 5 +- .../com/android/server/am/TaskRecord.java | 88 ++-- .../server/wm/ConfigurationContainer.java | 28 +- .../server/am/ActivityRecordTests.java | 119 +++-- .../am/ActivityStackSupervisorTests.java | 82 ++-- .../android/server/am/ActivityStackTests.java | 83 ++-- .../android/server/am/ActivityTestsBase.java | 115 ++--- 18 files changed, 827 insertions(+), 673 deletions(-) diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 5e2e333b4c9c1..b38caf8a919be 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -675,7 +675,7 @@ public class ActivityManager { /** First static stack ID. * @hide */ - public static final int FIRST_STATIC_STACK_ID = 0; + private static final int FIRST_STATIC_STACK_ID = 0; /** Home activity stack ID. */ public static final int HOME_STACK_ID = FIRST_STATIC_STACK_ID; @@ -700,7 +700,7 @@ public class ActivityManager { /** Last static stack stack ID. * @hide */ - public static final int LAST_STATIC_STACK_ID = ASSISTANT_STACK_ID; + private static final int LAST_STATIC_STACK_ID = ASSISTANT_STACK_ID; /** Start of ID range used by stacks that are created dynamically. * @hide */ diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java index 0cb38046826f6..6b4053842338d 100644 --- a/core/java/android/app/WindowConfiguration.java +++ b/core/java/android/app/WindowConfiguration.java @@ -500,10 +500,15 @@ public class WindowConfiguration implements Parcelable, Comparable T getStack(int windowingMode, int activityType) { + for (int i = mStacks.size() - 1; i >= 0; --i) { + final ActivityStack stack = mStacks.get(i); + // TODO: Should undefined windowing and activity type be compatible with standard type? + if (stack.isCompatible(windowingMode, activityType)) { + return (T) stack; + } + } + return null; + } + + /** + * @see #getStack(int, int) + * @see #createStack(int, int, boolean) + */ + T getOrCreateStack(int windowingMode, int activityType, + boolean onTop) { + T stack = getStack(windowingMode, activityType); + if (stack != null) { + return stack; + } + return createStack(windowingMode, activityType, onTop); + } + + /** Creates a stack matching the input windowing mode and activity type on this display. */ + T createStack(int windowingMode, int activityType, boolean onTop) { + + if (activityType != ACTIVITY_TYPE_STANDARD && activityType != ACTIVITY_TYPE_UNDEFINED) { + // For now there can be only one stack of a particular non-standard activity type on a + // display. So, get that ignoring whatever windowing mode it is currently in. + T stack = getStack(WINDOWING_MODE_UNDEFINED, activityType); + if (stack != null) { + throw new IllegalArgumentException("Stack=" + stack + " of activityType=" + + activityType + " already on display=" + this + ". Can't have multiple."); + } + } + + final ActivityManagerService service = mSupervisor.mService; + if (!mSupervisor.isWindowingModeSupported(windowingMode, service.mSupportsMultiWindow, + service.mSupportsSplitScreenMultiWindow, service.mSupportsFreeformWindowManagement, + service.mSupportsPictureInPicture, activityType)) { + throw new IllegalArgumentException("Can't create stack for unsupported windowingMode=" + + windowingMode); + } + + if (windowingMode == WINDOWING_MODE_UNDEFINED) { + // TODO: Should be okay to have stacks with with undefined windowing mode long term, but + // have to set them to something for now due to logic that depending on them. + windowingMode = WINDOWING_MODE_FULLSCREEN; + } + + final boolean inSplitScreenMode = hasSplitScreenStack(); + if (!inSplitScreenMode + && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) { + // Switch to fullscreen windowing mode if we are not in split-screen mode and we are + // trying to launch in split-screen secondary. + windowingMode = WINDOWING_MODE_FULLSCREEN; + } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN + && WindowConfiguration.supportSplitScreenWindowingMode( + windowingMode, activityType)) { + windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; + } + + int stackId = INVALID_STACK_ID; + if (mDisplayId == DEFAULT_DISPLAY) { + // TODO: Will be removed once we are no longer using static stack ids. + stackId = getStackIdForActivityType(activityType); + if (stackId == INVALID_STACK_ID) { + stackId = getStackIdForWindowingMode(windowingMode); + } + if (stackId == INVALID_STACK_ID) { + // Whatever...put in fullscreen stack for now. + stackId = FULLSCREEN_WORKSPACE_STACK_ID; + } + final T stack = getStack(stackId); + if (stack != null) { + return stack; + } + } + + if (stackId == INVALID_STACK_ID) { + stackId = mSupervisor.getNextStackId(); + } + + final T stack = createStackUnchecked(windowingMode, activityType, stackId, onTop); + + if (mDisplayId == DEFAULT_DISPLAY && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { + // Make sure recents stack exist when creating a dock stack as it normally need to be on + // the other side of the docked stack and we make visibility decisions based on that. + // TODO: Not sure if this is needed after we change to calculate visibility based on + // stack z-order vs. id. + getOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_RECENTS, onTop); + } + + return stack; + } + + @VisibleForTesting + T createStackUnchecked(int windowingMode, int activityType, + int stackId, boolean onTop) { + switch (windowingMode) { + case WINDOWING_MODE_PINNED: + return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop); + default: + return (T) new ActivityStack( + this, stackId, mSupervisor, windowingMode, activityType, onTop); + } + } + + /** Removes all stacks in the input windowing mode from the system */ + void removeStacksInWindowingMode(int windowingMode) { + for (int i = mStacks.size() - 1; i >= 0; --i) { + final ActivityStack stack = mStacks.get(i); + if (stack.getWindowingMode() == windowingMode) { + mSupervisor.removeStackLocked(stack.mStackId); + } + } + } + + /** Returns the top visible stack activity type that isn't in the exclude windowing mode. */ + int getTopVisibleStackActivityType(int excludeWindowingMode) { + for (int i = mStacks.size() - 1; i >= 0; --i) { + final ActivityStack stack = mStacks.get(i); + if (stack.getWindowingMode() == excludeWindowingMode) { + continue; + } + if (stack.shouldBeVisible(null /* starting */)) { + return stack.getActivityType(); + } + } + return ACTIVITY_TYPE_UNDEFINED; + } + + ActivityStack getSplitScreenStack() { + return getStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED); + } + + boolean hasSplitScreenStack() { + return getSplitScreenStack() != null; + } + + PinnedActivityStack getPinnedStack() { + return getStack(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED); + } + + boolean hasPinnedStack() { + return getPinnedStack() != null; + } + @Override public String toString() { return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}"; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 7295bcb9bc91f..2c39d8b3acd2a 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -33,6 +33,14 @@ import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID; import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.app.ActivityManager.StackId.getActivityTypeForStackId; +import static android.app.ActivityManager.StackId.getWindowingModeForStackId; +import static android.app.ActivityManager.StackId.isStaticStack; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS; import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT; import static android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY; @@ -164,7 +172,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_URI_PERMI import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED; import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME; import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_ONLY; import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS; @@ -177,7 +184,6 @@ import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE; import static com.android.server.am.proto.ActivityManagerServiceProto.ACTIVITIES; import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN; -import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_RELAUNCH; import static com.android.server.wm.AppTransition.TRANSIT_NONE; import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE; import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN; @@ -2372,11 +2378,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (disableNonVrUi) { // If we are in a VR mode where Picture-in-Picture mode is unsupported, // then remove the pinned stack. - final PinnedActivityStack pinnedStack = mStackSupervisor.getStack( - PINNED_STACK_ID); - if (pinnedStack != null) { - mStackSupervisor.removeStackLocked(PINNED_STACK_ID); - } + mStackSupervisor.removeStacksInWindowingMode(WINDOWING_MODE_PINNED); } } } break; @@ -8105,7 +8107,7 @@ public class ActivityManagerService extends IActivityManager.Stub final Rect sourceBounds = new Rect(r.pictureInPictureArgs.getSourceRectHint()); mStackSupervisor.moveActivityToPinnedStackLocked(r, sourceBounds, aspectRatio, true /* moveHomeStackToFront */, "enterPictureInPictureMode"); - final PinnedActivityStack stack = mStackSupervisor.getStack(PINNED_STACK_ID); + final PinnedActivityStack stack = r.getStack(); stack.setPictureInPictureAspectRatio(aspectRatio); stack.setPictureInPictureActions(actions); @@ -9862,7 +9864,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (tr.mBounds != null) { rti.bounds = new Rect(tr.mBounds); } - rti.supportsSplitScreenMultiWindow = tr.supportsSplitScreen(); + rti.supportsSplitScreenMultiWindow = tr.supportsSplitScreenWindowingMode(); rti.resizeMode = tr.mResizeMode; ActivityRecord base = null; @@ -10181,21 +10183,23 @@ public class ActivityManagerService extends IActivityManager.Stub // - a non-null bounds on a non-freeform (fullscreen OR docked) task moves // that task to freeform // - otherwise the task is not moved - int stackId = task.getStackId(); + ActivityStack stack = task.getStack(); if (!task.getWindowConfiguration().canResizeTask()) { throw new IllegalArgumentException("resizeTask not allowed on task=" + task); } - if (bounds == null && stackId == FREEFORM_WORKSPACE_STACK_ID) { - stackId = FULLSCREEN_WORKSPACE_STACK_ID; - } else if (bounds != null && stackId != FREEFORM_WORKSPACE_STACK_ID ) { - stackId = FREEFORM_WORKSPACE_STACK_ID; + if (bounds == null && stack.getWindowingMode() == WINDOWING_MODE_FREEFORM) { + stack = stack.getDisplay().getOrCreateStack( + WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), ON_TOP); + } else if (bounds != null && stack.getWindowingMode() != WINDOWING_MODE_FREEFORM) { + stack = stack.getDisplay().getOrCreateStack( + WINDOWING_MODE_FREEFORM, stack.getActivityType(), ON_TOP); } // Reparent the task to the right stack if necessary boolean preserveWindow = (resizeMode & RESIZE_MODE_PRESERVE_WINDOW) != 0; - if (stackId != task.getStackId()) { + if (stack != task.getStack()) { // Defer resume until the task is resized below - task.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, + task.reparent(stack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, DEFER_RESUME, "resizeTask"); preserveWindow = false; } @@ -10525,13 +10529,15 @@ public class ActivityManagerService extends IActivityManager.Stub public int createStackOnDisplay(int displayId) throws RemoteException { enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "createStackOnDisplay()"); synchronized (this) { - final int stackId = mStackSupervisor.getNextStackId(); - final ActivityStack stack = - mStackSupervisor.createStackOnDisplay(stackId, displayId, true /*onTop*/); - if (stack == null) { + final ActivityDisplay display = + mStackSupervisor.getActivityDisplayOrCreateLocked(displayId); + if (display == null) { return INVALID_STACK_ID; } - return stack.mStackId; + // TODO(multi-display): Have the caller pass in the windowing mode and activity type. + final ActivityStack stack = display.createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /*onTop*/); + return (stack != null) ? stack.mStackId : INVALID_STACK_ID; } } @@ -10563,8 +10569,12 @@ public class ActivityManagerService extends IActivityManager.Stub "exitFreeformMode: You can only go fullscreen from freeform."); } + final ActivityStack fullscreenStack = stack.getDisplay().getOrCreateStack( + WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), ON_TOP); + if (DEBUG_STACK) Slog.d(TAG_STACK, "exitFreeformMode: " + r); - r.getTask().reparent(FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, + // TODO: Should just change windowing mode vs. re-parenting... + r.getTask().reparent(fullscreenStack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME, "exitFreeformMode"); } finally { Binder.restoreCallingIdentity(ident); @@ -10594,8 +10604,20 @@ public class ActivityManagerService extends IActivityManager.Stub mWindowManager.setDockedStackCreateState(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */); } - task.reparent(stackId, toTop, - REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME, "moveTaskToStack"); + + ActivityStack stack = mStackSupervisor.getStack(stackId); + if (stack == null) { + if (!isStaticStack(stackId)) { + throw new IllegalStateException( + "moveTaskToStack: No stack for stackId=" + stackId); + } + stack = mStackSupervisor.getDefaultDisplay().createStack( + getWindowingModeForStackId(stackId, + mStackSupervisor.getDefaultDisplay().hasSplitScreenStack()), + getActivityTypeForStackId(stackId), toTop); + } + task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME, + "moveTaskToStack"); } finally { Binder.restoreCallingIdentity(ident); } @@ -10628,13 +10650,18 @@ public class ActivityManagerService extends IActivityManager.Stub Slog.w(TAG, "moveTaskToDockedStack: No task for id=" + taskId); return false; } - if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToDockedStack: moving task=" + taskId + " to createMode=" + createMode + " toTop=" + toTop); mWindowManager.setDockedStackCreateState(createMode, initialBounds); + final ActivityDisplay display = task.getStack().getDisplay(); + final ActivityStack stack = display.getOrCreateStack( + WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, task.getStack().getActivityType(), + toTop); + // Defer resuming until we move the home stack to the front below - final boolean moved = task.reparent(DOCKED_STACK_ID, toTop, + // TODO: Should just change windowing mode vs. re-parenting... + final boolean moved = task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, animate, !DEFER_RESUME, "moveTaskToDockedStack"); if (moved) { @@ -10682,17 +10709,16 @@ public class ActivityManagerService extends IActivityManager.Stub try { synchronized (this) { if (animate) { - if (stackId == PINNED_STACK_ID) { - final PinnedActivityStack pinnedStack = - mStackSupervisor.getStack(PINNED_STACK_ID); - if (pinnedStack != null) { - pinnedStack.animateResizePinnedStack(null /* sourceHintBounds */, - destBounds, animationDuration, false /* fromFullscreen */); - } - } else { + final PinnedActivityStack stack = mStackSupervisor.getStack(stackId); + if (stack == null) { + return; + } + if (stack.getWindowingMode() != WINDOWING_MODE_PINNED) { throw new IllegalArgumentException("Stack: " + stackId + " doesn't support animated resize."); } + stack.animateResizePinnedStack(null /* sourceHintBounds */, destBounds, + animationDuration, false /* fromFullscreen */); } else { mStackSupervisor.resizeStackLocked(stackId, destBounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */, preserveWindows, @@ -10760,8 +10786,12 @@ public class ActivityManagerService extends IActivityManager.Stub + taskId); } - final ActivityStack stack = mStackSupervisor.getStack(stackId, CREATE_IF_NEEDED, - !ON_TOP); + final ActivityStack stack = mStackSupervisor.getStack(stackId); + + if (stack == null) { + throw new IllegalArgumentException("positionTaskInStack: no stack for id=" + + stackId); + } // TODO: Have the callers of this API call a separate reparent method if that is // what they intended to do vs. having this method also do reparenting. @@ -10770,8 +10800,8 @@ public class ActivityManagerService extends IActivityManager.Stub stack.positionChildAt(task, position); } else { // Reparent to new stack. - task.reparent(stackId, position, REPARENT_LEAVE_STACK_IN_PLACE, - !ANIMATE, !DEFER_RESUME, "positionTaskInStack"); + task.reparent(stack, position, REPARENT_LEAVE_STACK_IN_PLACE, !ANIMATE, + !DEFER_RESUME, "positionTaskInStack"); } } finally { Binder.restoreCallingIdentity(ident); @@ -10849,11 +10879,7 @@ public class ActivityManagerService extends IActivityManager.Stub } // When a task is locked, dismiss the pinned stack if it exists - final PinnedActivityStack pinnedStack = mStackSupervisor.getStack( - PINNED_STACK_ID); - if (pinnedStack != null) { - mStackSupervisor.removeStackLocked(PINNED_STACK_ID); - } + mStackSupervisor.removeStacksInWindowingMode(WINDOWING_MODE_PINNED); // isAppPinning is used to distinguish between locked and pinned mode, as pinned mode // is initiated by system after the pinning request was shown and locked mode is initiated diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java index 0c8321d5b5c8c..fdcb8c695662a 100644 --- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java @@ -2,12 +2,9 @@ package com.android.server.am; import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_TASK_TO_FRONT; -import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID; -import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManagerInternal.APP_TRANSITION_TIMEOUT; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; -import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; @@ -32,13 +29,10 @@ import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_T import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.am.ActivityStack.STACK_INVISIBLE; -import android.app.ActivityManager.StackId; import android.content.Context; import android.metrics.LogMaker; import android.os.SystemClock; -import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 193443691ee58..7b0b942a98f13 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -17,7 +17,6 @@ package com.android.server.am; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; -import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; @@ -103,7 +102,6 @@ import static com.android.server.am.ActivityStack.ActivityState.STOPPING; import static com.android.server.am.ActivityStack.LAUNCH_TICK; import static com.android.server.am.ActivityStack.LAUNCH_TICK_MSG; import static com.android.server.am.ActivityStack.PAUSE_TIMEOUT_MSG; -import static com.android.server.am.ActivityStack.STACK_INVISIBLE; import static com.android.server.am.ActivityStack.STOP_TIMEOUT_MSG; import static com.android.server.am.EventLogTags.AM_ACTIVITY_FULLY_DRAWN_TIME; import static com.android.server.am.EventLogTags.AM_ACTIVITY_LAUNCH_TIME; @@ -1069,6 +1067,11 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo return getStack() != null ? getStack().mStackId : INVALID_STACK_ID; } + ActivityDisplay getDisplay() { + final ActivityStack stack = getStack(); + return stack != null ? stack.getDisplay() : null; + } + boolean changeWindowTranslucency(boolean toOpaque) { if (fullscreen == toOpaque) { return false; @@ -1134,10 +1137,12 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo * @return whether this activity supports split-screen multi-window and can be put in the docked * stack. */ - boolean supportsSplitScreen() { + @Override + public boolean supportsSplitScreenWindowingMode() { // An activity can not be docked even if it is considered resizeable because it only // supports picture-in-picture mode but has a non-resizeable resizeMode - return service.mSupportsSplitScreenMultiWindow && supportsResizeableMultiWindow(); + return super.supportsSplitScreenWindowingMode() + && service.mSupportsSplitScreenMultiWindow && supportsResizeableMultiWindow(); } /** @@ -1198,7 +1203,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo boolean isKeyguardLocked = service.isKeyguardLocked(); boolean isCurrentAppLocked = service.getLockTaskModeState() != LOCK_TASK_MODE_NONE; - boolean hasPinnedStack = mStackSupervisor.getStack(PINNED_STACK_ID) != null; + final ActivityDisplay display = getDisplay(); + boolean hasPinnedStack = display != null && display.hasPinnedStack(); // Don't return early if !isNotLocked, since we want to throw an exception if the activity // is in an incorrect state boolean isNotLockedOrOnKeyguard = !isKeyguardLocked && !isCurrentAppLocked; @@ -1544,8 +1550,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo if (service.mSupportsLeanbackOnly && isVisible && isActivityTypeRecents()) { // On devices that support leanback only (Android TV), Recents activity can only be // visible if the home stack is the focused stack or we are in split-screen mode. - isVisible = mStackSupervisor.getStack(DOCKED_STACK_ID) != null - || mStackSupervisor.isFocusedStack(getStack()); + final ActivityDisplay display = getDisplay(); + boolean hasSplitScreenStack = display != null && display.hasSplitScreenStack(); + isVisible = hasSplitScreenStack || mStackSupervisor.isFocusedStack(getStack()); } return isVisible; diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 829669327bf41..76b4ae224ea36 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -23,12 +23,11 @@ import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; -import static android.app.ActivityManager.StackId.getActivityTypeForStackId; -import static android.app.ActivityManager.StackId.getWindowingModeForStackId; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; @@ -77,7 +76,6 @@ import static com.android.server.am.ActivityStack.ActivityState.PAUSED; import static com.android.server.am.ActivityStack.ActivityState.STOPPED; import static com.android.server.am.ActivityStack.ActivityState.STOPPING; import static com.android.server.am.ActivityStackSupervisor.FindTaskResult; -import static com.android.server.am.ActivityStackSupervisor.ON_TOP; import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY; import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; @@ -112,7 +110,6 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.res.Configuration; -import android.graphics.Point; import android.graphics.Rect; import android.net.Uri; import android.os.Binder; @@ -243,11 +240,6 @@ class ActivityStack extends ConfigurationContai DESTROYED } - // Stack is not considered visible. - static final int STACK_INVISIBLE = 0; - // Stack is considered visible - static final int STACK_VISIBLE = 1; - @VisibleForTesting /* The various modes for the method {@link #removeTask}. */ // Task is being completely removed from all stacks in the system. @@ -461,7 +453,7 @@ class ActivityStack extends ConfigurationContai } ActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor, - boolean onTop) { + int windowingMode, int activityType, boolean onTop) { mStackSupervisor = supervisor; mService = supervisor.mService; mHandler = new ActivityStackHandler(mService.mHandler.getLooper()); @@ -471,7 +463,8 @@ class ActivityStack extends ConfigurationContai mTaskPositioner = mStackId == FREEFORM_WORKSPACE_STACK_ID ? new LaunchingTaskPositioner() : null; mTmpRect2.setEmpty(); - updateOverrideConfiguration(); + setWindowingMode(windowingMode); + setActivityType(activityType); mWindowContainerController = createStackWindowController(display.mDisplayId, onTop, mTmpRect2); postAddToDisplay(display, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop); @@ -485,20 +478,6 @@ class ActivityStack extends ConfigurationContai return mWindowContainerController; } - // TODO: Not needed once we are no longer using stack ids as the override config. can be passed - // in. - private void updateOverrideConfiguration() { - final int windowingMode = getWindowingModeForStackId( - mStackId, mStackSupervisor.getStack(DOCKED_STACK_ID) != null); - if (windowingMode != WINDOWING_MODE_UNDEFINED) { - setWindowingMode(windowingMode); - } - final int activityType = getActivityTypeForStackId(mStackId); - if (activityType != ACTIVITY_TYPE_UNDEFINED) { - setActivityType(activityType); - } - } - /** Adds the stack to specified display and calls WindowManager to do the same. */ void reparent(ActivityDisplay activityDisplay, boolean onTop) { removeFromDisplay(); @@ -518,8 +497,7 @@ class ActivityStack extends ConfigurationContai * @param activityDisplay New display to which this stack was attached. * @param bounds Updated bounds. */ - private void postAddToDisplay(ActivityDisplay activityDisplay, - Rect bounds, boolean onTop) { + private void postAddToDisplay(ActivityDisplay activityDisplay, Rect bounds, boolean onTop) { mDisplayId = activityDisplay.mDisplayId; mBounds = bounds != null ? new Rect(bounds) : null; mFullscreen = mBounds == null; @@ -571,12 +549,8 @@ class ActivityStack extends ConfigurationContai return mStackSupervisor.getActivityDisplay(mDisplayId); } - void getDisplaySize(Point out) { - getDisplay().mDisplay.getSize(out); - } - /** - * @see ActivityStack.getStackDockedModeBounds(Rect, Rect, Rect, boolean) + * @see #getStackDockedModeBounds(Rect, Rect, Rect, boolean) */ void getStackDockedModeBounds(Rect currentTempTaskBounds, Rect outStackBounds, Rect outTempTaskBounds, boolean ignoreVisibility) { @@ -1068,7 +1042,6 @@ class ActivityStack extends ConfigurationContai "Launch completed; removing icicle of " + r.icicle); } - private void startLaunchTraces(String packageName) { if (mFullyDrawnStartTime != 0) { Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0); @@ -1483,7 +1456,7 @@ class ActivityStack extends ConfigurationContai // focus). Also if there is an active pinned stack - we always want to notify it about // task stack changes, because its positioning may depend on it. if (mStackSupervisor.mAppVisibilitiesChangedSinceLastPause - || mService.mStackSupervisor.getStack(PINNED_STACK_ID) != null) { + || getDisplay().hasPinnedStack()) { mService.mTaskChangeNotificationController.notifyTaskStackChanged(); mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false; } @@ -1591,7 +1564,8 @@ class ActivityStack extends ConfigurationContai return true; } - final ArrayList displayStacks = getDisplay().mStacks; + final ActivityDisplay display = getDisplay(); + final ArrayList displayStacks = display.mStacks; final int stackIndex = displayStacks.indexOf(this); if (stackIndex == displayStacks.size() - 1) { @@ -1603,8 +1577,10 @@ class ActivityStack extends ConfigurationContai // Check position and visibility of this stack relative to the front stack on its display. final ActivityStack topStack = getTopStackOnDisplay(); final int topStackId = topStack.mStackId; + final int windowingMode = getWindowingMode(); + final int activityType = getActivityType(); - if (mStackId == DOCKED_STACK_ID) { + if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { // If the assistant stack is focused and translucent, then the docked stack is always // visible if (topStack.isActivityTypeAssistant()) { @@ -1616,9 +1592,10 @@ class ActivityStack extends ConfigurationContai // Set home stack to invisible when it is below but not immediately below the docked stack // A case would be if recents stack exists but has no tasks and is below the docked stack // and home stack is below recents - if (mStackId == HOME_STACK_ID) { - int dockedStackIndex = displayStacks.indexOf - (mStackSupervisor.getStack(DOCKED_STACK_ID)); + if (activityType == ACTIVITY_TYPE_HOME) { + final ActivityStack splitScreenStack = display.getStack( + WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED); + int dockedStackIndex = displayStacks.indexOf(splitScreenStack); if (dockedStackIndex > stackIndex && stackIndex != dockedStackIndex - 1) { return false; } @@ -1630,19 +1607,28 @@ class ActivityStack extends ConfigurationContai displayStacks.get(stackBehindTopIndex).topRunningActivityLocked() == null) { stackBehindTopIndex--; } - final int stackBehindTopId = (stackBehindTopIndex >= 0) - ? displayStacks.get(stackBehindTopIndex).mStackId : INVALID_STACK_ID; + final ActivityStack stackBehindTop = (stackBehindTopIndex >= 0) + ? displayStacks.get(stackBehindTopIndex) : null; + int stackBehindTopId = INVALID_STACK_ID; + int stackBehindTopWindowingMode = WINDOWING_MODE_UNDEFINED; + int stackBehindTopActivityType = ACTIVITY_TYPE_UNDEFINED; + if (stackBehindTop != null) { + stackBehindTopId = stackBehindTop.mStackId; + stackBehindTopWindowingMode = stackBehindTop.getWindowingMode(); + stackBehindTopActivityType = stackBehindTop.getActivityType(); + } + final boolean alwaysOnTop = topStack.getWindowConfiguration().isAlwaysOnTop(); - if (topStackId == DOCKED_STACK_ID || alwaysOnTop) { + if (topStack.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY || alwaysOnTop) { if (stackIndex == stackBehindTopIndex) { // Stacks directly behind the docked or pinned stack are always visible. return true; } else if (alwaysOnTop && stackIndex == stackBehindTopIndex - 1) { // Otherwise, this stack can also be visible if it is directly behind a docked stack // or translucent assistant stack behind an always-on-top top-most stack - if (stackBehindTopId == DOCKED_STACK_ID) { + if (stackBehindTopWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { return true; - } else if (stackBehindTopId == ASSISTANT_STACK_ID) { + } else if (stackBehindTopActivityType == ACTIVITY_TYPE_ASSISTANT) { return displayStacks.get(stackBehindTopIndex).isStackTranslucent( starting, mStackId); } @@ -1658,8 +1644,8 @@ class ActivityStack extends ConfigurationContai return true; } if (stackBehindTopIndex >= 0) { - if ((stackBehindTopId == DOCKED_STACK_ID - || stackBehindTopId == PINNED_STACK_ID) + if ((stackBehindTopWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY + || stackBehindTopWindowingMode == WINDOWING_MODE_PINNED) && stackIndex == (stackBehindTopIndex - 1)) { // The stack behind the docked or pinned stack is also visible so we can have a // complete backdrop to the translucent activity when the docked stack is up. @@ -1727,8 +1713,8 @@ class ActivityStack extends ConfigurationContai // If the top activity is not fullscreen, then we need to // make sure any activities under it are now visible. boolean aboveTop = top != null; - final boolean stackVisible = shouldBeVisible(starting); - boolean behindFullscreenActivity = !stackVisible; + final boolean stackShouldBeVisible = shouldBeVisible(starting); + boolean behindFullscreenActivity = !stackShouldBeVisible; boolean resumeNextActivity = mStackSupervisor.isFocusedStack(this) && (isInStackLocked(starting) == null); for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { @@ -1754,7 +1740,7 @@ class ActivityStack extends ConfigurationContai final boolean reallyVisible = checkKeyguardVisibility(r, visibleIgnoringKeyguard, isTop); if (visibleIgnoringKeyguard) { - behindFullscreenActivity = updateBehindFullscreen(!stackVisible, + behindFullscreenActivity = updateBehindFullscreen(!stackShouldBeVisible, behindFullscreenActivity, task, r); } if (reallyVisible) { @@ -1792,7 +1778,7 @@ class ActivityStack extends ConfigurationContai } else { if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make invisible? " + r + " finishing=" + r.finishing + " state=" + r.state - + " stackVisible=" + stackVisible + + " stackShouldBeVisible=" + stackShouldBeVisible + " behindFullscreenActivity=" + behindFullscreenActivity + " mLaunchTaskBehind=" + r.mLaunchTaskBehind); makeInvisible(r); @@ -1802,10 +1788,10 @@ class ActivityStack extends ConfigurationContai // The visibility of tasks and the activities they contain in freeform stack are // determined individually unlike other stacks where the visibility or fullscreen // status of an activity in a previous task affects other. - behindFullscreenActivity = !stackVisible; + behindFullscreenActivity = !stackShouldBeVisible; } else if (mStackId == HOME_STACK_ID) { if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home task: at " + task - + " stackVisible=" + stackVisible + + " stackShouldBeVisible=" + stackShouldBeVisible + " behindFullscreenActivity=" + behindFullscreenActivity); // No other task in the home stack should be visible behind the home activity. // Home activities is usually a translucent activity with the wallpaper behind @@ -4891,7 +4877,7 @@ class ActivityStack extends ConfigurationContai } ci.numActivities = numActivities; ci.numRunning = numRunning; - ci.supportsSplitScreenMultiWindow = task.supportsSplitScreen(); + ci.supportsSplitScreenMultiWindow = task.supportsSplitScreenWindowingMode(); ci.resizeMode = task.mResizeMode; list.add(ci); } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index f423ce81bd754..424caa00d0566 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -24,16 +24,12 @@ import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID; -import static android.app.ActivityManager.StackId.FIRST_STATIC_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; -import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.ActivityManager.StackId.RECENTS_STACK_ID; -import static android.app.ActivityManager.StackId.getStackIdForActivityType; -import static android.app.ActivityManager.StackId.getStackIdForWindowingMode; import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY; import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; @@ -87,8 +83,6 @@ import static com.android.server.am.ActivityStack.ActivityState.RESUMED; import static com.android.server.am.ActivityStack.ActivityState.STOPPED; import static com.android.server.am.ActivityStack.ActivityState.STOPPING; import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING; -import static com.android.server.am.ActivityStack.STACK_INVISIBLE; -import static com.android.server.am.ActivityStack.STACK_VISIBLE; import static com.android.server.am.TaskRecord.INVALID_TASK_ID; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; @@ -100,8 +94,6 @@ import static com.android.server.am.proto.ActivityStackSupervisorProto.FOCUSED_S import static com.android.server.am.proto.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER; import static com.android.server.am.proto.ActivityStackSupervisorProto.RESUMED_ACTIVITY; import static com.android.server.am.proto.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER; -import static com.android.server.am.proto.ActivityDisplayProto.STACKS; -import static com.android.server.am.proto.ActivityDisplayProto.ID; import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS; import static java.lang.Integer.MAX_VALUE; @@ -121,6 +113,7 @@ import android.app.AppOpsManager; import android.app.ProfilerInfo; import android.app.ResultInfo; import android.app.WaitResult; +import android.app.WindowConfiguration; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -172,7 +165,6 @@ import com.android.internal.os.TransferPipe; import com.android.internal.util.ArrayUtils; import com.android.server.LocalServices; import com.android.server.am.ActivityStack.ActivityState; -import com.android.server.am.proto.ActivityDisplayProto; import com.android.server.wm.ConfigurationContainer; import com.android.server.wm.PinnedStackWindowController; import com.android.server.wm.WindowManagerService; @@ -619,8 +611,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D calculateDefaultMinimalSizeOfResizeableTasks(activityDisplay); } - mHomeStack = mFocusedStack = mLastFocusedStack = - getStack(HOME_STACK_ID, CREATE_IF_NEEDED, ON_TOP); + mHomeStack = mFocusedStack = mLastFocusedStack = getDefaultDisplay().getOrCreateStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); } @@ -676,7 +668,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } void moveRecentsStackToFront(String reason) { - final ActivityStack recentsStack = getStack(RECENTS_STACK_ID); + final ActivityStack recentsStack = getDefaultDisplay().getStack( + WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS); if (recentsStack != null) { recentsStack.moveToFront(reason); } @@ -1163,8 +1156,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D void getTasksLocked(int maxNum, List list, int callingUid, boolean allowed) { // Gather all of the running tasks for each stack into runningTaskLists. - ArrayList> runningTaskLists = - new ArrayList>(); + ArrayList> runningTaskLists = new ArrayList<>(); final int numDisplays = mActivityDisplays.size(); for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { ArrayList stacks = mActivityDisplays.valueAt(displayNdx).mStacks; @@ -2107,19 +2099,19 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds()); task.updateOverrideConfiguration(bounds); - int stackId = getLaunchStackId(null, options, task); + ActivityStack stack = getLaunchStack(null, options, task, ON_TOP); - if (stackId != currentStack.mStackId) { - task.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE, - DEFER_RESUME, "findTaskToMoveToFrontLocked"); - stackId = currentStack.mStackId; + if (stack != currentStack) { + task.reparent(stack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE, DEFER_RESUME, + "findTaskToMoveToFrontLocked"); + stack = currentStack; // moveTaskToStackUncheckedLocked() should already placed the task on top, // still need moveTaskToFrontLocked() below for any transition settings. } - if (StackId.resizeStackWithLaunchBounds(stackId)) { - resizeStackLocked(stackId, bounds, - null /* tempTaskBounds */, null /* tempTaskInsetBounds */, - !PRESERVE_WINDOWS, true /* allowResizeInDockedMode */, !DEFER_RESUME); + if (StackId.resizeStackWithLaunchBounds(stack.mStackId)) { + resizeStackLocked(stack.mStackId, bounds, null /* tempTaskBounds */, + null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS, + true /* allowResizeInDockedMode */, !DEFER_RESUME); } else { // WM resizeTask must be done after the task is moved to the correct stack, // because Task's setBounds() also updates dim layer's bounds, but that has @@ -2160,25 +2152,46 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return null; } - protected T getStack(int stackId, boolean createStaticStackIfNeeded, - boolean createOnTop) { - final ActivityStack stack = getStack(stackId); - if (stack != null) { - return (T) stack; + /** + * Returns true if the {@param windowingMode} is supported based on other parameters passed in. + * @param windowingMode The windowing mode we are checking support for. + * @param supportsMultiWindow If we should consider support for multi-window mode in general. + * @param supportsSplitScreen If we should consider support for split-screen multi-window. + * @param supportsFreeform If we should consider support for freeform multi-window. + * @param supportsPip If we should consider support for picture-in-picture mutli-window. + * @param activityType The activity type under consideration. + * @return true if the windowing mode is supported. + */ + boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow, + boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip, + int activityType) { + + if (windowingMode == WINDOWING_MODE_UNDEFINED + || windowingMode == WINDOWING_MODE_FULLSCREEN) { + return true; } - if (!createStaticStackIfNeeded || !StackId.isStaticStack(stackId)) { - return null; + if (!supportsMultiWindow) { + return false; } - if (stackId == DOCKED_STACK_ID) { - // Make sure recents stack exist when creating a dock stack as it normally need to be on - // the other side of the docked stack and we make visibility decisions based on that. - getStack(RECENTS_STACK_ID, CREATE_IF_NEEDED, createOnTop); + + if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY + || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) { + return supportsSplitScreen && WindowConfiguration.supportSplitScreenWindowingMode( + windowingMode, activityType); } - return (T) createStackOnDisplay(stackId, DEFAULT_DISPLAY, createOnTop); + + if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) { + return false; + } + + if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) { + return false; + } + return true; } private int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options, - @Nullable TaskRecord task) { + @Nullable TaskRecord task, int activityType) { // First preference if the windowing mode in the activity options if set. int windowingMode = (options != null) @@ -2196,47 +2209,47 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } // Make sure the windowing mode we are trying to use makes sense for what is supported. - if (!mService.mSupportsMultiWindow && windowingMode != WINDOWING_MODE_FULLSCREEN) { - windowingMode = WINDOWING_MODE_FULLSCREEN; + boolean supportsMultiWindow = mService.mSupportsMultiWindow; + boolean supportsSplitScreen = mService.mSupportsSplitScreenMultiWindow; + boolean supportsFreeform = mService.mSupportsFreeformWindowManagement; + boolean supportsPip = mService.mSupportsPictureInPicture; + if (supportsMultiWindow) { + if (task != null) { + supportsMultiWindow = task.isResizeable(); + supportsSplitScreen = task.supportsSplitScreenWindowingMode(); + // TODO: Do we need to check for freeform and Pip support here? + } else if (r != null) { + supportsMultiWindow = r.isResizeable(); + supportsSplitScreen = r.supportsSplitScreenWindowingMode(); + supportsFreeform = r.supportsFreeform(); + supportsPip = r.supportsPictureInPicture(); + } } - if (!mService.mSupportsSplitScreenMultiWindow - && (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY - || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)) { - windowingMode = WINDOWING_MODE_FULLSCREEN; + if (isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen, + supportsFreeform, supportsPip, activityType)) { + return windowingMode; } - - if (windowingMode == WINDOWING_MODE_FREEFORM - && !mService.mSupportsFreeformWindowManagement) { - windowingMode = WINDOWING_MODE_FULLSCREEN; - } - - return windowingMode; + return WINDOWING_MODE_FULLSCREEN; } - private int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options, + int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord task) { - // First preference if the activity type in the activity options if set. - int activityType = (options != null) - ? options.getLaunchActivityType() : ACTIVITY_TYPE_UNDEFINED; - + // Preference is given to the activity type for the activity then the task since the type + // once set shouldn't change. + int activityType = r != null ? r.getActivityType() : ACTIVITY_TYPE_UNDEFINED; + if (activityType == ACTIVITY_TYPE_UNDEFINED && task != null) { + activityType = task.getActivityType(); + } if (activityType != ACTIVITY_TYPE_UNDEFINED) { return activityType; } - - // If activity type is unset, then next preference is the task, then the activity record. - if (task != null) { - activityType = task.getActivityType(); - } - if (activityType == ACTIVITY_TYPE_UNDEFINED && r != null) { - activityType = r.getActivityType(); - } - return activityType; + return options != null ? options.getLaunchActivityType() : ACTIVITY_TYPE_UNDEFINED; } - int getLaunchStackId(@Nullable ActivityRecord r, @Nullable ActivityOptions options, - @Nullable TaskRecord candidateTask) { - return getLaunchStackId(r, options, candidateTask, INVALID_DISPLAY); + T getLaunchStack(@Nullable ActivityRecord r, + @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop) { + return getLaunchStack(r, options, candidateTask, onTop, INVALID_DISPLAY); } /** @@ -2248,8 +2261,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D * * @return The stack to use for the launch or INVALID_STACK_ID. */ - int getLaunchStackId(@Nullable ActivityRecord r, @Nullable ActivityOptions options, - @Nullable TaskRecord candidateTask, int candidateDisplayId) { + T getLaunchStack(@Nullable ActivityRecord r, + @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop, + int candidateDisplayId) { int taskId = INVALID_TASK_ID; int displayId = INVALID_DISPLAY; //Rect bounds = null; @@ -2271,13 +2285,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, options); options.setLaunchTaskId(taskId); if (task != null) { - return task.getStack().mStackId; + return task.getStack(); } } - final int windowingMode = resolveWindowingMode(r, options, candidateTask); final int activityType = resolveActivityType(r, options, candidateTask); - ActivityStack stack = null; + int windowingMode = resolveWindowingMode(r, options, candidateTask, activityType); + T stack = null; // Next preference for stack goes to the display Id set in the activity options or the // candidate display. @@ -2287,18 +2301,17 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D if (displayId != INVALID_DISPLAY) { if (r != null) { // TODO: This should also take in the windowing mode and activity type into account. - stack = getValidLaunchStackOnDisplay(displayId, r); + stack = (T) getValidLaunchStackOnDisplay(displayId, r); if (stack != null) { - return stack.mStackId; + return stack; } } final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId); if (display != null) { for (int i = display.mStacks.size() - 1; i >= 0; --i) { - stack = display.mStacks.get(i); - if (stack.getWindowingMode() == windowingMode - && stack.getActivityType() == activityType) { - return stack.mStackId; + stack = (T) display.mStacks.get(i); + if (stack.isCompatible(windowingMode, activityType)) { + return stack; } } // TODO: We should create the stack we want on the display at this point. @@ -2307,6 +2320,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Give preference to the stack and display of the input task and activity if they match the // mode we want to launch into. + stack = null; + ActivityDisplay display = null; if (candidateTask != null) { stack = candidateTask.getStack(); } @@ -2314,40 +2329,33 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D stack = r.getStack(); } if (stack != null) { - if (stack.getWindowingMode() == windowingMode - && stack.getActivityType() == activityType) { - return stack.mStackId; - } - ActivityDisplay display = stack.getDisplay(); - - if (display != null) { - for (int i = display.mStacks.size() - 1; i >= 0; --i) { - stack = display.mStacks.get(i); - if (stack.getWindowingMode() == windowingMode - && stack.getActivityType() == activityType) { - return stack.mStackId; - } - } + if (stack.isCompatible(windowingMode, activityType)) { + return stack; } + display = stack.getDisplay(); } - // Give preference to the type of activity we are trying to launch followed by the windowing - // mode. - int stackId = getStackIdForActivityType(activityType); - if (stackId != INVALID_STACK_ID) { - return stackId; + if (display == null + // TODO: Can be removed once we figure-out how non-standard types should launch + // outside the default display. + || (activityType != ACTIVITY_TYPE_STANDARD + && activityType != ACTIVITY_TYPE_UNDEFINED)) { + display = getDefaultDisplay(); } - stackId = getStackIdForWindowingMode(windowingMode); - if (stackId != INVALID_STACK_ID) { - return stackId; + + stack = display.getOrCreateStack(windowingMode, activityType, onTop); + if (stack != null) { + return stack; } // Whatever...return some default for now. if (candidateTask != null && candidateTask.mBounds != null && mService.mSupportsFreeformWindowManagement) { - return FREEFORM_WORKSPACE_STACK_ID; + windowingMode = WINDOWING_MODE_FREEFORM; + } else { + windowingMode = WINDOWING_MODE_FULLSCREEN; } - return FULLSCREEN_WORKSPACE_STACK_ID; + return display.getOrCreateStack(windowingMode, activityType, onTop); } /** @@ -2364,6 +2372,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D "Display with displayId=" + displayId + " not found."); } + if (!r.canBeLaunchedOnDisplay(displayId)) { + return null; + } + // Return the topmost valid stack on the display. for (int i = activityDisplay.mStacks.size() - 1; i >= 0; --i) { final ActivityStack stack = activityDisplay.mStacks.get(i); @@ -2373,11 +2385,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } // If there is no valid stack on the external display - check if new dynamic stack will do. - if (displayId != Display.DEFAULT_DISPLAY) { - final int newDynamicStackId = getNextStackId(); - if (isValidLaunchStackId(newDynamicStackId, displayId, r)) { - return createStackOnDisplay(newDynamicStackId, displayId, true /*onTop*/); - } + if (displayId != DEFAULT_DISPLAY) { + return activityDisplay.createStack( + r.getWindowingMode(), r.getActivityType(), true /*onTop*/); } Slog.w(TAG, "getValidLaunchStackOnDisplay: can't launch on displayId " + displayId); @@ -2394,7 +2404,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D case FREEFORM_WORKSPACE_STACK_ID: return r.supportsFreeform(); case DOCKED_STACK_ID: - return r.supportsSplitScreen(); + return r.supportsSplitScreenWindowingMode(); case PINNED_STACK_ID: return r.supportsPictureInPicture(); case RECENTS_STACK_ID: @@ -2440,7 +2450,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final List stacks = getActivityDisplayOrCreateLocked(displayId).mStacks; for (int j = stacks.size() - 1; j >= 0; --j) { final ActivityStack stack = stacks.get(j); - if (stack != currentFocus && stack.isFocusable() && stack.shouldBeVisible(null)) { + if (stack != currentFocus && stack.isFocusable() + && stack.shouldBeVisible(null)) { return stack; } } @@ -2509,7 +2520,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return; } - final boolean splitScreenActive = getStack(DOCKED_STACK_ID) != null; + final boolean splitScreenActive = getDefaultDisplay().hasSplitScreenStack(); if (!allowResizeInDockedMode && !stack.getWindowConfiguration().tasksAreFloating() && splitScreenActive) { // If the docked stack exists, don't resize non-floating stacks independently of the @@ -2520,7 +2531,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId); mWindowManager.deferSurfaceLayout(); try { - if (stack.supportSplitScreenWindowingMode()) { + if (stack.supportsSplitScreenWindowingMode()) { if (bounds == null && stack.inSplitScreenWindowingMode()) { // null bounds = fullscreen windowing mode...at least for now. stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN); @@ -2567,25 +2578,31 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mResizingTasksDuringAnimation.clear(); } + /** + * TODO: This should just change the windowing mode and resize vs. actually moving task around. + * Can do that once we are no longer using static stack ids. Specially when + * {@link ActivityManager.StackId#FULLSCREEN_WORKSPACE_STACK_ID} is removed. + */ private void moveTasksToFullscreenStackInSurfaceTransaction(ActivityStack fromStack, - boolean onTop) { + int toDisplayId, boolean onTop) { mWindowManager.deferSurfaceLayout(); try { - final int fromStackId = fromStack.mStackId; - if (fromStackId == DOCKED_STACK_ID) { + final int windowingMode = fromStack.getWindowingMode(); + final boolean inPinnedWindowingMode = windowingMode == WINDOWING_MODE_PINNED; + final ActivityDisplay toDisplay = getActivityDisplay(toDisplayId); + + if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { // We are moving all tasks from the docked stack to the fullscreen stack, // which is dismissing the docked stack, so resize all other stacks to // fullscreen here already so we don't end up with resize trashing. - for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) { - final ActivityStack otherStack = getStack(i); - if (otherStack == null) { - continue; - } + final ArrayList displayStacks = toDisplay.mStacks; + for (int i = displayStacks.size() - 1; i >= 0; --i) { + final ActivityStack otherStack = displayStacks.get(i); if (!otherStack.inSplitScreenSecondaryWindowingMode()) { continue; } - resizeStackLocked(i, null, null, null, PRESERVE_WINDOWS, + resizeStackLocked(otherStack.mStackId, null, null, null, PRESERVE_WINDOWS, true /* allowResizeInDockedMode */, DEFER_RESUME); } @@ -2594,35 +2611,35 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // resize when we remove task from it below and it is detached from the // display because it no longer contains any tasks. mAllowDockedStackResize = false; - } else if (fromStackId == PINNED_STACK_ID) { - if (onTop) { - // Log if we are expanding the PiP to fullscreen - MetricsLogger.action(mService.mContext, - ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN); - } + } else if (inPinnedWindowingMode && onTop) { + // Log if we are expanding the PiP to fullscreen + MetricsLogger.action(mService.mContext, + ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN); } - ActivityStack fullscreenStack = getStack(FULLSCREEN_WORKSPACE_STACK_ID); - final boolean isFullscreenStackVisible = fullscreenStack != null - && fullscreenStack.shouldBeVisible(null); + // If we are moving from the pinned stack, then the animation takes care of updating // the picture-in-picture mode. - final boolean schedulePictureInPictureModeChange = (fromStackId == PINNED_STACK_ID); + final boolean schedulePictureInPictureModeChange = inPinnedWindowingMode; final ArrayList tasks = fromStack.getAllTasks(); final int size = tasks.size(); + final ActivityStack fullscreenStack = toDisplay.getOrCreateStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, onTop); + if (onTop) { + final int returnToType = + toDisplay.getTopVisibleStackActivityType(WINDOWING_MODE_PINNED); for (int i = 0; i < size; i++) { final TaskRecord task = tasks.get(i); final boolean isTopTask = i == (size - 1); - if (fromStackId == PINNED_STACK_ID) { + if (inPinnedWindowingMode) { // Update the return-to to reflect where the pinned stack task was moved // from so that we retain the stack that was previously visible if the // pinned stack is recreated. See moveActivityToPinnedStackLocked(). - task.setTaskToReturnTo(isFullscreenStackVisible ? - ACTIVITY_TYPE_STANDARD : ACTIVITY_TYPE_HOME); + task.setTaskToReturnTo(returnToType); } // Defer resume until all the tasks have been moved to the fullscreen stack - task.reparent(FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, - REPARENT_MOVE_STACK_TO_FRONT, isTopTask /* animate */, DEFER_RESUME, + task.reparent(fullscreenStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, + isTopTask /* animate */, DEFER_RESUME, schedulePictureInPictureModeChange, "moveTasksToFullscreenStack - onTop"); } @@ -2632,7 +2649,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Position the tasks in the fullscreen stack in order at the bottom of the // stack. Also defer resume until all the tasks have been moved to the // fullscreen stack. - task.reparent(FULLSCREEN_WORKSPACE_STACK_ID, i /* position */, + task.reparent(fullscreenStack, i /* position */, REPARENT_LEAVE_STACK_IN_PLACE, !ANIMATE, DEFER_RESUME, schedulePictureInPictureModeChange, "moveTasksToFullscreenStack - NOT_onTop"); @@ -2648,8 +2665,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } void moveTasksToFullscreenStackLocked(ActivityStack fromStack, boolean onTop) { - mWindowManager.inSurfaceTransaction( - () -> moveTasksToFullscreenStackInSurfaceTransaction(fromStack, onTop)); + moveTasksToFullscreenStackLocked(fromStack, DEFAULT_DISPLAY, onTop); + } + + void moveTasksToFullscreenStackLocked(ActivityStack fromStack, int toDisplayId, boolean onTop) { + mWindowManager.inSurfaceTransaction(() -> + moveTasksToFullscreenStackInSurfaceTransaction(fromStack, toDisplayId, onTop)); } void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds, @@ -2660,7 +2681,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D false /* deferResume */); } - void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds, + private void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds, Rect tempDockedTaskInsetBounds, Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds, boolean preserveWindows, boolean deferResume) { @@ -2669,7 +2690,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return; } - final ActivityStack stack = getStack(DOCKED_STACK_ID); + final ActivityStack stack = getDefaultDisplay().getStack( + WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED); if (stack == null) { Slog.w(TAG, "resizeDockedStackLocked: docked stack not found"); return; @@ -2698,13 +2720,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // static stacks need to be adjusted so they don't overlap with the docked stack. // We get the bounds to use from window manager which has been adjusted for any // screen controls and is also the same for all stacks. + final ArrayList stacks = getStacksOnDefaultDisplay(); final Rect otherTaskRect = new Rect(); - for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) { - if (i == DOCKED_STACK_ID) { + for (int i = stacks.size() - 1; i >= 0; --i) { + final ActivityStack current = stacks.get(i); + if (current.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { continue; } - final ActivityStack current = getStack(i); - if (current == null || !current.supportSplitScreenWindowingMode()) { + if (!current.supportsSplitScreenWindowingMode()) { continue; } // Need to set windowing mode here before we try to get the dock bounds. @@ -2714,7 +2737,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D tempRect /* outStackBounds */, otherTaskRect /* outTempTaskBounds */, true /* ignoreVisibility */); - resizeStackLocked(i, !tempRect.isEmpty() ? tempRect : null, + resizeStackLocked(current.mStackId, !tempRect.isEmpty() ? tempRect : null, !otherTaskRect.isEmpty() ? otherTaskRect : tempOtherTaskBounds, tempOtherTaskInsetBounds, preserveWindows, true /* allowResizeInDockedMode */, deferResume); @@ -2731,7 +2754,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } void resizePinnedStackLocked(Rect pinnedBounds, Rect tempPinnedTaskBounds) { - final PinnedActivityStack stack = getStack(PINNED_STACK_ID); + // TODO(multi-display): Pinned stack display should be passed in. + final PinnedActivityStack stack = getDefaultDisplay().getStack( + WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED); if (stack == null) { Slog.w(TAG, "resizePinnedStackLocked: pinned stack not found"); return; @@ -2769,32 +2794,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } - ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) { - final ActivityDisplay activityDisplay = getActivityDisplayOrCreateLocked(displayId); - if (activityDisplay == null) { - return null; - } - return createStack(stackId, activityDisplay, onTop); - - } - - ActivityStack createStack(int stackId, ActivityDisplay display, boolean onTop) { - switch (stackId) { - case PINNED_STACK_ID: - return new PinnedActivityStack(display, stackId, this, onTop); - default: - return new ActivityStack(display, stackId, this, onTop); - } - } - - void removeStackInSurfaceTransaction(int stackId) { + private void removeStackInSurfaceTransaction(int stackId) { final ActivityStack stack = getStack(stackId); if (stack == null) { return; } final ArrayList tasks = stack.getAllTasks(); - if (stack.getStackId() == PINNED_STACK_ID) { + if (stack.getWindowingMode() == WINDOWING_MODE_PINNED) { /** * Workaround: Force-stop all the activities in the pinned stack before we reparent them * to the fullscreen stack. This is to guarantee that when we are removing a stack, @@ -2827,8 +2834,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D * instead moved back onto the fullscreen stack. */ void removeStackLocked(int stackId) { - mWindowManager.inSurfaceTransaction( - () -> removeStackInSurfaceTransaction(stackId)); + mWindowManager.inSurfaceTransaction(() -> removeStackInSurfaceTransaction(stackId)); + } + + /** Removes all stacks in the input windowing mode from the system */ + void removeStacksInWindowingMode(int windowingMode) { + for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { + mActivityDisplays.valueAt(i).removeStacksInWindowingMode(windowingMode); + } } /** @@ -2966,11 +2979,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D * @return true if the task has been restored successfully. */ boolean restoreRecentTaskLocked(TaskRecord task, ActivityOptions aOptions) { - final int stackId = getLaunchStackId(null, aOptions, task); + final ActivityStack stack = getLaunchStack(null, aOptions, task, !ON_TOP); final ActivityStack currentStack = task.getStack(); if (currentStack != null) { // Task has already been restored once. See if we need to do anything more - if (currentStack.mStackId == stackId) { + if (currentStack == stack) { // Nothing else to do since it is already restored in the right stack. return true; } @@ -2979,11 +2992,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D currentStack.removeTask(task, "restoreRecentTaskLocked", REMOVE_TASK_MODE_MOVING); } - final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, !ON_TOP); - - stack.addTask(task, false /* toTop */, "restoreRecentTask"); + stack.addTask(task, !ON_TOP, "restoreRecentTask"); // TODO: move call for creation here and other place into Stack.addTask() - task.createWindowContainer(false /* toTop */, true /* showForAllUsers */); + task.createWindowContainer(!ON_TOP, true /* showForAllUsers */); if (DEBUG_RECENTS) Slog.v(TAG_RECENTS, "Added restored task=" + task + " to stack=" + stack); final ArrayList activities = task.mActivities; @@ -3030,8 +3041,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D * Returns the reparent target stack, creating the stack if necessary. This call also enforces * the various checks on tasks that are going to be reparented from one stack to another. */ - ActivityStack getReparentTargetStack(TaskRecord task, int stackId, boolean toTop) { + ActivityStack getReparentTargetStack(TaskRecord task, ActivityStack stack, boolean toTop) { final ActivityStack prevStack = task.getStack(); + final int stackId = stack.mStackId; + final boolean inMultiWindowMode = stack.inMultiWindowMode(); // Check that we aren't reparenting to the same stack that the task is already in if (prevStack != null && prevStack.mStackId == stackId) { @@ -3042,22 +3055,22 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Ensure that we aren't trying to move into a multi-window stack without multi-window // support - if (StackId.isMultiWindowStack(stackId) && !mService.mSupportsMultiWindow) { + if (inMultiWindowMode && !mService.mSupportsMultiWindow) { throw new IllegalArgumentException("Device doesn't support multi-window, can not" - + " reparent task=" + task + " to stackId=" + stackId); + + " reparent task=" + task + " to stack=" + stack); } // Ensure that we're not moving a task to a dynamic stack if device doesn't support // multi-display. - // TODO(multi-display): Support non-dynamic stacks on secondary displays. - if (StackId.isDynamicStack(stackId) && !mService.mSupportsMultiDisplay) { + if (stack.mDisplayId != DEFAULT_DISPLAY && !mService.mSupportsMultiDisplay) { throw new IllegalArgumentException("Device doesn't support multi-display, can not" + " reparent task=" + task + " to stackId=" + stackId); } // Ensure that we aren't trying to move into a freeform stack without freeform // support - if (stackId == FREEFORM_WORKSPACE_STACK_ID && !mService.mSupportsFreeformWindowManagement) { + if (stack.getWindowingMode() == WINDOWING_MODE_FREEFORM + && !mService.mSupportsFreeformWindowManagement) { throw new IllegalArgumentException("Device doesn't support freeform, can not reparent" + " task=" + task); } @@ -3066,25 +3079,25 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // used for split-screen mode and will cause things like the docked divider to show up. We // instead leave the task in its current stack or move it to the fullscreen stack if it // isn't currently in a stack. - if (stackId == DOCKED_STACK_ID && !task.isResizeable()) { - stackId = (prevStack != null) ? prevStack.mStackId : FULLSCREEN_WORKSPACE_STACK_ID; + if (inMultiWindowMode && !task.isResizeable()) { Slog.w(TAG, "Can not move unresizeable task=" + task + " to docked stack." + " Moving to stackId=" + stackId + " instead."); + // Temporarily disable resizeablility of the task as we don't want it to be resized if, + // for example, a docked stack is created which will lead to the stack we are moving + // from being resized and and its resizeable tasks being resized. + try { + task.mTemporarilyUnresizable = true; + stack = stack.getDisplay().createStack( + WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), toTop); + } finally { + task.mTemporarilyUnresizable = false; + } } - - // Temporarily disable resizeablility of the task as we don't want it to be resized if, for - // example, a docked stack is created which will lead to the stack we are moving from being - // resized and and its resizeable tasks being resized. - try { - task.mTemporarilyUnresizable = true; - return getStack(stackId, CREATE_IF_NEEDED, toTop); - } finally { - task.mTemporarilyUnresizable = false; - } + return stack; } boolean moveTopStackActivityToPinnedStackLocked(int stackId, Rect destBounds) { - final ActivityStack stack = getStack(stackId, !CREATE_IF_NEEDED, !ON_TOP); + final ActivityStack stack = getStack(stackId); if (stack == null) { throw new IllegalArgumentException( "moveTopStackActivityToPinnedStackLocked: Unknown stackId=" + stackId); @@ -3114,7 +3127,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mWindowManager.deferSurfaceLayout(); - PinnedActivityStack stack = getStack(PINNED_STACK_ID); + final ActivityDisplay display = r.getStack().getDisplay(); + PinnedActivityStack stack = display.getPinnedStack(); // This will clear the pinned stack by moving an existing task to the full screen stack, // ensuring only one task is present. @@ -3123,7 +3137,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } // Need to make sure the pinned stack exist so we can resize it below... - stack = getStack(PINNED_STACK_ID, CREATE_IF_NEEDED, ON_TOP); + stack = display.getOrCreateStack(WINDOWING_MODE_PINNED, r.getActivityType(), ON_TOP); try { final TaskRecord task = r.getTask(); @@ -3147,8 +3161,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D moveHomeStackToFront(reason); } // Defer resume until below, and do not schedule PiP changes until we animate below - task.reparent(PINNED_STACK_ID, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, !ANIMATE, - DEFER_RESUME, false /* schedulePictureInPictureModeChange */, reason); + task.reparent(stack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, !ANIMATE, DEFER_RESUME, + false /* schedulePictureInPictureModeChange */, reason); } else { // There are multiple activities in the task and moving the top activity should // reveal/leave the other activities in their original task. @@ -3163,7 +3177,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D r.reparent(newTask, MAX_VALUE, "moveActivityToStack"); // Defer resume until below, and do not schedule PiP changes until we animate below - newTask.reparent(PINNED_STACK_ID, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, !ANIMATE, + newTask.reparent(stack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, !ANIMATE, DEFER_RESUME, false /* schedulePictureInPictureModeChange */, reason); } @@ -3617,7 +3631,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean switchUserLocked(int userId, UserState uss) { final int focusStackId = mFocusedStack.getStackId(); // We dismiss the docked stack whenever we switch users. - final ActivityStack dockedStack = getStack(DOCKED_STACK_ID); + final ActivityStack dockedStack = getDefaultDisplay().getSplitScreenStack(); if (dockedStack != null) { moveTasksToFullscreenStackLocked(dockedStack, mFocusedStack == dockedStack); } @@ -4057,15 +4071,22 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return getActivityDisplayOrCreateLocked(displayId) != null; } + // TODO: Look into consolidating with getActivityDisplayOrCreateLocked() ActivityDisplay getActivityDisplay(int displayId) { return mActivityDisplays.get(displayId); } + // TODO(multi-display): Look at all callpoints to make sure they make sense in multi-display. + ActivityDisplay getDefaultDisplay() { + return mActivityDisplays.get(DEFAULT_DISPLAY); + } + /** * Get an existing instance of {@link ActivityDisplay} or create new if there is a * corresponding record in display manager. */ - private ActivityDisplay getActivityDisplayOrCreateLocked(int displayId) { + // TODO: Look into consolidating with getActivityDisplay() + ActivityDisplay getActivityDisplayOrCreateLocked(int displayId) { ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); if (activityDisplay != null) { return activityDisplay; @@ -4290,7 +4311,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } final ActivityRecord topActivity = task.getTopActivity(); - if (launchOnSecondaryDisplayFailed || !task.supportsSplitScreen() || forceNonResizable) { + if (launchOnSecondaryDisplayFailed + || !task.supportsSplitScreenWindowingMode() || forceNonResizable) { if (launchOnSecondaryDisplayFailed) { // Display a warning toast that we tried to put a non-resizeable task on a secondary // display with config different from global config. @@ -4304,7 +4326,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Dismiss docked stack. If task appeared to be in docked stack but is not resizable - // we need to move it to top of fullscreen stack, otherwise it will be covered. - final ActivityStack dockedStack = getStack(DOCKED_STACK_ID); + + final ActivityStack dockedStack = task.getStack().getDisplay().getSplitScreenStack(); if (dockedStack != null) { moveTasksToFullscreenStackLocked(dockedStack, actualStackId == dockedStack.getStackId()); @@ -4582,13 +4605,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Since we don't have an actual source record here, we assume that the currently // focused activity was the source. - final ActivityStack focusedStack = getFocusedStack(); - final ActivityRecord sourceRecord = focusedStack != null - ? focusedStack.topActivity() : null; - final int stackId = getLaunchStackId(null, activityOptions, task); + final ActivityStack stack = getLaunchStack(null, activityOptions, task, ON_TOP); - if (stackId != INVALID_STACK_ID && task.getStackId() != stackId) { - task.reparent(stackId, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME, + if (stack != null && task.getStack() != stack) { + task.reparent(stack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME, "startActivityFromRecents"); } @@ -4613,10 +4633,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } mService.mActivityStarter.postStartActivityProcessing(task.getTopActivity(), - ActivityManager.START_TASK_TO_FRONT, - sourceRecord != null - ? sourceRecord.getTask().getStackId() : INVALID_STACK_ID, - sourceRecord, task.getStack()); + ActivityManager.START_TASK_TO_FRONT, task.getStack()); return ActivityManager.START_TASK_TO_FRONT; } callingUid = task.mCallingUid; diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 1a2b46c9b9484..9bcba0d8a329f 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -31,14 +31,15 @@ import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; -import static android.app.ActivityManager.StackId.RECENTS_STACK_ID; import static android.app.ActivityManager.StackId.isDynamicStack; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; @@ -77,7 +78,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.ActivityManagerService.ANIMATE; import static com.android.server.am.ActivityStack.ActivityState.RESUMED; -import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED; import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME; import static com.android.server.am.ActivityStackSupervisor.ON_TOP; import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; @@ -590,9 +590,7 @@ class ActivityStarter { auxiliaryResponse.token, auxiliaryResponse.needsPhaseTwo); } - void postStartActivityProcessing( - ActivityRecord r, int result, int prevFocusedStackId, ActivityRecord sourceRecord, - ActivityStack targetStack) { + void postStartActivityProcessing(ActivityRecord r, int result, ActivityStack targetStack) { if (ActivityManager.isStartResultFatalError(result)) { return; @@ -614,7 +612,8 @@ class ActivityStarter { } if (startedActivityStackId == DOCKED_STACK_ID) { - final ActivityStack homeStack = mSupervisor.getStack(HOME_STACK_ID); + final ActivityStack homeStack = mSupervisor.getDefaultDisplay().getStack( + WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME); final boolean homeStackVisible = homeStack != null && homeStack.isVisible(); if (homeStackVisible) { // We launch an activity while being in home stack, which means either launcher or @@ -1002,8 +1001,7 @@ class ActivityStarter { mService.mWindowManager.continueSurfaceLayout(); } - postStartActivityProcessing(r, result, mSupervisor.getLastStack().mStackId, mSourceRecord, - mTargetStack); + postStartActivityProcessing(r, result, mTargetStack); return result; } @@ -1612,12 +1610,11 @@ class ActivityStarter { mTargetStack.moveTaskToFrontLocked(intentTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "bringingFoundTaskToFront"); mMovedToFront = true; - } else if (launchStack.mStackId == DOCKED_STACK_ID - || launchStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) { + } else if (launchStack.inSplitScreenWindowingMode()) { if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) { // If we want to launch adjacent and mTargetStack is not the computed // launch stack - move task to top of computed stack. - intentTask.reparent(launchStack.mStackId, ON_TOP, + intentTask.reparent(launchStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME, "launchToSide"); } else { @@ -1634,17 +1631,17 @@ class ActivityStarter { // Target and computed stacks are on different displays and we've // found a matching task - move the existing instance to that display and // move it to front. - intentActivity.getTask().reparent(launchStack.mStackId, ON_TOP, + intentActivity.getTask().reparent(launchStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME, "reparentToDisplay"); mMovedToFront = true; - } else if (launchStack.getStackId() == StackId.HOME_STACK_ID - && mTargetStack.getStackId() != StackId.HOME_STACK_ID) { + } else if (launchStack.isActivityTypeHome() + && !mTargetStack.isActivityTypeHome()) { // It is possible for the home activity to be in another stack initially. // For example, the activity may have been initially started with an intent // which placed it in the fullscreen stack. To ensure the proper handling of // the activity based on home stack assumptions, we must move it over. - intentActivity.getTask().reparent(launchStack.mStackId, ON_TOP, + intentActivity.getTask().reparent(launchStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME, "reparentingHome"); mMovedToFront = true; @@ -1879,8 +1876,8 @@ class ActivityStarter { if (mTargetStack == null) { mTargetStack = sourceStack; } else if (mTargetStack != sourceStack) { - sourceTask.reparent(mTargetStack.mStackId, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, - !ANIMATE, DEFER_RESUME, "launchToSide"); + sourceTask.reparent(mTargetStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, !ANIMATE, + DEFER_RESUME, "launchToSide"); } final TaskRecord topTask = mTargetStack.topTask(); @@ -1977,15 +1974,16 @@ class ActivityStarter { if (mLaunchBounds != null) { mInTask.updateOverrideConfiguration(mLaunchBounds); // TODO: Shouldn't we already know what stack to use by the time we get here? - int stackId = mSupervisor.getLaunchStackId(null, null, mInTask); - if (stackId != mInTask.getStackId()) { - mInTask.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE, + ActivityStack stack = mSupervisor.getLaunchStack(null, null, mInTask, ON_TOP); + if (stack != mInTask.getStack()) { + mInTask.reparent(stack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE, DEFER_RESUME, "inTaskToFront"); - stackId = mInTask.getStackId(); + stack = mInTask.getStack(); mTargetStack = mInTask.getStack(); } - if (StackId.resizeStackWithLaunchBounds(stackId)) { - mService.resizeStack(stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1); + if (StackId.resizeStackWithLaunchBounds(stack.mStackId)) { + mService.resizeStack( + stack.mStackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1); } } @@ -2116,11 +2114,7 @@ class ActivityStarter { } } // If there is no suitable dynamic stack then we figure out which static stack to use. - final int stackId = task != null ? mSupervisor.getLaunchStackId(r, aOptions, task) - // TODO: This should go in mSupervisor.getLaunchStackId method... - : bounds != null && mService.mSupportsFreeformWindowManagement - ? FREEFORM_WORKSPACE_STACK_ID : FULLSCREEN_WORKSPACE_STACK_ID; - stack = mSupervisor.getStack(stackId, CREATE_IF_NEEDED, ON_TOP); + stack = mSupervisor.getLaunchStack(r, aOptions, task, ON_TOP); } if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r=" + r + " stackId=" + stack.mStackId); @@ -2143,7 +2137,7 @@ class ActivityStarter { break; case DOCKED_STACK_ID: // Any activity which supports split screen can go in the docked stack. - canUseFocusedStack = r.supportsSplitScreen(); + canUseFocusedStack = r.supportsSplitScreenWindowingMode(); break; case FREEFORM_WORKSPACE_STACK_ID: // Any activity which supports freeform can go in the freeform stack. @@ -2168,50 +2162,12 @@ class ActivityStarter { return mReuseTask.getStack(); } - // If the activity is of a specific type, return the associated stack, creating it if - // necessary - if (r.isActivityTypeHome()) { - return mSupervisor.mHomeStack; - } - if (r.isActivityTypeRecents()) { - return mSupervisor.getStack(RECENTS_STACK_ID, CREATE_IF_NEEDED, ON_TOP); - } - if (r.isActivityTypeAssistant()) { - return mSupervisor.getStack(ASSISTANT_STACK_ID, CREATE_IF_NEEDED, ON_TOP); - } + final int vrDisplayId = mUsingVr2dDisplay ? mPreferredDisplayId : INVALID_DISPLAY; + final ActivityStack launchStack = mSupervisor.getLaunchStack(r, aOptions, task, ON_TOP, + vrDisplayId); - int launchDisplayId = INVALID_DISPLAY; - int launchStackId = INVALID_STACK_ID; - if (aOptions != null) { - launchDisplayId = aOptions.getLaunchDisplayId(); - final int vrDisplayId = mUsingVr2dDisplay ? mPreferredDisplayId : INVALID_DISPLAY; - launchStackId = mSupervisor.getLaunchStackId(r, aOptions, task, vrDisplayId); - } - - // TODO: Will no longer be needed once we are on longer using static stack ids. - if (mSupervisor.isValidLaunchStackId(launchStackId, launchDisplayId, r)) { - return mSupervisor.getStack(launchStackId, CREATE_IF_NEEDED, ON_TOP); - } - if (launchStackId == DOCKED_STACK_ID) { - // The preferred launch stack is the docked stack, but it isn't a valid launch stack - // for this activity, so we put the activity in the fullscreen stack. - return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP); - } - // TODO: Can probably be removed since ASS.getLaunchStackId() does display resolution. - if (launchDisplayId != INVALID_DISPLAY) { - // Stack id has higher priority than display id. - return mSupervisor.getValidLaunchStackOnDisplay(launchDisplayId, r); - } - - // If we are using Vr2d display, find the virtual display stack. - // TODO: Can be removed. - if (mUsingVr2dDisplay) { - ActivityStack as = mSupervisor.getValidLaunchStackOnDisplay(mPreferredDisplayId, r); - if (DEBUG_STACK) { - Slog.v(TAG, "Launch stack for app: " + r.toString() + - ", on virtual display stack:" + as.toString()); - } - return as; + if (launchStack != null) { + return launchStack; } if (((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0) @@ -2237,13 +2193,15 @@ class ActivityStarter { if (parentStack != null && parentStack.isDockedStack()) { // If parent was in docked stack, the natural place to launch another activity // will be fullscreen, so it can appear alongside the docked window. - return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, - ON_TOP); + final int activityType = mSupervisor.resolveActivityType(r, mOptions, task); + return parentStack.getDisplay().getOrCreateStack( + WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, activityType, ON_TOP); } else { // If the parent is not in the docked stack, we check if there is docked window // and if yes, we will launch into that stack. If not, we just put the new // activity into parent's stack, because we can't find a better place. - final ActivityStack dockedStack = mSupervisor.getStack(DOCKED_STACK_ID); + final ActivityStack dockedStack = mSupervisor.getDefaultDisplay().getStack( + WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED); if (dockedStack != null && !dockedStack.shouldBeVisible(r)) { // There is a docked stack, but it isn't visible, so we can't launch into that. return null; @@ -2267,15 +2225,6 @@ class ActivityStarter { mWindowManager = wm; } - void removePendingActivityLaunchesLocked(ActivityStack stack) { - for (int palNdx = mPendingActivityLaunches.size() - 1; palNdx >= 0; --palNdx) { - PendingActivityLaunch pal = mPendingActivityLaunches.get(palNdx); - if (pal.stack == stack) { - mPendingActivityLaunches.remove(palNdx); - } - } - } - static boolean isDocumentLaunchesIntoExisting(int flags) { return (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && (flags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0; diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java index 7101fc4eb93c8..5c48f90df1890 100644 --- a/services/core/java/com/android/server/am/KeyguardController.java +++ b/services/core/java/com/android/server/am/KeyguardController.java @@ -342,7 +342,7 @@ class KeyguardController { // show on top of the lock screen. In this can we want to dismiss the docked // stack since it will be complicated/risky to try to put the activity on top // of the lock screen in the right fullscreen configuration. - final ActivityStack stack = mStackSupervisor.getStack(DOCKED_STACK_ID); + final ActivityStack stack = mStackSupervisor.getDefaultDisplay().getSplitScreenStack(); if (stack == null) { return; } diff --git a/services/core/java/com/android/server/am/PinnedActivityStack.java b/services/core/java/com/android/server/am/PinnedActivityStack.java index 33f56644a3f64..468b86720f2fb 100644 --- a/services/core/java/com/android/server/am/PinnedActivityStack.java +++ b/services/core/java/com/android/server/am/PinnedActivityStack.java @@ -16,6 +16,9 @@ package com.android.server.am; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; + import android.app.RemoteAction; import android.content.res.Configuration; import android.graphics.Rect; @@ -34,7 +37,7 @@ class PinnedActivityStack extends ActivityStack PinnedActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor, boolean onTop) { - super(display, stackId, supervisor, onTop); + super(display, stackId, supervisor, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, onTop); } @Override diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index fb8b034ab0646..0d8df7968e963 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -18,20 +18,19 @@ package com.android.server.am; import static android.app.ActivityManager.RESIZE_MODE_FORCED; import static android.app.ActivityManager.RESIZE_MODE_SYSTEM; -import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID; -import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; -import static android.app.ActivityManager.StackId.RECENTS_STACK_ID; -import static android.app.ActivityManager.StackId.getWindowingModeForStackId; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY; @@ -573,36 +572,36 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi /** * Convenience method to reparent a task to the top or bottom position of the stack. */ - boolean reparent(int preferredStackId, boolean toTop, @ReparentMoveStackMode int moveStackMode, - boolean animate, boolean deferResume, String reason) { - return reparent(preferredStackId, toTop ? MAX_VALUE : 0, moveStackMode, animate, - deferResume, true /* schedulePictureInPictureModeChange */, reason); + boolean reparent(ActivityStack preferredStack, boolean toTop, + @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, + String reason) { + return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, deferResume, + true /* schedulePictureInPictureModeChange */, reason); } /** * Convenience method to reparent a task to the top or bottom position of the stack, with * an option to skip scheduling the picture-in-picture mode change. */ - boolean reparent(int preferredStackId, boolean toTop, @ReparentMoveStackMode int moveStackMode, - boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange, - String reason) { - return reparent(preferredStackId, toTop ? MAX_VALUE : 0, moveStackMode, animate, + boolean reparent(ActivityStack preferredStack, boolean toTop, + @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, + boolean schedulePictureInPictureModeChange, String reason) { + return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, deferResume, schedulePictureInPictureModeChange, reason); } - /** - * Convenience method to reparent a task to a specific position of the stack. - */ - boolean reparent(int preferredStackId, int position, @ReparentMoveStackMode int moveStackMode, - boolean animate, boolean deferResume, String reason) { - return reparent(preferredStackId, position, moveStackMode, animate, deferResume, + /** Convenience method to reparent a task to a specific position of the stack. */ + boolean reparent(ActivityStack preferredStack, int position, + @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, + String reason) { + return reparent(preferredStack, position, moveStackMode, animate, deferResume, true /* schedulePictureInPictureModeChange */, reason); } /** * Reparents the task into a preferred stack, creating it if necessary. * - * @param preferredStackId the stack id of the target stack to move this task + * @param preferredStack the target stack to move this task * @param position the position to place this task in the new stack * @param animate whether or not we should wait for the new window created as a part of the * reparenting to be drawn and animated in @@ -616,13 +615,16 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi * @param reason the caller of this reparenting * @return whether the task was reparented */ - boolean reparent(int preferredStackId, int position, @ReparentMoveStackMode int moveStackMode, - boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange, - String reason) { + // TODO: Inspect all call sites and change to just changing windowing mode of the stack vs. + // re-parenting the task. Can only be done when we are no longer using static stack Ids like + /** {@link ActivityManager.StackId#FULLSCREEN_WORKSPACE_STACK_ID} */ + boolean reparent(ActivityStack preferredStack, int position, + @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, + boolean schedulePictureInPictureModeChange, String reason) { final ActivityStackSupervisor supervisor = mService.mStackSupervisor; final WindowManagerService windowManager = mService.mWindowManager; final ActivityStack sourceStack = getStack(); - final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStackId, + final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStack, position == MAX_VALUE); if (toStack == sourceStack) { return false; @@ -705,19 +707,22 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi toStack.prepareFreezingTaskBounds(); // Make sure the task has the appropriate bounds/size for the stack it is in. + final int toStackWindowingMode = toStack.getWindowingMode(); + final boolean toStackSplitScreenPrimary = + toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && !Objects.equals(mBounds, toStack.mBounds)) { kept = resize(toStack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow, deferResume); - } else if (stackId == FREEFORM_WORKSPACE_STACK_ID) { + } else if (toStackWindowingMode == WINDOWING_MODE_FREEFORM) { Rect bounds = getLaunchBounds(); if (bounds == null) { toStack.layoutTaskInStack(this, null); bounds = mBounds; } kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume); - } else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) { - if (stackId == DOCKED_STACK_ID && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) { + } else if (toStackSplitScreenPrimary || toStackWindowingMode == WINDOWING_MODE_PINNED) { + if (toStackSplitScreenPrimary && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) { // Move recents to front so it is not behind home stack when going into docked // mode mService.mStackSupervisor.moveRecentsStackToFront(reason); @@ -744,11 +749,12 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi } // TODO: Handle incorrect request to move before the actual move, not after. - supervisor.handleNonResizableTaskIfNeeded(this, getWindowingModeForStackId(preferredStackId, - supervisor.getStack(DOCKED_STACK_ID) != null), DEFAULT_DISPLAY, stackId); + final boolean inSplitScreenMode = supervisor.getDefaultDisplay().hasSplitScreenStack(); + supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(), + DEFAULT_DISPLAY, stackId); - boolean successful = (preferredStackId == stackId); - if (successful && stackId == DOCKED_STACK_ID) { + boolean successful = (preferredStack == toStack); + if (successful && toStack.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { // If task moved to docked stack - show recents if needed. mService.mWindowManager.showRecentApps(false /* fromHome */); } @@ -941,8 +947,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.taskId; } - ActivityStack getStack() { - return mStack; + T getStack() { + return (T) mStack; } /** @@ -1457,10 +1463,12 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi return isResizeable(true /* checkSupportsPip */); } - boolean supportsSplitScreen() { + @Override + public boolean supportsSplitScreenWindowingMode() { // A task can not be docked even if it is considered resizeable because it only supports // picture-in-picture mode but has a non-resizeable resizeMode - return mService.mSupportsSplitScreenMultiWindow + return super.supportsSplitScreenWindowingMode() + && mService.mSupportsSplitScreenMultiWindow && (mService.mForceResizableActivities || (isResizeable(false /* checkSupportsPip */) && !ActivityInfo.isPreserveOrientationMode(mResizeMode))); @@ -2101,12 +2109,10 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi return null; } - final int stackId = mStack.mStackId; - if (stackId == HOME_STACK_ID - || stackId == RECENTS_STACK_ID - || stackId == ASSISTANT_STACK_ID - || stackId == FULLSCREEN_WORKSPACE_STACK_ID - || (stackId == DOCKED_STACK_ID && !isResizeable())) { + final int windowingMode = getWindowingMode(); + if (!isActivityTypeStandardOrUndefined() + || windowingMode == WINDOWING_MODE_FULLSCREEN + || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) { return isResizeable() ? mStack.mBounds : null; } else if (!getWindowConfiguration().persistTaskBounds()) { return mStack.mBounds; diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java index dc5a81443b965..9e028d38a220e 100644 --- a/services/core/java/com/android/server/wm/ConfigurationContainer.java +++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java @@ -21,8 +21,10 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.activityTypeToString; import static com.android.server.wm.proto.ConfigurationContainerProto.FULL_CONFIGURATION; import static com.android.server.wm.proto.ConfigurationContainerProto.MERGED_OVERRIDE_CONFIGURATION; @@ -152,6 +154,17 @@ public abstract class ConfigurationContainer { onOverrideConfigurationChanged(mTmpConfig); } + /** + * Returns true if this container is currently in multi-window mode. I.e. sharing the screen + * with another activity. + */ + public boolean inMultiWindowMode() { + /*@WindowConfiguration.WindowingMode*/ int windowingMode = + mFullConfiguration.windowConfiguration.getWindowingMode(); + return windowingMode != WINDOWING_MODE_FULLSCREEN + && windowingMode != WINDOWING_MODE_UNDEFINED; + } + /** Returns true if this container is currently in split-screen windowing mode. */ public boolean inSplitScreenWindowingMode() { /*@WindowConfiguration.WindowingMode*/ int windowingMode = @@ -175,7 +188,7 @@ public abstract class ConfigurationContainer { * {@link WindowConfiguration##WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} windowing modes based on * its current state. */ - public boolean supportSplitScreenWindowingMode() { + public boolean supportsSplitScreenWindowingMode() { return mFullConfiguration.windowConfiguration.supportSplitScreenWindowingMode(); } @@ -238,6 +251,16 @@ public abstract class ConfigurationContainer { /** * Returns true if this container is compatible with the input windowing mode and activity type. + * The container is compatible: + * - If {@param activityType} and {@param windowingMode} match this container activity type and + * windowing mode. + * - If {@param activityType} is {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} or + * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} and this containers activity type is also + * standard or undefined and its windowing mode matches {@param windowingMode}. + * - If {@param activityType} isn't {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} or + * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} or this containers activity type isn't + * also standard or undefined and its activity type matches {@param activityType} regardless of + * if {@param windowingMode} matches the containers windowing mode. */ public boolean isCompatible(int windowingMode, int activityType) { final int thisActivityType = getActivityType(); @@ -249,7 +272,8 @@ public abstract class ConfigurationContainer { return true; } - if (activityType != ACTIVITY_TYPE_UNDEFINED && activityType != ACTIVITY_TYPE_STANDARD) { + if ((activityType != ACTIVITY_TYPE_UNDEFINED && activityType != ACTIVITY_TYPE_STANDARD) + || !isActivityTypeStandardOrUndefined()) { // Only activity type need to match for non-standard activity types that are defined. return sameActivityType; } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java index 526f81572b07f..679be1d40b60b 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java @@ -16,9 +16,15 @@ package com.android.server.am; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; +import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManagerPolicy.NAV_BAR_BOTTOM; import static android.view.WindowManagerPolicy.NAV_BAR_LEFT; import static android.view.WindowManagerPolicy.NAV_BAR_RIGHT; +import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -26,14 +32,13 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.when; import android.content.ComponentName; -import android.content.pm.ActivityInfo; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.support.test.filters.MediumTest; import android.support.test.runner.AndroidJUnit4; -import android.view.Display; import org.junit.runner.RunWith; +import org.junit.Before; import org.junit.Test; /** @@ -46,64 +51,53 @@ import org.junit.Test; @Presubmit @RunWith(AndroidJUnit4.class) public class ActivityRecordTests extends ActivityTestsBase { - private static final int TEST_STACK_ID = 100; - private final ComponentName testActivityComponent = ComponentName.unflattenFromString("com.foo/.BarActivity"); private final ComponentName secondaryActivityComponent = ComponentName.unflattenFromString("com.foo/.BarActivity2"); + + private ActivityManagerService mService; + private ActivityStack mStack; + private TaskRecord mTask; + private ActivityRecord mActivity; + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + + mService = createActivityManagerService(); + mStack = mService.mStackSupervisor.getDefaultDisplay().createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + mTask = createTask(mService.mStackSupervisor, testActivityComponent, mStack); + mActivity = createActivity(mService, testActivityComponent, mTask); + } + @Test public void testStackCleanupOnClearingTask() throws Exception { - final ActivityManagerService service = createActivityManagerService(); - final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); - final ActivityRecord record = createActivity(service, testActivityComponent, task); - - record.setTask(null); - assertEquals(getActivityRemovedFromStackCount(service, TEST_STACK_ID), 1); + mActivity.setTask(null); + assertEquals(getActivityRemovedFromStackCount(), 1); } @Test public void testStackCleanupOnActivityRemoval() throws Exception { - final ActivityManagerService service = createActivityManagerService(); - final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); - final ActivityRecord record = createActivity(service, testActivityComponent, task); - - task.removeActivity(record); - assertEquals(getActivityRemovedFromStackCount(service, TEST_STACK_ID), 1); + mTask.removeActivity(mActivity); + assertEquals(getActivityRemovedFromStackCount(), 1); } @Test public void testStackCleanupOnTaskRemoval() throws Exception { - final ActivityManagerService service = createActivityManagerService(); - final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); - final ActivityRecord record = createActivity(service, testActivityComponent, task); - - service.mStackSupervisor.getStack(TEST_STACK_ID) - .removeTask(task, null /*reason*/, ActivityStack.REMOVE_TASK_MODE_MOVING); - + mStack.removeTask(mTask, null /*reason*/, REMOVE_TASK_MODE_MOVING); // Stack should be gone on task removal. - assertNull(service.mStackSupervisor.getStack(TEST_STACK_ID)); + assertNull(mService.mStackSupervisor.getStack(mStack.mStackId)); } @Test public void testNoCleanupMovingActivityInSameStack() throws Exception { - final ActivityManagerService service = createActivityManagerService(); - final TaskRecord oldTask = createTask(service, testActivityComponent, TEST_STACK_ID); - final ActivityRecord record = createActivity(service, testActivityComponent, oldTask); - final TaskRecord newTask = createTask(service, testActivityComponent, TEST_STACK_ID); - - record.reparent(newTask, 0, null /*reason*/); - assertEquals(getActivityRemovedFromStackCount(service, TEST_STACK_ID), 0); - } - - private static int getActivityRemovedFromStackCount(ActivityManagerService service, - int stackId) { - final ActivityStack stack = service.mStackSupervisor.getStack(stackId); - if (stack instanceof ActivityStackReporter) { - return ((ActivityStackReporter) stack).onActivityRemovedFromStackInvocationCount(); - } - - return -1; + final TaskRecord newTask = + createTask(mService.mStackSupervisor, testActivityComponent, mStack); + mActivity.reparent(newTask, 0, null /*reason*/); + assertEquals(getActivityRemovedFromStackCount(), 0); } @Test @@ -126,16 +120,21 @@ public class ActivityRecordTests extends ActivityTestsBase { private void verifyPositionWithLimitedAspectRatio(int navBarPosition, Rect taskBounds, float aspectRatio, Rect expectedActivityBounds) { - final ActivityManagerService service = createActivityManagerService(); - final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); - final ActivityRecord record = createActivity(service, testActivityComponent, task); - // Verify with nav bar on the right. - when(service.mWindowManager.getNavBarPosition()).thenReturn(navBarPosition); - task.getConfiguration().windowConfiguration.setAppBounds(taskBounds); - record.info.maxAspectRatio = aspectRatio; - record.ensureActivityConfigurationLocked(0 /* globalChanges */, false /* preserveWindow */); - assertEquals(expectedActivityBounds, record.getBounds()); + when(mService.mWindowManager.getNavBarPosition()).thenReturn(navBarPosition); + mTask.getConfiguration().windowConfiguration.setAppBounds(taskBounds); + mActivity.info.maxAspectRatio = aspectRatio; + mActivity.ensureActivityConfigurationLocked( + 0 /* globalChanges */, false /* preserveWindow */); + assertEquals(expectedActivityBounds, mActivity.getBounds()); + } + + private int getActivityRemovedFromStackCount() { + if (mStack instanceof ActivityStackReporter) { + return ((ActivityStackReporter) mStack).onActivityRemovedFromStackInvocationCount(); + } + + return -1; } @@ -156,26 +155,22 @@ public class ActivityRecordTests extends ActivityTestsBase { private void testSupportsLaunchingResizeable(boolean taskPresent, boolean taskResizeable, boolean activityResizeable, boolean expected) { - final ActivityManagerService service = createActivityManagerService(); - service.mSupportsMultiWindow = true; - + mService.mSupportsMultiWindow = true; final TaskRecord task = taskPresent - ? createTask(service, testActivityComponent, TEST_STACK_ID) : null; + ? createTask(mService.mStackSupervisor, testActivityComponent, mStack) : null; if (task != null) { - task.setResizeMode(taskResizeable ? ActivityInfo.RESIZE_MODE_RESIZEABLE - : ActivityInfo.RESIZE_MODE_UNRESIZEABLE); + task.setResizeMode(taskResizeable ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_UNRESIZEABLE); } - final ActivityRecord record = createActivity(service, secondaryActivityComponent, - task); - record.info.resizeMode = activityResizeable ? ActivityInfo.RESIZE_MODE_RESIZEABLE - : ActivityInfo.RESIZE_MODE_UNRESIZEABLE; + final ActivityRecord record = createActivity(mService, secondaryActivityComponent, task); + record.info.resizeMode = activityResizeable + ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_UNRESIZEABLE; - record.canBeLaunchedOnDisplay(Display.DEFAULT_DISPLAY); + record.canBeLaunchedOnDisplay(DEFAULT_DISPLAY); - assertEquals(((TestActivityStackSupervisor) service.mStackSupervisor) + assertEquals(((TestActivityStackSupervisor) mService.mStackSupervisor) .getLastResizeableFromCanPlaceEntityOnDisplay(), expected); } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java index cd1843b37ae22..6b93d0eaa71b4 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java @@ -16,11 +16,10 @@ package com.android.server.am; -import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.HOME_STACK_ID; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -33,6 +32,7 @@ import android.support.test.filters.MediumTest; import android.support.test.runner.AndroidJUnit4; import org.junit.runner.RunWith; +import org.junit.Before; import org.junit.Test; import java.util.ArrayList; @@ -54,6 +54,21 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { private final ComponentName testActivityComponent = ComponentName.unflattenFromString("com.foo/.BarActivity"); + private ActivityManagerService mService; + private ActivityStackSupervisor mSupervisor; + private ActivityStack mFullscreenStack; + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + + mService = createActivityManagerService(); + mSupervisor = mService.mStackSupervisor; + mFullscreenStack = mService.mStackSupervisor.getDefaultDisplay().createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + } + /** * This test ensures that we do not try to restore a task based off an invalid task id. The * stack supervisor is a test version so there will be no tasks present. We should expect @@ -61,8 +76,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { */ @Test public void testRestoringInvalidTask() throws Exception { - final ActivityManagerService service = createActivityManagerService(); - TaskRecord task = service.mStackSupervisor.anyTaskForIdLocked(0 /*taskId*/, + TaskRecord task = mSupervisor.anyTaskForIdLocked(0 /*taskId*/, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null); assertNull(task); } @@ -73,43 +87,44 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { */ @Test public void testReplacingTaskInPinnedStack() throws Exception { - final ActivityManagerService service = createActivityManagerService(); - final TaskRecord firstTask = createTask(service, testActivityComponent, - FULLSCREEN_WORKSPACE_STACK_ID); - final ActivityRecord firstActivity = createActivity(service, testActivityComponent, + final TaskRecord firstTask = createTask( + mSupervisor, testActivityComponent, mFullscreenStack); + final ActivityRecord firstActivity = createActivity(mService, testActivityComponent, firstTask); // Create a new task on the full screen stack - final TaskRecord secondTask = createTask(service, testActivityComponent, - FULLSCREEN_WORKSPACE_STACK_ID); - final ActivityRecord secondActivity = createActivity(service, testActivityComponent, + final TaskRecord secondTask = createTask( + mSupervisor, testActivityComponent, mFullscreenStack); + final ActivityRecord secondActivity = createActivity(mService, testActivityComponent, secondTask); - service.mStackSupervisor.setFocusStackUnchecked("testReplacingTaskInPinnedStack", - service.mStackSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID)); + mSupervisor.setFocusStackUnchecked("testReplacingTaskInPinnedStack", mFullscreenStack); // Ensure full screen stack has both tasks. - ensureStackPlacement(service.mStackSupervisor, FULLSCREEN_WORKSPACE_STACK_ID, firstTask, - secondTask); + ensureStackPlacement(mFullscreenStack, firstTask, secondTask); // Move first activity to pinned stack. - service.mStackSupervisor.moveActivityToPinnedStackLocked(firstActivity, - new Rect() /*sourceBounds*/, 0f /*aspectRatio*/, false, "initialMove"); + final Rect sourceBounds = new Rect(); + mSupervisor.moveActivityToPinnedStackLocked(firstActivity, sourceBounds, + 0f /*aspectRatio*/, false, "initialMove"); + final ActivityDisplay display = mFullscreenStack.getDisplay(); + ActivityStack pinnedStack = display.getPinnedStack(); // Ensure a task has moved over. - ensureStackPlacement(service.mStackSupervisor, PINNED_STACK_ID, firstTask); - ensureStackPlacement(service.mStackSupervisor, FULLSCREEN_WORKSPACE_STACK_ID, secondTask); + ensureStackPlacement(pinnedStack, firstTask); + ensureStackPlacement(mFullscreenStack, secondTask); // Move second activity to pinned stack. - service.mStackSupervisor.moveActivityToPinnedStackLocked(secondActivity, - new Rect() /*sourceBounds*/, 0f /*aspectRatio*/ /*destBounds*/, false, "secondMove"); + mSupervisor.moveActivityToPinnedStackLocked(secondActivity, sourceBounds, + 0f /*aspectRatio*/, false, "secondMove"); + + // Need to get pinned stack again as a new instance might have been created. + pinnedStack = display.getPinnedStack(); // Ensure stacks have swapped tasks. - ensureStackPlacement(service.mStackSupervisor, PINNED_STACK_ID, secondTask); - ensureStackPlacement(service.mStackSupervisor, FULLSCREEN_WORKSPACE_STACK_ID, firstTask); + ensureStackPlacement(pinnedStack, secondTask); + ensureStackPlacement(mFullscreenStack, firstTask); } - private static void ensureStackPlacement(ActivityStackSupervisor supervisor, int stackId, - TaskRecord... tasks) { - final ActivityStack stack = supervisor.getStack(stackId); + private static void ensureStackPlacement(ActivityStack stack, TaskRecord... tasks) { final ArrayList stackTasks = stack.getAllTasks(); assertEquals(stackTasks.size(), tasks != null ? tasks.length : 0); @@ -127,15 +142,14 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { */ @Test public void testStoppingActivityRemovedWhenResumed() throws Exception { - final ActivityManagerService service = createActivityManagerService(); - final TaskRecord firstTask = createTask(service, testActivityComponent, - FULLSCREEN_WORKSPACE_STACK_ID); - final ActivityRecord firstActivity = createActivity(service, testActivityComponent, + final TaskRecord firstTask = createTask( + mSupervisor, testActivityComponent, mFullscreenStack); + final ActivityRecord firstActivity = createActivity(mService, testActivityComponent, firstTask); - service.mStackSupervisor.mStoppingActivities.add(firstActivity); + mSupervisor.mStoppingActivities.add(firstActivity); firstActivity.completeResumeLocked(); - assertFalse(service.mStackSupervisor.mStoppingActivities.contains(firstActivity)); + assertFalse(mSupervisor.mStoppingActivities.contains(firstActivity)); } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java index 02fba082ca98d..4ee1f47d02e06 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java @@ -16,12 +16,14 @@ package com.android.server.am; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import android.app.ActivityManager; import android.content.ComponentName; import android.content.pm.ActivityInfo; import android.os.UserHandle; @@ -30,6 +32,7 @@ import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import org.junit.runner.RunWith; +import org.junit.Before; import org.junit.Test; /** @@ -48,78 +51,80 @@ public class ActivityStackTests extends ActivityTestsBase { private static final ComponentName testOverlayComponent = ComponentName.unflattenFromString("com.foo/.OverlayActivity"); + private ActivityManagerService mService; + private ActivityStackSupervisor mSupervisor; + private ActivityStack mStack; + private TaskRecord mTask; + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + + mService = createActivityManagerService(); + mSupervisor = mService.mStackSupervisor; + mStack = mService.mStackSupervisor.getDefaultDisplay().createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + mTask = createTask(mSupervisor, testActivityComponent, mStack); + } + @Test public void testEmptyTaskCleanupOnRemove() throws Exception { - final ActivityManagerService service = createActivityManagerService(); - final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); - assertNotNull(task.getWindowContainerController()); - service.mStackSupervisor.getStack(TEST_STACK_ID).removeTask(task, - "testEmptyTaskCleanupOnRemove", ActivityStack.REMOVE_TASK_MODE_DESTROYING); - assertNull(task.getWindowContainerController()); + assertNotNull(mTask.getWindowContainerController()); + mStack.removeTask(mTask, "testEmptyTaskCleanupOnRemove", REMOVE_TASK_MODE_DESTROYING); + assertNull(mTask.getWindowContainerController()); } @Test public void testOccupiedTaskCleanupOnRemove() throws Exception { - final ActivityManagerService service = createActivityManagerService(); - final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); - final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task); - assertNotNull(task.getWindowContainerController()); - service.mStackSupervisor.getStack(TEST_STACK_ID).removeTask(task, - "testOccupiedTaskCleanupOnRemove", ActivityStack.REMOVE_TASK_MODE_DESTROYING); - assertNotNull(task.getWindowContainerController()); + final ActivityRecord r = createActivity(mService, testActivityComponent, mTask); + assertNotNull(mTask.getWindowContainerController()); + mStack.removeTask(mTask, "testOccupiedTaskCleanupOnRemove", REMOVE_TASK_MODE_DESTROYING); + assertNotNull(mTask.getWindowContainerController()); } @Test public void testNoPauseDuringResumeTopActivity() throws Exception { - final ActivityManagerService service = createActivityManagerService(); - final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); - final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task); - final ActivityStack testStack = service.mStackSupervisor.getStack(TEST_STACK_ID); + final ActivityRecord r = createActivity(mService, testActivityComponent, mTask); // Simulate the a resumed activity set during // {@link ActivityStack#resumeTopActivityUncheckedLocked}. - service.mStackSupervisor.inResumeTopActivity = true; - testStack.mResumedActivity = activityRecord; + mSupervisor.inResumeTopActivity = true; + mStack.mResumedActivity = r; - final boolean waiting = testStack.goToSleepIfPossible(false); + final boolean waiting = mStack.goToSleepIfPossible(false); // Ensure we report not being ready for sleep. assertFalse(waiting); // Make sure the resumed activity is untouched. - assertEquals(testStack.mResumedActivity, activityRecord); + assertEquals(mStack.mResumedActivity, r); } @Test public void testStopActivityWhenActivityDestroyed() throws Exception { - final ActivityManagerService service = createActivityManagerService(); - final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); - final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task); - activityRecord.info.flags |= ActivityInfo.FLAG_NO_HISTORY; - final ActivityStack testStack = service.mStackSupervisor.getStack(TEST_STACK_ID); - service.mStackSupervisor.setFocusStackUnchecked("testStopActivityWithDestroy", testStack); - - testStack.stopActivityLocked(activityRecord); + final ActivityRecord r = createActivity(mService, testActivityComponent, mTask); + r.info.flags |= ActivityInfo.FLAG_NO_HISTORY; + mSupervisor.setFocusStackUnchecked("testStopActivityWithDestroy", mStack); + mStack.stopActivityLocked(r); + // Mostly testing to make sure there is a crash in the call part, so if we get here we are + // good-to-go! } @Test public void testFindTaskWithOverlay() throws Exception { - final ActivityManagerService service = createActivityManagerService(); - final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); - final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task, - 0); + final ActivityRecord r = createActivity(mService, testActivityComponent, mTask, 0); // Overlay must be for a different user to prevent recognizing a matching top activity - final ActivityRecord taskOverlay = createActivity(service, testOverlayComponent, task, + final ActivityRecord taskOverlay = createActivity(mService, testOverlayComponent, mTask, UserHandle.PER_USER_RANGE * 2); taskOverlay.mTaskOverlay = true; - final ActivityStack testStack = service.mStackSupervisor.getStack(TEST_STACK_ID); final ActivityStackSupervisor.FindTaskResult result = new ActivityStackSupervisor.FindTaskResult(); - testStack.findTaskLocked(activityRecord, result); + mStack.findTaskLocked(r, result); - assertEquals(task.getTopActivity(false /* includeOverlays */), activityRecord); - assertEquals(task.getTopActivity(true /* includeOverlays */), taskOverlay); + assertEquals(mTask.getTopActivity(false /* includeOverlays */), r); + assertEquals(mTask.getTopActivity(true /* includeOverlays */), taskOverlay); assertNotNull(result.r); } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java index 6caa60b5a0100..b4bfa621a37e7 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java @@ -16,7 +16,7 @@ package com.android.server.am; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.view.Display.DEFAULT_DISPLAY; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.doReturn; @@ -76,16 +76,6 @@ public class ActivityTestsBase { return service; } - protected static ActivityStack createActivityStack(ActivityManagerService service, - int stackId, int displayId, boolean onTop) { - if (service.mStackSupervisor instanceof TestActivityStackSupervisor) { - return ((TestActivityStackSupervisor) service.mStackSupervisor) - .createTestStack(stackId, onTop); - } - - return null; - } - protected static ActivityRecord createActivity(ActivityManagerService service, ComponentName component, TaskRecord task) { return createActivity(service, component, task, 0 /* userId */); @@ -114,8 +104,8 @@ public class ActivityTestsBase { return activity; } - protected static TaskRecord createTask(ActivityManagerService service, - ComponentName component, int stackId) { + protected static TaskRecord createTask(ActivityStackSupervisor supervisor, + ComponentName component, ActivityStack stack) { final ActivityInfo aInfo = new ActivityInfo(); aInfo.applicationInfo = new ApplicationInfo(); aInfo.applicationInfo.packageName = component.getPackageName(); @@ -123,11 +113,9 @@ public class ActivityTestsBase { Intent intent = new Intent(); intent.setComponent(component); - final TaskRecord task = new TaskRecord(service, 0, aInfo, intent /*intent*/, + final TaskRecord task = new TaskRecord(supervisor.mService, 0, aInfo, intent /*intent*/, null /*_taskDescription*/); - final ActivityStack stack = service.mStackSupervisor.getStack(stackId, - true /*createStaticStackIfNeeded*/, true /*onTop*/); - service.mStackSupervisor.setFocusStackUnchecked("test", stack); + supervisor.setFocusStackUnchecked("test", stack); stack.addTask(task, true, "creating test task"); task.setStack(stack); task.setWindowContainerController(mock(TaskWindowContainerController.class)); @@ -135,16 +123,18 @@ public class ActivityTestsBase { return task; } - /** * An {@link ActivityManagerService} subclass which provides a test * {@link ActivityStackSupervisor}. */ protected static class TestActivityManagerService extends ActivityManagerService { - public TestActivityManagerService(Context context) { + TestActivityManagerService(Context context) { super(context); mSupportsMultiWindow = true; mSupportsMultiDisplay = true; + mSupportsSplitScreenMultiWindow = true; + mSupportsFreeformWindowManagement = true; + mSupportsPictureInPicture = true; mWindowManager = WindowTestUtils.getWindowManagerService(context); } @@ -171,10 +161,15 @@ public class ActivityTestsBase { mDisplayManager = (DisplayManager) mService.mContext.getSystemService(Context.DISPLAY_SERVICE); mWindowManager = prepareMockWindowManager(); - mDisplay = new ActivityDisplay(this, DEFAULT_DISPLAY); + mDisplay = new TestActivityDisplay(this, DEFAULT_DISPLAY); attachDisplay(mDisplay); } + @Override + ActivityDisplay getDefaultDisplay() { + return mDisplay; + } + // TODO: Use Mockito spy instead. Currently not possible due to TestActivityStackSupervisor // access to ActivityDisplay @Override @@ -218,41 +213,36 @@ public class ActivityTestsBase { boolean preserveWindows) { } - T createTestStack(int stackId, boolean onTop) { - return (T) createStack(stackId, mDisplay, onTop); + // Always keep things awake + @Override + boolean hasAwakeDisplay() { + return true; + } + } + + private static class TestActivityDisplay extends ActivityDisplay { + + private final ActivityStackSupervisor mSupervisor; + TestActivityDisplay(ActivityStackSupervisor supervisor, int displayId) { + super(supervisor, displayId); + mSupervisor = supervisor; } @Override - ActivityStack createStack(int stackId, ActivityDisplay display, boolean onTop) { - if (stackId == PINNED_STACK_ID) { - return new PinnedActivityStack(display, stackId, this, onTop) { + T createStackUnchecked(int windowingMode, int activityType, + int stackId, boolean onTop) { + if (windowingMode == WINDOWING_MODE_PINNED) { + return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop) { @Override Rect getDefaultPictureInPictureBounds(float aspectRatio) { return new Rect(50, 50, 100, 100); } }; } else { - return new TestActivityStack(display, stackId, this, onTop); + return (T) new TestActivityStack( + this, stackId, mSupervisor, windowingMode, activityType, onTop); } } - - @Override - protected T getStack(int stackId, - boolean createStaticStackIfNeeded, boolean createOnTop) { - final T stack = super.getStack(stackId, createStaticStackIfNeeded, createOnTop); - - if (stack != null || !createStaticStackIfNeeded) { - return stack; - } - - return createTestStack(stackId, createOnTop); - } - - // Always keep things awake - @Override - boolean hasAwakeDisplay() { - return true; - } } private static WindowManagerService prepareMockWindowManager() { @@ -282,9 +272,10 @@ public class ActivityTestsBase { extends ActivityStack implements ActivityStackReporter { private int mOnActivityRemovedFromStackCount = 0; private T mContainerController; + TestActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor, - boolean onTop) { - super(display, stackId, supervisor, onTop); + int windowingMode, int activityType, boolean onTop) { + super(display, stackId, supervisor, windowingMode, activityType, onTop); } @Override @@ -310,36 +301,4 @@ public class ActivityTestsBase { return mContainerController; } } - - - protected static class ActivityStackBuilder { - private boolean mOnTop = true; - private int mStackId = 0; - private int mDisplayId = 1; - - private final ActivityManagerService mService; - - public ActivityStackBuilder(ActivityManagerService ams) { - mService = ams; - } - - public ActivityStackBuilder setOnTop(boolean onTop) { - mOnTop = onTop; - return this; - } - - public ActivityStackBuilder setStackId(int id) { - mStackId = id; - return this; - } - - public ActivityStackBuilder setDisplayId(int id) { - mDisplayId = id; - return this; - } - - public ActivityStack build() { - return createActivityStack(mService, mStackId, mDisplayId, mOnTop); - } - } } From 68278568de7479f9fef31517d799c2c254dd1d37 Mon Sep 17 00:00:00 2001 From: Wale Ogunwale Date: Sat, 23 Sep 2017 17:13:55 -0700 Subject: [PATCH 2/2] HOME_STACK_ID, ASSISTANT_STACK_ID, and RECENTS_STACK_ID be gone! Replaced usages with ACTIVITY_TYPE_HOME, ACTIVITY_TYPE_ASSISTANT and ACTIVITY_TYPE_RECENTS. Test: go/wm-smoke Test: Existing tests pass. Bug: 64146578 Change-Id: I62c55c99df86dba8c9ba9d9986049de1b1083234 --- api/test-current.txt | 5 +- core/java/android/app/ActivityManager.java | 188 +++++----------- core/java/android/app/IActivityManager.aidl | 11 +- core/java/android/view/IWindowManager.aidl | 4 +- .../android/view/WindowManagerPolicy.java | 5 +- core/res/AndroidManifest.xml | 4 +- .../keyguard/KeyguardUpdateMonitor.java | 4 +- .../systemui/pip/phone/PipManager.java | 5 +- .../pip/phone/PipMenuActivityController.java | 8 +- .../systemui/pip/phone/PipMotionHelper.java | 8 +- .../android/systemui/pip/phone/PipUtils.java | 5 +- .../android/systemui/pip/tv/PipManager.java | 5 +- .../com/android/systemui/recents/Recents.java | 10 +- .../android/systemui/recents/RecentsImpl.java | 11 +- .../recents/misc/SystemServicesProxy.java | 77 +++---- .../systemui/stackdivider/DividerView.java | 18 +- .../stackdivider/WindowManagerProxy.java | 8 +- .../car/CarNavigationBarController.java | 9 +- .../systemui/statusbar/car/CarStatusBar.java | 2 +- .../statusbar/phone/PhoneStatusBarPolicy.java | 33 ++- .../android/server/am/ActivityDisplay.java | 69 ++++-- .../server/am/ActivityManagerService.java | 105 ++++++--- .../am/ActivityManagerShellCommand.java | 205 +----------------- .../com/android/server/am/ActivityStack.java | 41 +++- .../server/am/ActivityStackSupervisor.java | 111 ++++++---- .../android/server/am/ActivityStarter.java | 58 ++--- .../com/android/server/am/TaskPersister.java | 3 - .../server/policy/PhoneWindowManager.java | 11 +- .../com/android/server/wm/DisplayContent.java | 13 +- .../wm/DockedStackDividerController.java | 16 +- .../com/android/server/wm/DragResizeMode.java | 15 +- .../server/wm/PinnedStackController.java | 6 +- .../wm/PinnedStackWindowController.java | 10 +- .../server/wm/RootWindowContainer.java | 11 + .../core/java/com/android/server/wm/Task.java | 22 +- .../server/wm/TaskSnapshotController.java | 2 +- .../java/com/android/server/wm/TaskStack.java | 26 ++- .../server/wm/WindowLayersController.java | 16 +- .../server/wm/WindowManagerService.java | 8 +- .../com/android/server/wm/WindowState.java | 2 +- .../server/wm/DisplayContentTests.java | 12 +- .../server/wm/TaskStackContainersTests.java | 5 +- .../server/wm/WindowConfigurationTests.java | 20 +- .../wm/WindowLayersControllerTests.java | 22 +- .../android/server/wm/WindowTestsBase.java | 35 +-- 45 files changed, 597 insertions(+), 667 deletions(-) diff --git a/api/test-current.txt b/api/test-current.txt index 2512e8e666b59..e42ee25fe050b 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -3863,6 +3863,8 @@ package android.app { method public void moveTaskToFront(int, int); method public void moveTaskToFront(int, int, android.os.Bundle); method public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener); + method public void removeStacksInWindowingModes(int[]) throws java.lang.SecurityException; + method public void removeStacksWithActivityTypes(int[]) throws java.lang.SecurityException; method public deprecated void restartPackage(java.lang.String); method public static void setVrThread(int); method public void setWatchHeapLimit(long); @@ -4016,14 +4018,11 @@ package android.app { } public static class ActivityManager.StackId { - field public static final int ASSISTANT_STACK_ID = 6; // 0x6 field public static final int DOCKED_STACK_ID = 3; // 0x3 field public static final int FREEFORM_WORKSPACE_STACK_ID = 2; // 0x2 field public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1; // 0x1 - field public static final int HOME_STACK_ID = 0; // 0x0 field public static final int INVALID_STACK_ID = -1; // 0xffffffff field public static final int PINNED_STACK_ID = 4; // 0x4 - field public static final int RECENTS_STACK_ID = 5; // 0x5 } public static class ActivityManager.TaskDescription implements android.os.Parcelable { diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index b38caf8a919be..26f96fbeede13 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -16,10 +16,6 @@ package android.app; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; @@ -46,6 +42,7 @@ import android.content.pm.IPackageDataObserver; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.UserInfo; +import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -677,9 +674,6 @@ public class ActivityManager { * @hide */ private static final int FIRST_STATIC_STACK_ID = 0; - /** Home activity stack ID. */ - public static final int HOME_STACK_ID = FIRST_STATIC_STACK_ID; - /** ID of stack where fullscreen activities are normally launched into. */ public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1; @@ -692,15 +686,9 @@ public class ActivityManager { /** ID of stack that always on top (always visible) when it exist. */ public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1; - /** ID of stack that contains the Recents activity. */ - public static final int RECENTS_STACK_ID = PINNED_STACK_ID + 1; - - /** ID of stack that contains activities launched by the assistant. */ - public static final int ASSISTANT_STACK_ID = RECENTS_STACK_ID + 1; - /** Last static stack stack ID. * @hide */ - private static final int LAST_STATIC_STACK_ID = ASSISTANT_STACK_ID; + private static final int LAST_STATIC_STACK_ID = PINNED_STACK_ID; /** Start of ID range used by stacks that are created dynamically. * @hide */ @@ -719,15 +707,6 @@ public class ActivityManager { return stackId >= FIRST_DYNAMIC_STACK_ID; } - /** - * Returns true if dynamic stacks are allowed to be visible behind the input stack. - * @hide - */ - // TODO: Figure-out a way to remove. - public static boolean isDynamicStacksVisibleBehindAllowed(int stackId) { - return stackId == PINNED_STACK_ID || stackId == ASSISTANT_STACK_ID; - } - /** * Returns true if we try to maintain focus in the current stack when the top activity * finishes. @@ -739,15 +718,6 @@ public class ActivityManager { || stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID; } - /** - * Returns true if the input stack is affected by drag resizing. - * @hide - */ - public static boolean isStackAffectedByDragResizing(int stackId) { - return isStaticStack(stackId) && stackId != PINNED_STACK_ID - && stackId != ASSISTANT_STACK_ID; - } - /** * Returns true if the windows of tasks being moved to the target stack from the source * stack should be replaced, meaning that window manager will keep the old window around @@ -759,26 +729,6 @@ public class ActivityManager { || targetStackId == FREEFORM_WORKSPACE_STACK_ID; } - /** - * Return whether a stackId is a stack that be a backdrop to a translucent activity. These - * are generally fullscreen stacks. - * @hide - */ - public static boolean isBackdropToTranslucentActivity(int stackId) { - return stackId == FULLSCREEN_WORKSPACE_STACK_ID - || stackId == ASSISTANT_STACK_ID; - } - - /** - * Returns true if activities from stasks in the given {@param stackId} are allowed to - * enter picture-in-picture. - * @hide - */ - public static boolean isAllowedToEnterPictureInPicture(int stackId) { - return stackId != HOME_STACK_ID && stackId != ASSISTANT_STACK_ID && - stackId != RECENTS_STACK_ID; - } - /** * Returns true if the top task in the task is allowed to return home when finished and * there are other tasks in the stack. @@ -810,34 +760,18 @@ public class ActivityManager { && stackId != DOCKED_STACK_ID; } - /** - * Returns true if the input stack id should only be present on a device that supports - * multi-window mode. - * @see android.app.ActivityManager#supportsMultiWindow - * @hide - */ - // TODO: What about the other side of docked stack if we move this to WindowConfiguration? - public static boolean isMultiWindowStack(int stackId) { - return stackId == PINNED_STACK_ID || stackId == FREEFORM_WORKSPACE_STACK_ID - || stackId == DOCKED_STACK_ID; - } - - /** - * Returns true if the input {@param stackId} is HOME_STACK_ID or RECENTS_STACK_ID - * @hide - */ - public static boolean isHomeOrRecentsStack(int stackId) { - return stackId == HOME_STACK_ID || stackId == RECENTS_STACK_ID; - } - - /** Returns true if the input stack and its content can affect the device orientation. + /** Returns the stack id for the input windowing mode. * @hide */ - public static boolean canSpecifyOrientation(int stackId) { - return stackId == HOME_STACK_ID - || stackId == RECENTS_STACK_ID - || stackId == FULLSCREEN_WORKSPACE_STACK_ID - || stackId == ASSISTANT_STACK_ID - || isDynamicStack(stackId); + // TODO: To be removed once we are not using stack id for stuff... + public static int getStackIdForWindowingMode(int windowingMode) { + switch (windowingMode) { + case WINDOWING_MODE_PINNED: return PINNED_STACK_ID; + case WINDOWING_MODE_FREEFORM: return FREEFORM_WORKSPACE_STACK_ID; + case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return DOCKED_STACK_ID; + case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: return FULLSCREEN_WORKSPACE_STACK_ID; + case WINDOWING_MODE_FULLSCREEN: return FULLSCREEN_WORKSPACE_STACK_ID; + default: return INVALID_STACK_ID; + } } /** Returns the windowing mode that should be used for this input stack id. @@ -847,14 +781,9 @@ public class ActivityManager { final int windowingMode; switch (stackId) { case FULLSCREEN_WORKSPACE_STACK_ID: - case HOME_STACK_ID: - case RECENTS_STACK_ID: windowingMode = inSplitScreenMode ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY : WINDOWING_MODE_FULLSCREEN; break; - case ASSISTANT_STACK_ID: - windowingMode = WINDOWING_MODE_FULLSCREEN; - break; case PINNED_STACK_ID: windowingMode = WINDOWING_MODE_PINNED; break; @@ -869,51 +798,6 @@ public class ActivityManager { } return windowingMode; } - - /** Returns the stack id for the input windowing mode. - * @hide */ - // TODO: To be removed once we are not using stack id for stuff... - public static int getStackIdForWindowingMode(int windowingMode) { - switch (windowingMode) { - case WINDOWING_MODE_PINNED: return PINNED_STACK_ID; - case WINDOWING_MODE_FREEFORM: return FREEFORM_WORKSPACE_STACK_ID; - case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return DOCKED_STACK_ID; - default: return INVALID_STACK_ID; - } - } - - /** Returns the activity type that should be used for this input stack id. - * @hide */ - // TODO: To be removed once we are not using stack id for stuff... - public static int getActivityTypeForStackId(int stackId) { - final int activityType; - switch (stackId) { - case HOME_STACK_ID: - activityType = ACTIVITY_TYPE_HOME; - break; - case RECENTS_STACK_ID: - activityType = ACTIVITY_TYPE_RECENTS; - break; - case ASSISTANT_STACK_ID: - activityType = ACTIVITY_TYPE_ASSISTANT; - break; - default : - activityType = ACTIVITY_TYPE_STANDARD; - } - return activityType; - } - - /** Returns the stack id for the input activity type. - * @hide */ - // TODO: To be removed once we are not using stack id for stuff... - public static int getStackIdForActivityType(int activityType) { - switch (activityType) { - case ACTIVITY_TYPE_HOME: return HOME_STACK_ID; - case ACTIVITY_TYPE_RECENTS: return RECENTS_STACK_ID; - case ACTIVITY_TYPE_ASSISTANT: return ASSISTANT_STACK_ID; - default: return INVALID_STACK_ID; - } - } } /** @@ -1910,6 +1794,12 @@ public class ActivityManager { */ public int resizeMode; + /** + * The full configuration the task is currently running in. + * @hide + */ + public Configuration configuration = new Configuration(); + public RunningTaskInfo() { } @@ -1934,6 +1824,7 @@ public class ActivityManager { dest.writeInt(numRunning); dest.writeInt(supportsSplitScreenMultiWindow ? 1 : 0); dest.writeInt(resizeMode); + configuration.writeToParcel(dest, flags); } public void readFromParcel(Parcel source) { @@ -1951,6 +1842,7 @@ public class ActivityManager { numRunning = source.readInt(); supportsSplitScreenMultiWindow = source.readInt() != 0; resizeMode = source.readInt(); + configuration.readFromParcel(source); } public static final Creator CREATOR = new Creator() { @@ -2132,6 +2024,35 @@ public class ActivityManager { } } + /** + * Removes stacks in the windowing modes from the system if they are of activity type + * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED + * + * @hide + */ + @TestApi + public void removeStacksInWindowingModes(int[] windowingModes) throws SecurityException { + try { + getService().removeStacksInWindowingModes(windowingModes); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Removes stack of the activity types from the system. + * + * @hide + */ + @TestApi + public void removeStacksWithActivityTypes(int[] activityTypes) throws SecurityException { + try { + getService().removeStacksWithActivityTypes(activityTypes); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Represents a task snapshot. * @hide @@ -2610,6 +2531,11 @@ public class ActivityManager { public boolean visible; // Index of the stack in the display's stack list, can be used for comparison of stack order public int position; + /** + * The full configuration the stack is currently running in. + * @hide + */ + public Configuration configuration = new Configuration(); @Override public int describeContents() { @@ -2644,6 +2570,7 @@ public class ActivityManager { } else { dest.writeInt(0); } + configuration.writeToParcel(dest, flags); } public void readFromParcel(Parcel source) { @@ -2671,6 +2598,7 @@ public class ActivityManager { if (source.readInt() > 0) { topActivity = ComponentName.readFromParcel(source); } + configuration.readFromParcel(source); } public static final Creator CREATOR = new Creator() { @@ -2698,6 +2626,8 @@ public class ActivityManager { sb.append(" displayId="); sb.append(displayId); sb.append(" userId="); sb.append(userId); sb.append("\n"); + sb.append(" configuration="); sb.append(configuration); + sb.append("\n"); prefix = prefix + " "; for (int i = 0; i < taskIds.length; ++i) { sb.append(prefix); sb.append("taskId="); sb.append(taskIds[i]); diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index eccb264796f89..955b46300ea08 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -380,7 +380,8 @@ interface IActivityManager { boolean preserveWindows, boolean animate, int animationDuration); List getAllStackInfos(); void setFocusedStack(int stackId); - ActivityManager.StackInfo getStackInfo(int stackId); + ActivityManager.StackInfo getFocusedStackInfo(); + ActivityManager.StackInfo getStackInfo(int windowingMode, int activityType); boolean convertFromTranslucent(in IBinder token); boolean convertToTranslucent(in IBinder token, in Bundle options); void notifyActivityDrawn(in IBinder token); @@ -440,7 +441,6 @@ interface IActivityManager { // Start of M transactions void notifyCleartextNetwork(int uid, in byte[] firstPacket); int createStackOnDisplay(int displayId); - int getFocusedStackId(); void setTaskResizeable(int taskId, int resizeableMode); boolean requestAssistContextExtras(int requestType, in IResultReceiver receiver, in Bundle receiverExtras, in IBinder activityToken, @@ -540,6 +540,13 @@ interface IActivityManager { void notifyPinnedStackAnimationStarted(); void notifyPinnedStackAnimationEnded(); void removeStack(int stackId); + /** + * Removes stacks in the input windowing modes from the system if they are of activity type + * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED + */ + void removeStacksInWindowingModes(in int[] windowingModes); + /** Removes stack of the activity types from the system. */ + void removeStacksWithActivityTypes(in int[] activityTypes); void makePackageIdle(String packageName, int userId); int getMemoryTrimLevel(); /** diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index e576a0fbdb2b0..6e49bac381160 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -358,10 +358,10 @@ interface IWindowManager * Updates the dim layer used while resizing. * * @param visible Whether the dim layer should be visible. - * @param targetStackId The id of the task stack the dim layer should be placed on. + * @param targetWindowingMode The windowing mode of the stack the dim layer should be placed on. * @param alpha The translucency of the dim layer, between 0 and 1. */ - void setResizeDimLayer(boolean visible, int targetStackId, float alpha); + void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha); /** * Requests Keyboard Shortcuts from the displayed window. diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 4131fd1ae9ff3..da72535d54ecb 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -592,9 +592,10 @@ public interface WindowManagerPolicy { int getDockedDividerInsetsLw(); /** - * Retrieves the {@param outBounds} from the stack with id {@param stackId}. + * Retrieves the {@param outBounds} from the stack matching the {@param windowingMode} and + * {@param activityType}. */ - void getStackBounds(int stackId, Rect outBounds); + void getStackBounds(int windowingMode, int activityType, Rect outBounds); /** * Notifies window manager that {@link #isShowingDreamLw} has changed. diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 695fdac702807..4159c21e837b5 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1873,11 +1873,11 @@ + android:protectionLevel="signature|privileged|development" /> + android:protectionLevel="signature|privileged|development" />