Loading core/java/android/app/ActivityManager.java +7 −1 Original line number Diff line number Diff line Loading @@ -428,11 +428,17 @@ public class ActivityManager { */ public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1; /** * ID of stack that occupies a dedicated region of the screen. * @hide */ public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1; /** * Last static stack stack ID. * @hide */ public static final int LAST_STATIC_STACK_ID = FREEFORM_WORKSPACE_STACK_ID; public static final int LAST_STATIC_STACK_ID = DOCKED_STACK_ID; /** * Start of ID range used by stacks that are created dynamically. Loading core/java/android/app/ActivityManagerNative.java +2 −2 Original line number Diff line number Diff line Loading @@ -3528,12 +3528,12 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } @Override public void resizeStack(int stackBoxId, Rect r) throws RemoteException public void resizeStack(int stackId, Rect r) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeInt(stackBoxId); data.writeInt(stackId); r.writeToParcel(data, 0); mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, 0); reply.readException(); Loading services/core/java/com/android/server/am/ActivityManagerService.java +13 −13 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.am; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.app.ActivityManager.DOCKED_STACK_ID; import static android.app.ActivityManager.HOME_STACK_ID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static com.android.internal.util.XmlUtils.readBooleanAttribute; Loading @@ -29,6 +30,7 @@ import static com.android.internal.util.XmlUtils.writeIntAttribute; import static com.android.internal.util.XmlUtils.writeLongAttribute; import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST; import static com.android.server.am.ActivityManagerDebugConfig.*; import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS; import static com.android.server.am.ActivityStackSupervisor.ON_TOP; import static com.android.server.am.TaskRecord.INVALID_TASK_ID; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK; Loading Loading @@ -8653,8 +8655,12 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.e(TAG, "setActivityBounds: No TaskRecord for the ActivityRecord r=" + r); return; } if (task.stack != null && task.stack.mStackId == DOCKED_STACK_ID) { mStackSupervisor.resizeStackLocked(task.stack.mStackId, bounds); } else { mStackSupervisor.resizeTaskLocked(task, bounds); } } } finally { Binder.restoreCallingIdentity(ident); } Loading Loading @@ -9010,7 +9016,7 @@ public final class ActivityManagerService extends ActivityManagerNative public void moveActivityToStack(IBinder token, int stackId) throws RemoteException { if (stackId == HOME_STACK_ID) { throw new IllegalArgumentException( "moveTaskToStack: Attempt to move token " + token + " to home stack"); "moveActivityToStack: Attempt to move token " + token + " to home stack"); } synchronized (this) { long ident = Binder.clearCallingIdentity(); Loading @@ -9022,13 +9028,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if (DEBUG_STACK) Slog.d(TAG_STACK, "moveActivityToStack: moving r=" + r + " to stackId=" + stackId); mStackSupervisor.moveTaskToStackLocked(r.task.taskId, stackId, ON_TOP); if (mFocusedActivity != r) { setFocusedActivityLocked(r, "moveActivityToStack"); } else { mStackSupervisor.setFocusedStack(r, "moveActivityToStack"); } mStackSupervisor.resumeTopActivitiesLocked(r.task.stack, null, null); mStackSupervisor.moveTaskToStackLocked(r.task.taskId, stackId, ON_TOP, FORCE_FOCUS); } finally { Binder.restoreCallingIdentity(ident); } Loading @@ -9048,7 +9048,7 @@ public final class ActivityManagerService extends ActivityManagerNative try { if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId + " to stackId=" + stackId + " toTop=" + toTop); mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop); mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop, !FORCE_FOCUS); } finally { Binder.restoreCallingIdentity(ident); } Loading @@ -9074,9 +9074,9 @@ public final class ActivityManagerService extends ActivityManagerNative enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, "positionTaskInStack()"); if (stackId == HOME_STACK_ID) { Slog.e(TAG, "positionTaskInStack: Attempt to change the position of task " + taskId + " in/to home stack", new RuntimeException("here").fillInStackTrace()); throw new IllegalArgumentException( "positionTaskInStack: Attempt to change the position of task " + taskId + " in/to home stack"); } synchronized (this) { long ident = Binder.clearCallingIdentity(); Loading services/core/java/com/android/server/am/ActivityStack.java +70 −15 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.am; import static android.app.ActivityManager.DOCKED_STACK_ID; import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.HOME_STACK_ID; Loading Loading @@ -229,6 +230,8 @@ final class ActivityStack { // Whether or not this stack covers the entire screen; by default stacks are fullscreen boolean mFullscreen = true; // Current bounds of the stack or null if fullscreen. Rect mBounds = null; long mLaunchStartTime = 0; long mFullyDrawnStartTime = 0; Loading Loading @@ -1227,8 +1230,42 @@ final class ActivityStack { return null; } // Checks if any of the stacks above this one has a fullscreen activity behind it. // If so, this stack is hidden, otherwise it is visible. /** Returns true if the stack contains a fullscreen task. */ private boolean hasFullscreenTask() { for (int i = mTaskHistory.size() - 1; i >= 0; --i) { final TaskRecord task = mTaskHistory.get(i); if (task.mFullscreen) { return true; } } return false; } /** Return true if this stack is hidden by the presence of a docked stack. */ private boolean isHiddenByDockedStack() { final ActivityStack dockedStack = mStackSupervisor.getStack(DOCKED_STACK_ID); if (dockedStack != null) { final int dockedStackIndex = mStacks.indexOf(dockedStack); final int stackIndex = mStacks.indexOf(this); if (dockedStackIndex > stackIndex) { // Fullscreen stacks or stacks with fullscreen task below the docked stack are not // visible. We do this so we don't have the 2 stacks and their tasks overlap. if (mFullscreen) { return true; } // We need to also check the tasks in the stack because they can be fullscreen // even though their stack isn't due to their root activity not been resizeable // (i.e. doesn't support multi-window mode). if (hasFullscreenTask()) { return true; } } } return false; } /** Returns true if the stack is considered visible. */ private boolean isStackVisibleLocked() { if (!isAttached()) { return false; Loading @@ -1238,12 +1275,15 @@ final class ActivityStack { return true; } // Any stack that isn't the front stack is not visible, except for the case of the home // stack behind the main application stack since we can have dialog activities on the // main application stack that need the home stack to display behind them. // TODO(multi-window): Also need to add exception for side-by-side stacks. final boolean homeStack = mStackId == HOME_STACK_ID; if (!homeStack) { final int stackIndex = mStacks.indexOf(this); if (stackIndex == mStacks.size() - 1) { Slog.wtf(TAG, "Stack=" + this + " isn't front stack but is at the top of the stack list"); return false; } if (isHiddenByDockedStack()) { return false; } Loading @@ -1252,13 +1292,24 @@ final class ActivityStack { * fullscreen activity, or a translucent activity that requested the * wallpaper to be shown behind it. */ for (int i = mStacks.indexOf(this) + 1; i < mStacks.size(); i++) { for (int i = stackIndex + 1; i < mStacks.size(); i++) { final ActivityStack stack = mStacks.get(i); if (stack.mStackId != FULLSCREEN_WORKSPACE_STACK_ID) { final ArrayList<TaskRecord> tasks = stack.getAllTasks(); if (!stack.mFullscreen && !stack.hasFullscreenTask()) { continue; } if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID || stack.mStackId == HOME_STACK_ID) { // The freeform and home stacks can't have any other stack visible behind them // when they are fullscreen since they act as base/cut-off points for visibility. // NOTE: we don't cut-off at the FULLSCREEN_WORKSPACE_STACK_ID because the home // stack sometimes needs to be visible behind it when it is displaying a dialog // activity. We let it fall through to the logic below to determine visibility. return false; } final ArrayList<TaskRecord> tasks = stack.getAllTasks(); for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { final TaskRecord task = tasks.get(taskNdx); // task above isn't fullscreen, so, we assume we're still visible. Loading Loading @@ -2680,9 +2731,10 @@ final class ActivityStack { ActivityRecord next = topRunningActivityLocked(null); final String myReason = reason + " adjustFocus"; if (next != r) { if (next != null && mStackId == FREEFORM_WORKSPACE_STACK_ID) { // For freeform stack we always keep the focus within the stack as long as // there is a running activity in the stack that we can adjust focus to. if (next != null && (mStackId == FREEFORM_WORKSPACE_STACK_ID || mStackId == DOCKED_STACK_ID)) { // For freeform and docked stacks we always keep the focus within the stack as // long as there is a running activity in the stack that we can adjust focus to. mService.setFocusedActivityLocked(next, myReason); return; } else { Loading Loading @@ -4321,7 +4373,10 @@ final class ActivityStack { printed |= ActivityStackSupervisor.dumpHistoryList(fd, pw, mTaskHistory.get(taskNdx).mActivities, " ", "Hist", true, !dumpAll, dumpClient, dumpPackage, needSep, header, " Task id #" + task.taskId); " Task id #" + task.taskId + "\n" + " mFullscreen=" + task.mFullscreen + "\n" + " mBounds=" + task.mBounds + "\n" + " mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds); if (printed) { header = null; } Loading services/core/java/com/android/server/am/ActivityStackSupervisor.java +87 −16 Original line number Diff line number Diff line Loading @@ -184,6 +184,9 @@ public final class ActivityStackSupervisor implements DisplayListener { // (e.g. stack) is due to it moving to another container. static final boolean MOVING = true; // Force the focus to change to the stack we are moving a task to.. static final boolean FORCE_FOCUS = true; // Activity actions an app cannot start if it uses a permission which is not granted. private static final ArrayMap<String, String> ACTION_TO_RUNTIME_PERMISSION = new ArrayMap<>(); Loading Loading @@ -328,6 +331,9 @@ public final class ActivityStackSupervisor implements DisplayListener { /** Used to keep resumeTopActivityLocked() from being entered recursively */ boolean inResumeTopActivity; // temp. rect used during resize calculation so we don't need to create a new object each time. private final Rect tempRect = new Rect(); /** * Description of a request to start a new activity, which has been held * due to app switches being disabled. Loading Loading @@ -2908,16 +2914,13 @@ public final class ActivityStackSupervisor implements DisplayListener { return; } final ActivityRecord r = stack.topRunningActivityLocked(null); if (r != null && !r.task.mResizeable) { Slog.w(TAG, "resizeStack: top task " + r.task + " not resizeable."); return; } ActivityRecord r = stack.topRunningActivityLocked(null); final boolean resizeTasks = r != null && r.task.mResizeable; final IntArray changedTaskIds = new IntArray(stack.numTasks()); final List<Configuration> newTaskConfigs = new ArrayList<>(stack.numTasks()); stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, changedTaskIds, newTaskConfigs); stack.mFullscreen = mWindowManager.resizeStack( stackId, bounds, resizeTasks, changedTaskIds, newTaskConfigs); for (int i = changedTaskIds.size() - 1; i >= 0; i--) { final TaskRecord task = anyTaskForIdLocked(changedTaskIds.get(i), false); if (task == null) { Loading @@ -2927,6 +2930,55 @@ public final class ActivityStackSupervisor implements DisplayListener { task.updateOverrideConfiguration(newTaskConfigs.get(i), bounds); } if (stack.mStackId == DOCKED_STACK_ID) { // Dock stack funness...Yay! if (stack.mFullscreen) { // The dock stack went fullscreen which is kinda like dismissing it. // In this case we make all other static stacks fullscreen and move all // docked stack tasks to the fullscreen stack. for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) { if (i != DOCKED_STACK_ID) { resizeStackLocked(i, null); } } final ArrayList<TaskRecord> tasks = stack.getAllTasks(); final int count = tasks.size(); for (int i = 0; i < count; i++) { moveTaskToStackLocked(tasks.get(i).taskId, FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, FORCE_FOCUS); } // stack shouldn't contain anymore activities, so nothing to resume. r = null; } else { // Docked stacks occupy a dedicated region on screen so the size of all other // static stacks need to be adjusted so they don't overlap with the docked stack. final int leftChange = stack.mBounds.left - bounds.left; final int rightChange = stack.mBounds.right - bounds.right; final int topChange = stack.mBounds.top - bounds.top; final int bottomChange = stack.mBounds.bottom - bounds.bottom; for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) { if (i != DOCKED_STACK_ID) { ActivityStack otherStack = getStack(i); if (otherStack != null) { tempRect.set(otherStack.mBounds); // We adjust the opposing sides of the other stacks to // the side in the dock stack that changed. tempRect.left -= rightChange; tempRect.right -= leftChange; tempRect.top -= bottomChange; tempRect.bottom -= topChange; resizeStackLocked(i, tempRect); } } } } } stack.mBounds = stack.mFullscreen ? null : new Rect(bounds); if (r != null) { final boolean updated = stack.ensureActivityConfigurationLocked(r, 0); // And we need to make sure at this point that all other activities Loading Loading @@ -2968,7 +3020,8 @@ public final class ActivityStackSupervisor implements DisplayListener { final boolean wasFrontStack = isFrontStack(task.stack); if (bounds == null && stackId != FULLSCREEN_WORKSPACE_STACK_ID) { stackId = FULLSCREEN_WORKSPACE_STACK_ID; } else if (bounds != null && task.stack.mStackId != FREEFORM_WORKSPACE_STACK_ID) { } else if (bounds != null && stackId != FREEFORM_WORKSPACE_STACK_ID && stackId != DOCKED_STACK_ID) { stackId = FREEFORM_WORKSPACE_STACK_ID; } if (stackId != task.stack.mStackId) { Loading Loading @@ -3069,8 +3122,7 @@ public final class ActivityStackSupervisor implements DisplayListener { */ private ActivityStack moveTaskToStackUncheckedLocked( TaskRecord task, int stackId, boolean toTop, String reason) { final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop); final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop); mWindowManager.moveTaskToStack(task.taskId, stack.mStackId, toTop); if (task.stack != null) { task.stack.removeTask(task, reason, MOVING); Loading @@ -3079,26 +3131,39 @@ public final class ActivityStackSupervisor implements DisplayListener { return stack; } void moveTaskToStackLocked(int taskId, int stackId, boolean toTop) { void moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus) { final TaskRecord task = anyTaskForIdLocked(taskId); if (task == null) { Slog.w(TAG, "moveTaskToStack: no task for id=" + taskId); return; } ActivityStack stack = moveTaskToStackUncheckedLocked(task, stackId, toTop, "moveTaskToStack"); final String reason = "moveTaskToStack"; final ActivityRecord top = task.topRunningActivityLocked(null); final boolean adjustFocus = forceFocus || mService.mFocusedActivity == top; final ActivityStack stack = moveTaskToStackUncheckedLocked(task, stackId, toTop, reason); // Make sure the task has the appropriate bounds/size for the stack it is in. if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) { resizeTaskLocked(task, null); resizeTaskLocked(task, stack.mBounds); } else if (stackId == FREEFORM_WORKSPACE_STACK_ID && task.mBounds == null && task.mLastNonFullscreenBounds != null) { resizeTaskLocked(task, task.mLastNonFullscreenBounds); } else if (stackId == DOCKED_STACK_ID) { resizeTaskLocked(task, stack.mBounds); } if (top != null && adjustFocus) { if (mService.mFocusedActivity != top) { mService.setFocusedActivityLocked(top, reason); } else { setFocusedStack(top, reason); } } // The task might have already been running and its visibility needs to be synchronized with // the visibility of the stack / windows. stack.ensureActivitiesVisibleLocked(null, 0); ensureActivitiesVisibleLocked(null, 0); resumeTopActivitiesLocked(); } Loading Loading @@ -3659,6 +3724,10 @@ public final class ActivityStackSupervisor implements DisplayListener { stackHeader.append(" Stack #"); stackHeader.append(stack.mStackId); stackHeader.append(":"); stackHeader.append("\n"); stackHeader.append(" mFullscreen=" + stack.mFullscreen); stackHeader.append("\n"); stackHeader.append(" mBounds=" + stack.mBounds); printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage, needSep, stackHeader.toString()); printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, " ", "Run", false, Loading Loading @@ -4313,7 +4382,9 @@ public final class ActivityStackSupervisor implements DisplayListener { mStack.mStacks = activityDisplay.mStacks; activityDisplay.attachActivities(mStack, onTop); mStack.mBounds = mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId, onTop); mStack.mFullscreen = mStack.mBounds == null; } @Override Loading Loading
core/java/android/app/ActivityManager.java +7 −1 Original line number Diff line number Diff line Loading @@ -428,11 +428,17 @@ public class ActivityManager { */ public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1; /** * ID of stack that occupies a dedicated region of the screen. * @hide */ public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1; /** * Last static stack stack ID. * @hide */ public static final int LAST_STATIC_STACK_ID = FREEFORM_WORKSPACE_STACK_ID; public static final int LAST_STATIC_STACK_ID = DOCKED_STACK_ID; /** * Start of ID range used by stacks that are created dynamically. Loading
core/java/android/app/ActivityManagerNative.java +2 −2 Original line number Diff line number Diff line Loading @@ -3528,12 +3528,12 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } @Override public void resizeStack(int stackBoxId, Rect r) throws RemoteException public void resizeStack(int stackId, Rect r) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeInt(stackBoxId); data.writeInt(stackId); r.writeToParcel(data, 0); mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, 0); reply.readException(); Loading
services/core/java/com/android/server/am/ActivityManagerService.java +13 −13 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.am; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.app.ActivityManager.DOCKED_STACK_ID; import static android.app.ActivityManager.HOME_STACK_ID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static com.android.internal.util.XmlUtils.readBooleanAttribute; Loading @@ -29,6 +30,7 @@ import static com.android.internal.util.XmlUtils.writeIntAttribute; import static com.android.internal.util.XmlUtils.writeLongAttribute; import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST; import static com.android.server.am.ActivityManagerDebugConfig.*; import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS; import static com.android.server.am.ActivityStackSupervisor.ON_TOP; import static com.android.server.am.TaskRecord.INVALID_TASK_ID; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK; Loading Loading @@ -8653,8 +8655,12 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.e(TAG, "setActivityBounds: No TaskRecord for the ActivityRecord r=" + r); return; } if (task.stack != null && task.stack.mStackId == DOCKED_STACK_ID) { mStackSupervisor.resizeStackLocked(task.stack.mStackId, bounds); } else { mStackSupervisor.resizeTaskLocked(task, bounds); } } } finally { Binder.restoreCallingIdentity(ident); } Loading Loading @@ -9010,7 +9016,7 @@ public final class ActivityManagerService extends ActivityManagerNative public void moveActivityToStack(IBinder token, int stackId) throws RemoteException { if (stackId == HOME_STACK_ID) { throw new IllegalArgumentException( "moveTaskToStack: Attempt to move token " + token + " to home stack"); "moveActivityToStack: Attempt to move token " + token + " to home stack"); } synchronized (this) { long ident = Binder.clearCallingIdentity(); Loading @@ -9022,13 +9028,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if (DEBUG_STACK) Slog.d(TAG_STACK, "moveActivityToStack: moving r=" + r + " to stackId=" + stackId); mStackSupervisor.moveTaskToStackLocked(r.task.taskId, stackId, ON_TOP); if (mFocusedActivity != r) { setFocusedActivityLocked(r, "moveActivityToStack"); } else { mStackSupervisor.setFocusedStack(r, "moveActivityToStack"); } mStackSupervisor.resumeTopActivitiesLocked(r.task.stack, null, null); mStackSupervisor.moveTaskToStackLocked(r.task.taskId, stackId, ON_TOP, FORCE_FOCUS); } finally { Binder.restoreCallingIdentity(ident); } Loading @@ -9048,7 +9048,7 @@ public final class ActivityManagerService extends ActivityManagerNative try { if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId + " to stackId=" + stackId + " toTop=" + toTop); mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop); mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop, !FORCE_FOCUS); } finally { Binder.restoreCallingIdentity(ident); } Loading @@ -9074,9 +9074,9 @@ public final class ActivityManagerService extends ActivityManagerNative enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, "positionTaskInStack()"); if (stackId == HOME_STACK_ID) { Slog.e(TAG, "positionTaskInStack: Attempt to change the position of task " + taskId + " in/to home stack", new RuntimeException("here").fillInStackTrace()); throw new IllegalArgumentException( "positionTaskInStack: Attempt to change the position of task " + taskId + " in/to home stack"); } synchronized (this) { long ident = Binder.clearCallingIdentity(); Loading
services/core/java/com/android/server/am/ActivityStack.java +70 −15 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.am; import static android.app.ActivityManager.DOCKED_STACK_ID; import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.HOME_STACK_ID; Loading Loading @@ -229,6 +230,8 @@ final class ActivityStack { // Whether or not this stack covers the entire screen; by default stacks are fullscreen boolean mFullscreen = true; // Current bounds of the stack or null if fullscreen. Rect mBounds = null; long mLaunchStartTime = 0; long mFullyDrawnStartTime = 0; Loading Loading @@ -1227,8 +1230,42 @@ final class ActivityStack { return null; } // Checks if any of the stacks above this one has a fullscreen activity behind it. // If so, this stack is hidden, otherwise it is visible. /** Returns true if the stack contains a fullscreen task. */ private boolean hasFullscreenTask() { for (int i = mTaskHistory.size() - 1; i >= 0; --i) { final TaskRecord task = mTaskHistory.get(i); if (task.mFullscreen) { return true; } } return false; } /** Return true if this stack is hidden by the presence of a docked stack. */ private boolean isHiddenByDockedStack() { final ActivityStack dockedStack = mStackSupervisor.getStack(DOCKED_STACK_ID); if (dockedStack != null) { final int dockedStackIndex = mStacks.indexOf(dockedStack); final int stackIndex = mStacks.indexOf(this); if (dockedStackIndex > stackIndex) { // Fullscreen stacks or stacks with fullscreen task below the docked stack are not // visible. We do this so we don't have the 2 stacks and their tasks overlap. if (mFullscreen) { return true; } // We need to also check the tasks in the stack because they can be fullscreen // even though their stack isn't due to their root activity not been resizeable // (i.e. doesn't support multi-window mode). if (hasFullscreenTask()) { return true; } } } return false; } /** Returns true if the stack is considered visible. */ private boolean isStackVisibleLocked() { if (!isAttached()) { return false; Loading @@ -1238,12 +1275,15 @@ final class ActivityStack { return true; } // Any stack that isn't the front stack is not visible, except for the case of the home // stack behind the main application stack since we can have dialog activities on the // main application stack that need the home stack to display behind them. // TODO(multi-window): Also need to add exception for side-by-side stacks. final boolean homeStack = mStackId == HOME_STACK_ID; if (!homeStack) { final int stackIndex = mStacks.indexOf(this); if (stackIndex == mStacks.size() - 1) { Slog.wtf(TAG, "Stack=" + this + " isn't front stack but is at the top of the stack list"); return false; } if (isHiddenByDockedStack()) { return false; } Loading @@ -1252,13 +1292,24 @@ final class ActivityStack { * fullscreen activity, or a translucent activity that requested the * wallpaper to be shown behind it. */ for (int i = mStacks.indexOf(this) + 1; i < mStacks.size(); i++) { for (int i = stackIndex + 1; i < mStacks.size(); i++) { final ActivityStack stack = mStacks.get(i); if (stack.mStackId != FULLSCREEN_WORKSPACE_STACK_ID) { final ArrayList<TaskRecord> tasks = stack.getAllTasks(); if (!stack.mFullscreen && !stack.hasFullscreenTask()) { continue; } if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID || stack.mStackId == HOME_STACK_ID) { // The freeform and home stacks can't have any other stack visible behind them // when they are fullscreen since they act as base/cut-off points for visibility. // NOTE: we don't cut-off at the FULLSCREEN_WORKSPACE_STACK_ID because the home // stack sometimes needs to be visible behind it when it is displaying a dialog // activity. We let it fall through to the logic below to determine visibility. return false; } final ArrayList<TaskRecord> tasks = stack.getAllTasks(); for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { final TaskRecord task = tasks.get(taskNdx); // task above isn't fullscreen, so, we assume we're still visible. Loading Loading @@ -2680,9 +2731,10 @@ final class ActivityStack { ActivityRecord next = topRunningActivityLocked(null); final String myReason = reason + " adjustFocus"; if (next != r) { if (next != null && mStackId == FREEFORM_WORKSPACE_STACK_ID) { // For freeform stack we always keep the focus within the stack as long as // there is a running activity in the stack that we can adjust focus to. if (next != null && (mStackId == FREEFORM_WORKSPACE_STACK_ID || mStackId == DOCKED_STACK_ID)) { // For freeform and docked stacks we always keep the focus within the stack as // long as there is a running activity in the stack that we can adjust focus to. mService.setFocusedActivityLocked(next, myReason); return; } else { Loading Loading @@ -4321,7 +4373,10 @@ final class ActivityStack { printed |= ActivityStackSupervisor.dumpHistoryList(fd, pw, mTaskHistory.get(taskNdx).mActivities, " ", "Hist", true, !dumpAll, dumpClient, dumpPackage, needSep, header, " Task id #" + task.taskId); " Task id #" + task.taskId + "\n" + " mFullscreen=" + task.mFullscreen + "\n" + " mBounds=" + task.mBounds + "\n" + " mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds); if (printed) { header = null; } Loading
services/core/java/com/android/server/am/ActivityStackSupervisor.java +87 −16 Original line number Diff line number Diff line Loading @@ -184,6 +184,9 @@ public final class ActivityStackSupervisor implements DisplayListener { // (e.g. stack) is due to it moving to another container. static final boolean MOVING = true; // Force the focus to change to the stack we are moving a task to.. static final boolean FORCE_FOCUS = true; // Activity actions an app cannot start if it uses a permission which is not granted. private static final ArrayMap<String, String> ACTION_TO_RUNTIME_PERMISSION = new ArrayMap<>(); Loading Loading @@ -328,6 +331,9 @@ public final class ActivityStackSupervisor implements DisplayListener { /** Used to keep resumeTopActivityLocked() from being entered recursively */ boolean inResumeTopActivity; // temp. rect used during resize calculation so we don't need to create a new object each time. private final Rect tempRect = new Rect(); /** * Description of a request to start a new activity, which has been held * due to app switches being disabled. Loading Loading @@ -2908,16 +2914,13 @@ public final class ActivityStackSupervisor implements DisplayListener { return; } final ActivityRecord r = stack.topRunningActivityLocked(null); if (r != null && !r.task.mResizeable) { Slog.w(TAG, "resizeStack: top task " + r.task + " not resizeable."); return; } ActivityRecord r = stack.topRunningActivityLocked(null); final boolean resizeTasks = r != null && r.task.mResizeable; final IntArray changedTaskIds = new IntArray(stack.numTasks()); final List<Configuration> newTaskConfigs = new ArrayList<>(stack.numTasks()); stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, changedTaskIds, newTaskConfigs); stack.mFullscreen = mWindowManager.resizeStack( stackId, bounds, resizeTasks, changedTaskIds, newTaskConfigs); for (int i = changedTaskIds.size() - 1; i >= 0; i--) { final TaskRecord task = anyTaskForIdLocked(changedTaskIds.get(i), false); if (task == null) { Loading @@ -2927,6 +2930,55 @@ public final class ActivityStackSupervisor implements DisplayListener { task.updateOverrideConfiguration(newTaskConfigs.get(i), bounds); } if (stack.mStackId == DOCKED_STACK_ID) { // Dock stack funness...Yay! if (stack.mFullscreen) { // The dock stack went fullscreen which is kinda like dismissing it. // In this case we make all other static stacks fullscreen and move all // docked stack tasks to the fullscreen stack. for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) { if (i != DOCKED_STACK_ID) { resizeStackLocked(i, null); } } final ArrayList<TaskRecord> tasks = stack.getAllTasks(); final int count = tasks.size(); for (int i = 0; i < count; i++) { moveTaskToStackLocked(tasks.get(i).taskId, FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, FORCE_FOCUS); } // stack shouldn't contain anymore activities, so nothing to resume. r = null; } else { // Docked stacks occupy a dedicated region on screen so the size of all other // static stacks need to be adjusted so they don't overlap with the docked stack. final int leftChange = stack.mBounds.left - bounds.left; final int rightChange = stack.mBounds.right - bounds.right; final int topChange = stack.mBounds.top - bounds.top; final int bottomChange = stack.mBounds.bottom - bounds.bottom; for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) { if (i != DOCKED_STACK_ID) { ActivityStack otherStack = getStack(i); if (otherStack != null) { tempRect.set(otherStack.mBounds); // We adjust the opposing sides of the other stacks to // the side in the dock stack that changed. tempRect.left -= rightChange; tempRect.right -= leftChange; tempRect.top -= bottomChange; tempRect.bottom -= topChange; resizeStackLocked(i, tempRect); } } } } } stack.mBounds = stack.mFullscreen ? null : new Rect(bounds); if (r != null) { final boolean updated = stack.ensureActivityConfigurationLocked(r, 0); // And we need to make sure at this point that all other activities Loading Loading @@ -2968,7 +3020,8 @@ public final class ActivityStackSupervisor implements DisplayListener { final boolean wasFrontStack = isFrontStack(task.stack); if (bounds == null && stackId != FULLSCREEN_WORKSPACE_STACK_ID) { stackId = FULLSCREEN_WORKSPACE_STACK_ID; } else if (bounds != null && task.stack.mStackId != FREEFORM_WORKSPACE_STACK_ID) { } else if (bounds != null && stackId != FREEFORM_WORKSPACE_STACK_ID && stackId != DOCKED_STACK_ID) { stackId = FREEFORM_WORKSPACE_STACK_ID; } if (stackId != task.stack.mStackId) { Loading Loading @@ -3069,8 +3122,7 @@ public final class ActivityStackSupervisor implements DisplayListener { */ private ActivityStack moveTaskToStackUncheckedLocked( TaskRecord task, int stackId, boolean toTop, String reason) { final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop); final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop); mWindowManager.moveTaskToStack(task.taskId, stack.mStackId, toTop); if (task.stack != null) { task.stack.removeTask(task, reason, MOVING); Loading @@ -3079,26 +3131,39 @@ public final class ActivityStackSupervisor implements DisplayListener { return stack; } void moveTaskToStackLocked(int taskId, int stackId, boolean toTop) { void moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus) { final TaskRecord task = anyTaskForIdLocked(taskId); if (task == null) { Slog.w(TAG, "moveTaskToStack: no task for id=" + taskId); return; } ActivityStack stack = moveTaskToStackUncheckedLocked(task, stackId, toTop, "moveTaskToStack"); final String reason = "moveTaskToStack"; final ActivityRecord top = task.topRunningActivityLocked(null); final boolean adjustFocus = forceFocus || mService.mFocusedActivity == top; final ActivityStack stack = moveTaskToStackUncheckedLocked(task, stackId, toTop, reason); // Make sure the task has the appropriate bounds/size for the stack it is in. if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) { resizeTaskLocked(task, null); resizeTaskLocked(task, stack.mBounds); } else if (stackId == FREEFORM_WORKSPACE_STACK_ID && task.mBounds == null && task.mLastNonFullscreenBounds != null) { resizeTaskLocked(task, task.mLastNonFullscreenBounds); } else if (stackId == DOCKED_STACK_ID) { resizeTaskLocked(task, stack.mBounds); } if (top != null && adjustFocus) { if (mService.mFocusedActivity != top) { mService.setFocusedActivityLocked(top, reason); } else { setFocusedStack(top, reason); } } // The task might have already been running and its visibility needs to be synchronized with // the visibility of the stack / windows. stack.ensureActivitiesVisibleLocked(null, 0); ensureActivitiesVisibleLocked(null, 0); resumeTopActivitiesLocked(); } Loading Loading @@ -3659,6 +3724,10 @@ public final class ActivityStackSupervisor implements DisplayListener { stackHeader.append(" Stack #"); stackHeader.append(stack.mStackId); stackHeader.append(":"); stackHeader.append("\n"); stackHeader.append(" mFullscreen=" + stack.mFullscreen); stackHeader.append("\n"); stackHeader.append(" mBounds=" + stack.mBounds); printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage, needSep, stackHeader.toString()); printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, " ", "Run", false, Loading Loading @@ -4313,7 +4382,9 @@ public final class ActivityStackSupervisor implements DisplayListener { mStack.mStacks = activityDisplay.mStacks; activityDisplay.attachActivities(mStack, onTop); mStack.mBounds = mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId, onTop); mStack.mFullscreen = mStack.mBounds == null; } @Override Loading