Remove use of TaskTile
We just have the TaskOrganizer create root task directly
Test: Existing tests pass
Bug: 133381284
Bug: 149429752
Change-Id: Id884cbe8e7d2fdd93e729fcb2793fad4afd59b21
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index e8bfe8e..6308d25 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -303,9 +303,6 @@
private static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 1;
- // TODO(task-hierarchy): remove when tiles can be actual parents
- TaskTile mTile = null;
-
private final Handler mHandler;
private class ActivityStackHandler extends Handler {
@@ -551,10 +548,10 @@
}
ActivityStack(ActivityTaskManagerService atmService, int id, int activityType,
- ActivityInfo info, Intent intent) {
+ ActivityInfo info, Intent intent, boolean createdByOrganizer) {
this(atmService, id, info, intent, null /*voiceSession*/, null /*voiceInteractor*/,
null /*taskDescription*/, null /*stack*/);
-
+ mCreatedByOrganizer = createdByOrganizer;
setActivityType(activityType);
}
@@ -601,20 +598,11 @@
}
@Override
- public void resolveTileOverrideConfiguration(Configuration newParentConfig) {
- super.resolveTileOverrideConfiguration(newParentConfig);
- if (mTile != null) {
- // If this is a virtual child of a tile, simulate the parent-child relationship
- mTile.updateResolvedConfig(getResolvedOverrideConfiguration());
- }
- }
-
- @Override
public void onConfigurationChanged(Configuration newParentConfig) {
// Calling Task#onConfigurationChanged() for leaf task since the ops in this method are
// particularly for ActivityStack, like preventing bounds changes when inheriting certain
// windowing mode.
- if (!isRootTask() || this instanceof TaskTile) {
+ if (!isRootTask()) {
super.onConfigurationChanged(newParentConfig);
return;
}
@@ -689,6 +677,9 @@
@Override
public void setWindowingMode(int windowingMode) {
+ // Reset the cached result of toString()
+ stringName = null;
+
// Calling Task#setWindowingMode() for leaf task since this is the a specialization of
// {@link #setWindowingMode(int)} for ActivityStack.
if (!isRootTask()) {
@@ -742,7 +733,6 @@
final int currentOverrideMode = getRequestedOverrideWindowingMode();
final DisplayContent display = getDisplay();
final Task topTask = getTopMostTask();
- final ActivityStack splitScreenStack = display.getRootSplitScreenPrimaryTask();
int windowingMode = preferredWindowingMode;
if (preferredWindowingMode == WINDOWING_MODE_UNDEFINED
&& isTransientWindowingMode(currentMode)) {
@@ -756,14 +746,14 @@
windowingMode = display.validateWindowingMode(windowingMode,
null /* ActivityRecord */, topTask, getActivityType());
}
- if (splitScreenStack == this
+ if (display.getRootSplitScreenPrimaryTask() == this
&& windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
// Resolution to split-screen secondary for the primary split-screen stack means
// we want to leave split-screen mode.
windowingMode = mRestoreOverrideWindowingMode;
}
- final boolean alreadyInSplitScreenMode = display.hasSplitScreenPrimaryTask();
+ final boolean alreadyInSplitScreenMode = display.isSplitScreenModeActivated();
// Don't send non-resizeable notifications if the windowing mode changed was a side effect
// of us entering split-screen mode.
@@ -831,7 +821,7 @@
return;
}
- if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && splitScreenStack != null) {
+ if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && alreadyInSplitScreenMode) {
// We already have a split-screen stack in this display, so just move the tasks over.
// TODO: Figure-out how to do all the stuff in
// AMS.setTaskWindowingModeSplitScreenPrimary
@@ -1063,7 +1053,7 @@
final DisplayContent display = getDisplay();
if (inSplitScreenSecondaryWindowingMode()) {
- // If the stack is in split-screen seconardy mode, we need to make sure we move the
+ // If the stack is in split-screen secondary mode, we need to make sure we move the
// primary split-screen stack forward in the case it is currently behind a fullscreen
// stack so both halves of the split-screen appear on-top and the fullscreen stack isn't
// cutting between them.
@@ -1085,12 +1075,13 @@
display.moveHomeStackToFront(reason + " returnToHome");
}
- final boolean movingTask = task != null;
- display.positionStackAtTop(this, !movingTask /* includingParents */, reason);
- if (movingTask) {
- // This also moves the entire hierarchy branch to top, including parents
- positionChildAtTop(task);
+ if (isRootTask()) {
+ display.positionStackAtTop(this, false /* includingParents */, reason);
}
+ if (task == null) {
+ task = this;
+ }
+ task.getParent().positionChildAt(POSITION_TOP, task, true /* includingParents */);
}
/**
@@ -1116,12 +1107,6 @@
}
}
- @Override
- boolean isFocusable() {
- // Special check for tile which isn't really in the hierarchy
- return mTile != null ? mTile.isFocusable() : super.isFocusable();
- }
-
boolean isTopActivityFocusable() {
final ActivityRecord r = topRunningActivity();
return r != null ? r.isFocusable()
@@ -3542,6 +3527,10 @@
@Override
void onChildPositionChanged(WindowContainer child) {
+ if (isOrganized()) {
+ mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, false /* force */);
+ }
+
if (!mChildren.contains(child)) {
return;
}
@@ -3572,11 +3561,6 @@
if (oldDisplay != null && oldDisplay.isRemoving()) {
postReparent();
}
- if (mTile != null && getSurfaceControl() != null) {
- // by now, the TaskStack should already have been reparented, so we can reparent its
- // surface here
- reparentSurfaceControl(getPendingTransaction(), mTile.getSurfaceControl());
- }
}
void reparent(DisplayContent newParent, boolean onTop) {
@@ -3614,16 +3598,7 @@
@Override
void getRelativeDisplayedPosition(Point outPos) {
- // check for tile which is "virtually" a parent.
- if (mTile != null) {
- final Rect dispBounds = getDisplayedBounds();
- outPos.set(dispBounds.left, dispBounds.top);
- final Rect parentBounds = mTile.getBounds();
- outPos.offset(-parentBounds.left, -parentBounds.top);
- } else {
- super.getRelativeDisplayedPosition(outPos);
- }
-
+ super.getRelativeDisplayedPosition(outPos);
final int outset = getStackOutset();
outPos.x -= outset;
outPos.y -= outset;
@@ -3633,16 +3608,6 @@
if (mSurfaceControl == null) {
return;
}
- if (mTile != null) {
- // Tile controls crop, so the app needs to be able to draw its background outside of
- // the stack bounds for when the tile crop gets bigger than the stack.
- if (mLastSurfaceSize.equals(0, 0)) {
- return;
- }
- transaction.setWindowCrop(mSurfaceControl, null);
- mLastSurfaceSize.set(0, 0);
- return;
- }
final Rect stackBounds = getDisplayedBounds();
int width = stackBounds.width();
@@ -3666,9 +3631,6 @@
@Override
void onDisplayChanged(DisplayContent dc) {
- if (mTile != null && dc != mTile.getDisplay()) {
- mTile.removeChild(this);
- }
super.onDisplayChanged(dc);
if (isRootTask()) {
updateSurfaceBounds();
@@ -3825,49 +3787,6 @@
return shouldSleepActivities() || mAtmService.mShuttingDown;
}
- TaskTile getTile() {
- return mTile;
- }
-
- /**
- * Don't call this directly. instead use {@link TaskTile#addChild} or
- * {@link TaskTile#removeChild}.
- */
- void setTile(TaskTile tile) {
- TaskTile origTile = mTile;
- mTile = tile;
- final ConfigurationContainer parent = getParent();
- if (parent != null) {
- onConfigurationChanged(parent.getConfiguration());
- }
-
- // Reparent to tile surface or back to original parent
- if (getSurfaceControl() == null) {
- return;
- }
- if (mTile != null) {
- // don't use reparentSurfaceControl because we need to bypass taskorg check
- mSurfaceAnimator.reparent(getPendingTransaction(), mTile.getSurfaceControl());
- } else if (mTile == null && origTile != null) {
- mSurfaceAnimator.reparent(getPendingTransaction(), getParentSurfaceControl());
- }
- }
-
- @Override
- public SurfaceControl getParentSurfaceControl() {
- // Tile is a "virtual" parent, so we need to intercept the parent surface here
- return mTile != null ? mTile.getSurfaceControl() : super.getParentSurfaceControl();
- }
-
- @Override
- void removeImmediately() {
- // TODO(task-hierarchy): remove this override when tiles are in hierarchy
- if (mTile != null) {
- mTile.removeChild(this);
- }
- super.removeImmediately();
- }
-
@Override
public void dumpDebug(ProtoOutputStream proto, long fieldId,
@WindowTraceLogLevel int logLevel) {
@@ -3912,7 +3831,7 @@
proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight());
}
- proto.write(CREATED_BY_ORGANIZER, this instanceof TaskTile);
+ proto.write(CREATED_BY_ORGANIZER, mCreatedByOrganizer);
proto.end(token);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 57f357d..4652f49 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -423,6 +423,10 @@
final ActivityStack toStack = mToDisplay.getOrCreateStack(
null, mTmpOptions, task, task.getActivityType(), mOnTop);
+ if (task == toStack) {
+ // The task was reused as the root task.
+ return;
+ }
if (mOnTop) {
final boolean isTopTask = task == mTopTask;
@@ -1704,7 +1708,7 @@
mRootWindowContainer.getLaunchStack(null, aOptions, task, onTop);
final WindowContainer parent = task.getParent();
- if (parent == stack) {
+ if (parent == stack || task == stack) {
// Nothing else to do since it is already restored in the right stack.
return true;
}
@@ -2237,7 +2241,7 @@
final boolean isSecondaryDisplayPreferred =
(preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY);
final boolean inSplitScreenMode = actualStack != null
- && actualStack.getDisplay().hasSplitScreenPrimaryTask();
+ && actualStack.getDisplay().isSplitScreenModeActivated();
if (((!inSplitScreenMode && preferredWindowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
&& !isSecondaryDisplayPreferred) || !task.isActivityTypeStandardOrUndefined()) {
return;
@@ -2284,16 +2288,14 @@
if (!task.supportsSplitScreenWindowingMode() || forceNonResizable) {
// 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 =
- task.getStack().getDisplay().getRootSplitScreenPrimaryTask();
- if (dockedStack != null) {
+ final DisplayContent display = task.getStack().getDisplay();
+ if (display.isSplitScreenModeActivated()) {
// Display a warning toast that we tried to put an app that doesn't support
// split-screen in split-screen.
mService.getTaskChangeNotificationController()
.notifyActivityDismissingDockedStack();
- dockedStack.getDisplay().onSplitScreenModeDismissed();
- dockedStack.getDisplay().ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
+ display.onSplitScreenModeDismissed();
+ display.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
true /* notifyClients */);
}
return;
@@ -2602,7 +2604,7 @@
"startActivityFromRecents: Task " + taskId + " not found.");
} else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
&& task.getWindowingMode() != windowingMode) {
- mService.moveTaskToSplitScreenPrimaryTile(task, true /* toTop */);
+ mService.moveTaskToSplitScreenPrimaryTask(task, true /* toTop */);
}
if (windowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 14ca7cb..da1c045 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -30,7 +30,6 @@
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WaitResult.LAUNCH_STATE_COLD;
import static android.app.WaitResult.LAUNCH_STATE_HOT;
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
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;
@@ -78,6 +77,7 @@
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1566,7 +1566,7 @@
}
if (!mAvoidMoveToFront && mDoResume) {
- mTargetStack.moveToFront("reuseOrNewTask");
+ mTargetStack.getStack().moveToFront("reuseOrNewTask", targetTask);
if (mOptions != null) {
if (mPreferredWindowingMode != WINDOWING_MODE_UNDEFINED) {
mTargetStack.setWindowingMode(mPreferredWindowingMode);
@@ -2364,6 +2364,7 @@
private void setTargetStackIfNeeded(ActivityRecord intentActivity) {
mTargetStack = intentActivity.getRootTask();
mTargetStack.mLastPausedActivity = null;
+ Task intentTask = intentActivity.getTask();
// If the target task is not in the front, then we need to bring it to the front...
// except... well, with SINGLE_TASK_LAUNCH it's not entirely clear. We'd like to have
// the same behavior as if a new instance was being started, which means not bringing it
@@ -2374,7 +2375,7 @@
final ActivityRecord curTop = (focusStack == null)
? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
final Task topTask = curTop != null ? curTop.getTask() : null;
- differentTopTask = topTask != intentActivity.getTask()
+ differentTopTask = topTask != intentTask
|| (focusStack != null && topTask != focusStack.getTopMostTask());
} else {
// The existing task should always be different from those in other displays.
@@ -2391,7 +2392,6 @@
intentActivity.setTaskToAffiliateWith(mSourceRecord.getTask());
}
- final Task intentTask = intentActivity.getTask();
final ActivityStack launchStack =
getLaunchStack(mStartActivity, mLaunchFlags, intentTask, mOptions);
if (launchStack == null || launchStack == mTargetStack) {
@@ -2400,6 +2400,14 @@
// new intent has delivered.
final boolean isSplitScreenTopStack = mTargetStack.isTopSplitScreenStack();
+ // TODO(b/151572268): Figure out a better way to move tasks in above 2-levels
+ // tasks hierarchies.
+ if (mTargetStack != intentTask
+ && mTargetStack != intentTask.getParent().asTask()) {
+ intentTask.getParent().positionChildAt(POSITION_TOP, intentTask,
+ false /* includingParents */);
+ intentTask = intentTask.getParent().asTask();
+ }
// We only want to move to the front, if we aren't going to launch on a
// different stack. If we launch on a different stack, we will put the
// task on top there.
@@ -2420,8 +2428,8 @@
// Need to update mTargetStack because if task was moved out of it, the original stack may
// be destroyed.
mTargetStack = intentActivity.getRootTask();
- mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTask(),
- WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, mTargetStack);
+ mSupervisor.handleNonResizableTaskIfNeeded(intentTask, WINDOWING_MODE_UNDEFINED,
+ DEFAULT_DISPLAY, mTargetStack);
}
private void resumeTargetStackIfNeeded() {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 214a676..35492f4 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -36,7 +36,6 @@
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.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -122,6 +121,7 @@
import static com.android.server.wm.Task.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
import android.Manifest;
import android.annotation.IntDef;
@@ -144,7 +144,6 @@
import android.app.IAssistDataReceiver;
import android.app.INotificationManager;
import android.app.IRequestFinishCallback;
-import android.window.ITaskOrganizerController;
import android.app.ITaskStackListener;
import android.app.Notification;
import android.app.NotificationManager;
@@ -230,9 +229,9 @@
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
+import android.view.WindowManager;
import android.window.IWindowOrganizerController;
import android.window.WindowContainerTransaction;
-import android.view.WindowManager;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -2349,16 +2348,18 @@
}
final ActivityStack stack = task.getStack();
- // Convert some windowing-mode changes into root-task reparents for split-screen.
- if (stack.getTile() != null) {
- stack.getDisplay().onSplitScreenModeDismissed();
- }
if (toTop) {
stack.moveToFront("setTaskWindowingMode", task);
}
- stack.setWindowingMode(windowingMode);
- stack.getDisplay().ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
- true /* notifyClients */);
+ // Convert some windowing-mode changes into root-task reparents for split-screen.
+ if (stack.inSplitScreenWindowingMode()) {
+ stack.getDisplay().onSplitScreenModeDismissed();
+
+ } else {
+ stack.setWindowingMode(windowingMode);
+ stack.getDisplay().ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
+ true /* notifyClients */);
+ }
return true;
} finally {
Binder.restoreCallingIdentity(ident);
@@ -2755,24 +2756,22 @@
}
final int prevMode = task.getWindowingMode();
- moveTaskToSplitScreenPrimaryTile(task, toTop);
+ moveTaskToSplitScreenPrimaryTask(task, toTop);
return prevMode != task.getWindowingMode();
}
- void moveTaskToSplitScreenPrimaryTile(Task task, boolean toTop) {
- ActivityStack stack = task.getStack();
- TaskTile tile = null;
- for (int i = stack.getDisplay().getStackCount() - 1; i >= 0; --i) {
- tile = stack.getDisplay().getStackAt(i).asTile();
- if (tile != null && tile.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- break;
- }
+ void moveTaskToSplitScreenPrimaryTask(Task task, boolean toTop) {
+ final DisplayContent display = task.getDisplayContent();
+ final ActivityStack primarySplitTask = display.getRootSplitScreenPrimaryTask();
+ if (primarySplitTask == null) {
+ throw new IllegalStateException("Can't enter split without associated organized task");
}
- if (tile == null) {
- throw new IllegalStateException("Can't enter split without associated tile");
+
+ if (toTop) {
+ display.positionStackAt(POSITION_TOP, primarySplitTask, false /* includingParents */);
}
WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.reparent(stack.mRemoteToken, tile.mRemoteToken, toTop);
+ wct.reparent(task.getStack().mRemoteToken, primarySplitTask.mRemoteToken, toTop);
mWindowOrganizerController.applyTransaction(wct);
}
@@ -3239,7 +3238,8 @@
final ActivityStack stack = r.getRootTask();
final Task task = stack.getDisplay().createStack(stack.getWindowingMode(),
- stack.getActivityType(), !ON_TOP, ainfo, intent);
+ stack.getActivityType(), !ON_TOP, ainfo, intent,
+ false /* createdByOrganizer */);
if (!mRecentTasks.addToBottom(task)) {
// The app has too many tasks already and we can't add any more
@@ -4278,19 +4278,9 @@
try {
synchronized (mGlobalLock) {
final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
- TaskTile primary = null;
- TaskTile secondary = null;
- for (int i = dc.getStackCount() - 1; i >= 0; --i) {
- final TaskTile t = dc.getStackAt(i).asTile();
- if (t == null) {
- continue;
- }
- if (t.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- primary = t;
- } else if (t.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
- secondary = t;
- }
- }
+ final Task primary = dc.getRootSplitScreenPrimaryTask();
+ final Task secondary = dc.getTask(t -> t.mCreatedByOrganizer && t.isRootTask()
+ && t.inSplitScreenSecondaryWindowingMode());
if (primary == null || secondary == null) {
return;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7df731b..6365144 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -200,7 +200,6 @@
import android.view.Gravity;
import android.view.IDisplayWindowInsetsController;
import android.view.ISystemGestureExclusionListener;
-import android.window.ITaskOrganizer;
import android.view.IWindow;
import android.view.InputChannel;
import android.view.InputDevice;
@@ -217,6 +216,7 @@
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
+import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
@@ -456,6 +456,8 @@
private final Configuration mTmpConfiguration = new Configuration();
+ private ArrayList<Task> mTmpTasks = new ArrayList<>();
+
/** Remove this display when animation on it has completed. */
private boolean mDeferredRemoval;
@@ -654,8 +656,8 @@
private final RootWindowContainer.FindTaskResult
mTmpFindTaskResult = new RootWindowContainer.FindTaskResult();
- // When non-null, new stacks get put into this tile.
- TaskTile mLaunchTile = null;
+ // When non-null, new tasks get put into this root task.
+ Task mLaunchRootTask = null;
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
WindowStateAnimator winAnimator = w.mWinAnimator;
@@ -2128,12 +2130,13 @@
}
/** @return The primary split-screen task, and {@code null} otherwise. */
- ActivityStack getRootSplitScreenPrimaryTask() {
+ @Nullable ActivityStack getRootSplitScreenPrimaryTask() {
return mTaskContainers.getRootSplitScreenPrimaryTask();
}
- boolean hasSplitScreenPrimaryTask() {
- return getRootSplitScreenPrimaryTask() != null;
+ boolean isSplitScreenModeActivated() {
+ Task task = getRootSplitScreenPrimaryTask();
+ return task != null && task.hasChild();
}
ActivityStack getRootPinnedTask() {
@@ -2600,7 +2603,7 @@
}
amendWindowTapExcludeRegion(mTouchExcludeRegion);
// TODO(multi-display): Support docked stacks on secondary displays.
- if (mDisplayId == DEFAULT_DISPLAY && getRootSplitScreenPrimaryTask() != null) {
+ if (mDisplayId == DEFAULT_DISPLAY && isSplitScreenModeActivated()) {
mDividerControllerLocked.getTouchRegion(mTmpRect);
mTmpRegion.set(mTmpRect);
mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
@@ -2623,8 +2626,7 @@
// If the task is home stack and it is resizable and visible (top of its root task), we want
// to exclude the docked stack from touch so we need the entire screen area and not just a
// small portion which the home stack currently is resized to.
- if (task.isActivityTypeHome() && task.isVisible() && task.getStack().getTile() != null
- && task.isResizeable()) {
+ if (task.isActivityTypeHome() && task.isVisible() && task.isResizeable()) {
mDisplayContent.getBounds(mTmpRect);
} else {
task.getDimBounds(mTmpRect);
@@ -4328,15 +4330,8 @@
@VisibleForTesting
ActivityStack getTopStack() {
- // TODO(task-hierarchy): Just grab index -1 once tiles are in hierarchy.
- for (int i = mTaskContainers.getChildCount() - 1; i >= 0; --i) {
- final ActivityStack child = mTaskContainers.getChildAt(i);
- if (child instanceof TaskTile) {
- continue;
- }
- return child;
- }
- return null;
+ final int count = mTaskContainers.getChildCount();
+ return count > 0 ? mTaskContainers.getChildAt(count - 1) : null;
}
int getIndexOf(ActivityStack stack) {
@@ -4375,10 +4370,6 @@
}
private void addStackReferenceIfNeeded(ActivityStack stack) {
- // TODO(task-hierarchy): Remove when tiles are in hierarchy.
- if (stack instanceof TaskTile) {
- return;
- }
if (stack.isActivityTypeHome()) {
if (mRootHomeTask != null) {
if (!stack.isDescendantOf(mRootHomeTask)) {
@@ -4390,27 +4381,26 @@
mRootHomeTask = stack;
}
}
+
+ if (!stack.isRootTask()) {
+ return;
+ }
final int windowingMode = stack.getWindowingMode();
if (windowingMode == WINDOWING_MODE_PINNED) {
if (mRootPinnedTask != null) {
- if (!stack.isDescendantOf(mRootPinnedTask)) {
- throw new IllegalArgumentException(
- "addStackReferenceIfNeeded: pinned stack=" + mRootPinnedTask
- + " already exist on display=" + this + " stack=" + stack);
- }
- } else {
- mRootPinnedTask = stack;
+ throw new IllegalArgumentException(
+ "addStackReferenceIfNeeded: pinned stack=" + mRootPinnedTask
+ + " already exist on display=" + this + " stack=" + stack);
}
+ mRootPinnedTask = stack;
} else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
if (mRootSplitScreenPrimaryTask != null) {
- if (!stack.isDescendantOf(mRootSplitScreenPrimaryTask)) {
- throw new IllegalArgumentException("addStackReferenceIfNeeded:"
- + " split-screen-primary" + " stack=" + mRootSplitScreenPrimaryTask
- + " already exist on display=" + this + " stack=" + stack);
- }
- } else {
- mRootSplitScreenPrimaryTask = stack;
+ throw new IllegalArgumentException(
+ "addStackReferenceIfNeeded: split screen primary stack="
+ + mRootSplitScreenPrimaryTask
+ + " already exist on display=" + this + " stack=" + stack);
}
+ mRootSplitScreenPrimaryTask = stack;
}
}
@@ -4645,10 +4635,9 @@
// Apps and their containers are not allowed to specify an orientation while using
// root tasks...except for the home stack if it is not resizable and currently
// visible (top of) its root task.
- if (mRootHomeTask != null && mRootHomeTask.isVisible()
- && mRootHomeTask.getTile() != null) {
+ if (mRootHomeTask != null && mRootHomeTask.isVisible()) {
final Task topMost = mRootHomeTask.getTopMostTask();
- final boolean resizable = topMost == null && topMost.isResizeable();
+ final boolean resizable = topMost != null && topMost.isResizeable();
if (!(resizable && mRootHomeTask.matchParentBounds())) {
final int orientation = mRootHomeTask.getOrientation();
if (orientation != SCREEN_ORIENTATION_UNSET) {
@@ -4792,17 +4781,6 @@
mSplitScreenDividerAnchor = null;
}
}
-
- @Override
- void onChildPositionChanged(WindowContainer child) {
- // TODO(task-hierarchy): Move functionality to TaskTile when it's a proper parent.
- TaskTile tile = ((ActivityStack) child).getTile();
- if (tile == null) {
- return;
- }
- mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
- tile, false /* force */);
- }
}
private class WindowContainers extends DisplayChildWindowContainer<WindowContainer> {
@@ -4983,7 +4961,7 @@
private boolean skipImeWindowsDuringTraversal(DisplayContent dc) {
// We skip IME windows so they're processed just above their target, except
// in split-screen mode where we process the IME containers above the docked divider.
- return dc.mInputMethodTarget != null && !dc.hasSplitScreenPrimaryTask();
+ return dc.mInputMethodTarget != null && !dc.isSplitScreenModeActivated();
}
/** Like {@link #forAllWindows}, but ignores {@link #skipImeWindowsDuringTraversal} */
@@ -5657,6 +5635,14 @@
mAtmService.updateSleepIfNeededLocked();
}
+ void addStackReferenceIfNeeded(ActivityStack stack) {
+ mTaskContainers.addStackReferenceIfNeeded(stack);
+ }
+
+ void removeStackReferenceIfNeeded(ActivityStack stack) {
+ mTaskContainers.removeStackReferenceIfNeeded(stack);
+ }
+
void onStackRemoved(ActivityStack stack) {
if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
Slog.v(TAG_STACK, "removeStack: detaching " + stack + " from displayId=" + mDisplayId);
@@ -5703,6 +5689,14 @@
"positionStackAt: Can only have one task on display=" + this);
}
+ final boolean movingToTop = wasContained && position >= getStackCount() - 1;
+ // Reset mPreferredTopFocusableStack before positioning to top or {@link
+ // ActivityStackSupervisor#updateTopResumedActivityIfNeeded()} won't update the top
+ // resumed activity.
+ if (movingToTop && stack.isFocusable()) {
+ mPreferredTopFocusableStack = null;
+ }
+
// Since positionChildAt() is called during the creation process of pinned stacks,
// ActivityStack#getStack() can be null.
positionStackAt(position, stack, includingParents);
@@ -5712,7 +5706,7 @@
// we are looking for top focusable stack. The condition {@code wasContained} restricts the
// preferred stack is set only when moving an existing stack to top instead of adding a new
// stack that may be too early (e.g. in the middle of launching or reparenting).
- if (wasContained && position >= getStackCount() - 1 && stack.isFocusableAndVisible()) {
+ if (movingToTop && stack.isFocusableAndVisible()) {
mPreferredTopFocusableStack = stack;
} else if (mPreferredTopFocusableStack == stack) {
mPreferredTopFocusableStack = null;
@@ -5755,18 +5749,54 @@
/**
* Returns an existing stack compatible with the windowing mode and activity type or creates one
* if a compatible stack doesn't exist.
+ * @see #getOrCreateStack(int, int, boolean, Intent, Task, boolean)
+ */
+ ActivityStack getOrCreateStack(int windowingMode, int activityType, boolean onTop) {
+ return getOrCreateStack(windowingMode, activityType, onTop, null /* intent */,
+ null /* candidateTask */, false /* createdByOrganizer */);
+ }
+
+ /**
+ * When two level tasks are required for given windowing mode and activity type, returns an
+ * existing compatible root task or creates a new one.
+ * For one level task, the candidate task would be reused to also be the root task or create
+ * a new root task if no candidate task.
* @see #getStack(int, int)
* @see #createStack(int, int, boolean)
*/
- ActivityStack getOrCreateStack(int windowingMode, int activityType,
- boolean onTop) {
+ ActivityStack getOrCreateStack(int windowingMode, int activityType, boolean onTop,
+ Intent intent, Task candidateTask, boolean createdByOrganizer) {
if (!alwaysCreateStack(windowingMode, activityType)) {
ActivityStack stack = getStack(windowingMode, activityType);
if (stack != null) {
return stack;
}
+ } else if (candidateTask != null) {
+ final ActivityStack stack = (ActivityStack) candidateTask;
+ final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
+ if (isSplitScreenModeActivated()) {
+ final Task splitRootSecondary = getTask(t -> t.mCreatedByOrganizer && t.isRootTask()
+ && t.inSplitScreenSecondaryWindowingMode());
+ if (stack.getParent() == null) {
+ splitRootSecondary.addChild(stack, position);
+ } else if (stack.getParent() != splitRootSecondary) {
+ stack.reparent(splitRootSecondary, position);
+ }
+ } else if (stack.getDisplay() != this || !stack.isRootTask()) {
+ if (stack.getParent() == null) {
+ addStack(stack, position);
+ } else {
+ stack.reparent(this, onTop);
+ }
+ }
+ // Update windowing mode if necessary, e.g. moving a pinned task to fullscreen.
+ if (candidateTask.getWindowingMode() != windowingMode) {
+ candidateTask.setWindowingMode(windowingMode);
+ }
+ return stack;
}
- return createStack(windowingMode, activityType, onTop);
+ return createStack(windowingMode, activityType, onTop, null /*info*/, intent,
+ createdByOrganizer);
}
/**
@@ -5784,7 +5814,8 @@
// UNDEFINED windowing mode is a valid result and means that the new stack will inherit
// it's display's windowing mode.
windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType);
- return getOrCreateStack(windowingMode, activityType, onTop);
+ return getOrCreateStack(windowingMode, activityType, onTop, null /* intent */,
+ candidateTask, false /* createdByOrganizer */);
}
@VisibleForTesting
@@ -5793,7 +5824,8 @@
}
ActivityStack createStack(int windowingMode, int activityType, boolean onTop) {
- return createStack(windowingMode, activityType, onTop, null /*info*/, null /*intent*/);
+ return createStack(windowingMode, activityType, onTop, null /* info */, null /* intent */,
+ false /* createdByOrganizer */);
}
/**
@@ -5805,25 +5837,29 @@
* {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will
* be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
* @param onTop If true the stack will be created at the top of the display, else at the bottom.
+ * @param info The started activity info.
+ * @param intent The intent that started this task.
+ * @param createdByOrganizer @{code true} if this is created by task organizer, @{code false}
+ * otherwise.
* @return The newly created stack.
*/
ActivityStack createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info,
- Intent intent) {
+ Intent intent, boolean createdByOrganizer) {
if (mSingleTaskInstance && getStackCount() > 0) {
// Create stack on default display instead since this display can only contain 1 stack.
// TODO: Kinda a hack, but better that having the decision at each call point. Hoping
// this goes away once ActivityView is no longer using virtual displays.
return mRootWindowContainer.getDefaultDisplay().createStack(
- windowingMode, activityType, onTop, info, intent);
+ windowingMode, activityType, onTop, info, intent, createdByOrganizer);
}
- if (activityType == ACTIVITY_TYPE_UNDEFINED) {
+ if (activityType == ACTIVITY_TYPE_UNDEFINED && !createdByOrganizer) {
// Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
- // anything else should be passing it in anyways...
+ // anything else should be passing it in anyways...except for the task organizer.
activityType = ACTIVITY_TYPE_STANDARD;
}
- if (activityType != ACTIVITY_TYPE_STANDARD) {
+ 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.
ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
@@ -5842,39 +5878,39 @@
}
final int stackId = getNextStackId();
- return createStackUnchecked(windowingMode, activityType, stackId, onTop, info, intent);
+ return createStackUnchecked(windowingMode, activityType, stackId, onTop, info, intent,
+ createdByOrganizer);
}
- /** @return the tile to create the next stack in. */
- private TaskTile updateLaunchTile(int windowingMode) {
+ /** @return the root task to create the next task in. */
+ private Task updateLaunchRootTask(int windowingMode) {
if (!isSplitScreenWindowingMode(windowingMode)) {
- // Only split-screen windowing modes interact with tiles.
+ // Only split-screen windowing modes can do this currently...
return null;
}
for (int i = getStackCount() - 1; i >= 0; --i) {
- final TaskTile t = getStackAt(i).asTile();
- if (t == null || t.getRequestedOverrideWindowingMode() != windowingMode) {
+ final Task t = getStackAt(i);
+ if (!t.mCreatedByOrganizer || t.getRequestedOverrideWindowingMode() != windowingMode) {
continue;
}
- // If not already set, pick a launch tile which is not the one we are launching
- // into.
- if (mLaunchTile == null) {
+ // If not already set, pick a launch root which is not the one we are launching into.
+ if (mLaunchRootTask == null) {
for (int j = 0, n = getStackCount(); j < n; ++j) {
- TaskTile tt = getStackAt(j).asTile();
- if (tt != t) {
- mLaunchTile = tt;
+ final Task tt = getStackAt(j);
+ if (tt.mCreatedByOrganizer && tt != t) {
+ mLaunchRootTask = tt;
break;
}
}
}
return t;
}
- return mLaunchTile;
+ return mLaunchRootTask;
}
@VisibleForTesting
- ActivityStack createStackUnchecked(int windowingMode, int activityType,
- int stackId, boolean onTop, ActivityInfo info, Intent intent) {
+ ActivityStack createStackUnchecked(int windowingMode, int activityType, int stackId,
+ boolean onTop, ActivityInfo info, Intent intent, boolean createdByOrganizer) {
if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
+ "activity type.");
@@ -5884,19 +5920,25 @@
info.applicationInfo = new ApplicationInfo();
}
- TaskTile tile = updateLaunchTile(windowingMode);
- if (tile != null) {
- // Since this stack will be put into a tile, its windowingMode will be inherited.
+ // Task created by organizer are added as root.
+ Task launchRootTask = createdByOrganizer ? null : updateLaunchRootTask(windowingMode);
+ if (launchRootTask != null) {
+ // Since this stack will be put into a root task, its windowingMode will be inherited.
windowingMode = WINDOWING_MODE_UNDEFINED;
}
+
final ActivityStack stack = (ActivityStack) Task.create(mAtmService, stackId, activityType,
- info, intent);
- addStack(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
- stack.setWindowingMode(windowingMode, false /* animate */, false /* showRecents */,
- false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */,
- true /* creating */);
- if (tile != null) {
- tile.addChild(stack, 0 /* index */);
+ info, intent, createdByOrganizer);
+ if (launchRootTask != null) {
+ launchRootTask.addChild(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
+ if (onTop) {
+ positionStackAtTop((ActivityStack) launchRootTask, false /* includingParents */);
+ }
+ } else {
+ addStack(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
+ stack.setWindowingMode(windowingMode, false /* animate */, false /* showRecents */,
+ false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */,
+ true /* creating */);
}
return stack;
}
@@ -6031,7 +6073,7 @@
mTmpFindTaskResult.clear();
for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = getStackAt(stackNdx);
- if (!r.hasCompatibleActivityType(stack)) {
+ if (!r.hasCompatibleActivityType(stack) && stack.isLeafTask()) {
if (DEBUG_TASKS) {
Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) " + stack);
}
@@ -6103,7 +6145,15 @@
final int activityType = activityTypes[j];
for (int i = getStackCount() - 1; i >= 0; --i) {
final ActivityStack stack = getStackAt(i);
- if (stack.getActivityType() == activityType) {
+ // Collect the root tasks that are currently being organized.
+ if (stack.isOrganized()) {
+ for (int k = stack.getChildCount() - 1; k >= 0; --k) {
+ final ActivityStack childStack = (ActivityStack) stack.getChildAt(k);
+ if (childStack.getActivityType() == activityType) {
+ stacks.add(childStack);
+ }
+ }
+ } else if (stack.getActivityType() == activityType) {
stacks.add(stack);
}
}
@@ -6117,13 +6167,8 @@
void onSplitScreenModeDismissed() {
mAtmService.deferWindowLayout();
try {
- mLaunchTile = null;
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final TaskTile t = getStackAt(i).asTile();
- if (t != null) {
- t.removeAllChildren();
- }
- }
+ mLaunchRootTask = null;
+ moveSplitScreenTasksToFullScreen();
} finally {
final ActivityStack topFullscreenStack =
getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
@@ -6141,6 +6186,24 @@
}
}
+ private void moveSplitScreenTasksToFullScreen() {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ mTmpTasks.clear();
+ forAllTasks(task -> {
+ if (task.mCreatedByOrganizer && task.inSplitScreenWindowingMode() && task.hasChild()) {
+ mTmpTasks.add(task);
+ }
+ });
+
+ for (int i = mTmpTasks.size() - 1; i >= 0; i--) {
+ final Task root = mTmpTasks.get(i);
+ for (int j = 0; j < root.getChildCount(); j++) {
+ wct.reparent(root.getChildAt(j).mRemoteToken, null, true /* toTop */);
+ }
+ }
+ mAtmService.mWindowOrganizerController.applyTransaction(wct);
+ }
+
/**
* Returns true if the {@param windowingMode} is supported based on other parameters passed in.
* @param windowingMode The windowing mode we are checking support for.
@@ -6253,7 +6316,7 @@
}
}
- final boolean inSplitScreenMode = hasSplitScreenPrimaryTask();
+ final boolean inSplitScreenMode = isSplitScreenModeActivated();
if (!inSplitScreenMode
&& windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
// Switch to the display's windowing mode if we are not in split-screen mode and we are
@@ -6278,10 +6341,6 @@
}
boolean isTopNotPinnedStack(ActivityStack stack) {
- // TODO(task-hierarchy): Remove when tiles are in hierarchy.
- if (stack instanceof TaskTile) {
- return false;
- }
for (int i = getStackCount() - 1; i >= 0; --i) {
final ActivityStack current = getStackAt(i);
if (!current.inPinnedWindowingMode()) {
@@ -6503,7 +6562,7 @@
// If default display is in split-window mode, set windowing mode of the stack
// to split-screen secondary. Otherwise, set the windowing mode to undefined by
// default to let stack inherited the windowing mode from the new display.
- final int windowingMode = toDisplay.hasSplitScreenPrimaryTask()
+ final int windowingMode = toDisplay.isSplitScreenModeActivated()
? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
: WINDOWING_MODE_UNDEFINED;
stack.reparent(toDisplay, true /* onTop */);
@@ -6607,27 +6666,35 @@
* already top-most.
*/
ActivityStack getStackAbove(ActivityStack stack) {
- final int stackIndex = getIndexOf(stack) + 1;
- return (stackIndex < getStackCount()) ? getStackAt(stackIndex) : null;
+ final WindowContainer wc = stack.getParent();
+ final int index = wc.mChildren.indexOf(stack) + 1;
+ return (index < wc.mChildren.size()) ? (ActivityStack) wc.mChildren.get(index) : null;
}
/**
* Adjusts the {@param stack} behind the last visible stack in the display if necessary.
* Generally used in conjunction with {@link #moveStackBehindStack}.
*/
+ // TODO(b/151575894): Remove special stack movement methods.
void moveStackBehindBottomMostVisibleStack(ActivityStack stack) {
if (stack.shouldBeVisible(null)) {
// Skip if the stack is already visible
return;
}
- // Move the stack to the bottom to not affect the following visibility checks
- positionStackAtBottom(stack);
+ final boolean isRootTask = stack.isRootTask();
+ if (isRootTask) {
+ // Move the stack to the bottom to not affect the following visibility checks
+ positionStackAtBottom(stack);
+ } else {
+ stack.getParent().positionChildAt(POSITION_BOTTOM, stack, false /* includingParents */);
+ }
// Find the next position where the stack should be placed
- final int numStacks = getStackCount();
+ final int numStacks = isRootTask ? getStackCount() : stack.getParent().getChildCount();
for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
- final ActivityStack s = getStackAt(stackNdx);
+ final ActivityStack s = isRootTask ? getStackAt(stackNdx)
+ : (ActivityStack) stack.getParent().getChildAt(stackNdx);
if (s == stack) {
continue;
}
@@ -6636,7 +6703,12 @@
|| winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
if (s.shouldBeVisible(null) && isValidWindowingMode) {
// Move the provided stack to behind this stack
- positionStackAt(stack, Math.max(0, stackNdx - 1));
+ final int position = Math.max(0, stackNdx - 1);
+ if (isRootTask) {
+ positionStackAt(stack, position);
+ } else {
+ stack.getParent().positionChildAt(position, stack, false /*includingParents */);
+ }
break;
}
}
@@ -6652,15 +6724,25 @@
return;
}
+ final WindowContainer parent = stack.getParent();
+ if (parent == null || parent != behindStack.getParent()) {
+ return;
+ }
+
// Note that positionChildAt will first remove the given stack before inserting into the
// list, so we need to adjust the insertion index to account for the removed index
// TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
// position internally
- final int stackIndex = getIndexOf(stack);
- final int behindStackIndex = getIndexOf(behindStack);
+ final int stackIndex = parent.mChildren.indexOf(stack);
+ final int behindStackIndex = parent.mChildren.indexOf(behindStack);
final int insertIndex = stackIndex <= behindStackIndex
? behindStackIndex - 1 : behindStackIndex;
- positionStackAt(stack, Math.max(0, insertIndex));
+ final int position = Math.max(0, insertIndex);
+ if (stack.isRootTask()) {
+ positionStackAt(stack, position);
+ } else {
+ parent.positionChildAt(position, stack, false /* includingParents */);
+ }
}
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
@@ -6697,19 +6779,6 @@
return getHomeActivityForUser(mRootWindowContainer.mCurrentUser);
}
- // TODO(task-hierarchy): Remove when tiles are in hierarchy.
- void addTile(TaskTile tile) {
- mTaskContainers.addChild(tile, POSITION_BOTTOM);
- ITaskOrganizer organizer = mAtmService.mTaskOrganizerController.getTaskOrganizer(
- tile.getWindowingMode());
- tile.setTaskOrganizer(organizer);
- }
-
- // TODO(task-hierarchy): Remove when tiles are in hierarchy.
- void removeTile(TaskTile tile) {
- mTaskContainers.removeChild(tile);
- }
-
@Nullable
ActivityRecord getHomeActivityForUser(int userId) {
final ActivityStack homeStack = getRootHomeTask();
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 44034ed..6b39fd2 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -406,12 +406,11 @@
// 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 =
- mRootWindowContainer.getDefaultDisplay().getRootSplitScreenPrimaryTask();
- if (stack == null) {
+ final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
+ if (!display.isSplitScreenModeActivated()) {
return;
}
- mRootWindowContainer.getDefaultDisplay().onSplitScreenModeDismissed();
+ display.onSplitScreenModeDismissed();
}
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index adafdec..9089240 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -388,11 +388,12 @@
// surfaces needs to be done immediately.
mWindowManager.executeAppTransition();
- if (targetStack.getTile() != null) {
+ final Task rootTask = targetStack.getRootTask();
+ if (rootTask.isOrganized()) {
// Client state may have changed during the recents animation, so force
// send task info so the client can synchronize its state.
mService.mTaskOrganizerController.dispatchTaskInfoChanged(
- targetStack.mTile, true /* force */);
+ rootTask, true /* force */);
}
} catch (Exception e) {
Slog.e(TAG, "Failed to clean up recents activity", e);
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index ebf1bc9..d2ed48f 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1970,8 +1970,7 @@
final int focusStackId = topFocusedStack != null
? topFocusedStack.getRootTaskId() : INVALID_TASK_ID;
// We dismiss the docked stack whenever we switch users.
- final ActivityStack dockedStack = getDefaultDisplay().getRootSplitScreenPrimaryTask();
- if (dockedStack != null) {
+ if (getDefaultDisplay().isSplitScreenModeActivated()) {
getDefaultDisplay().onSplitScreenModeDismissed();
}
// Also dismiss the pinned stack whenever we switch users. Removing the pinned stack will
@@ -2110,20 +2109,18 @@
final ActivityStack stack;
if (singleActivity) {
stack = r.getRootTask();
+ stack.setWindowingMode(WINDOWING_MODE_PINNED);
} else {
- // In the case of multiple activities, we will create a new stack for it and then
- // move the PIP activity into the stack.
- // We will then perform a windowing mode change for both scenarios.
- stack = display.createStack(
- r.getRootTask().getRequestedOverrideWindowingMode(),
- r.getActivityType(), ON_TOP, r.info, r.intent);
+ // In the case of multiple activities, we will create a new task for it and then
+ // move the PIP activity into the task.
+ stack = display.createStack(WINDOWING_MODE_PINNED, r.getActivityType(), ON_TOP,
+ r.info, r.intent, false /* createdByOrganizer */);
+
// There are multiple activities in the task and moving the top activity should
// reveal/leave the other activities in their original task.
r.reparent(stack, MAX_VALUE, "moveActivityToStack");
}
- stack.setWindowingMode(WINDOWING_MODE_PINNED);
-
// Reset the state that indicates it can enter PiP while pausing after we've moved it
// to the pinned stack
r.supportsEnterPipOnTaskSwitch = false;
@@ -2799,16 +2796,19 @@
if (stack == null && r != null) {
stack = r.getRootTask();
}
+ int windowingMode = launchParams != null ? launchParams.mWindowingMode
+ : WindowConfiguration.WINDOWING_MODE_UNDEFINED;
if (stack != null) {
display = stack.getDisplay();
if (display != null && canLaunchOnDisplay(r, display.mDisplayId)) {
- int windowingMode = launchParams != null ? launchParams.mWindowingMode
- : WindowConfiguration.WINDOWING_MODE_UNDEFINED;
if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
windowingMode = display.resolveWindowingMode(r, options, candidateTask,
activityType);
}
- if (stack.isCompatible(windowingMode, activityType)) {
+ // Always allow organized tasks that created by organizer since the activity type
+ // of an organized task is decided by the activity type of its top child, which
+ // could be incompatible with the given windowing mode and activity type.
+ if (stack.isCompatible(windowingMode, activityType) || stack.mCreatedByOrganizer) {
return stack;
}
if (windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY
@@ -2826,6 +2826,10 @@
if (display == null || !canLaunchOnDisplay(r, display.mDisplayId)) {
display = getDefaultDisplay();
+ if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
+ windowingMode = display.resolveWindowingMode(r, options, candidateTask,
+ activityType);
+ }
}
return display.getOrCreateStack(r, options, candidateTask, activityType, onTop);
@@ -2916,10 +2920,8 @@
case ACTIVITY_TYPE_RECENTS: return r.isActivityTypeRecents();
case ACTIVITY_TYPE_ASSISTANT: return r.isActivityTypeAssistant();
}
- // TODO(task-hierarchy): Find another way to differentiate tile from normal stack once it is
- // part of the hierarchy
- if (stack instanceof TaskTile) {
- // Don't launch directly into tiles.
+ if (stack.mCreatedByOrganizer) {
+ // Don't launch directly into task created by organizer...but why can't we?
return false;
}
// There is a 1-to-1 relationship between stack and task when not in
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index cd4fb3d..7dd38e1 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -114,7 +114,6 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
-import android.graphics.Point;
import android.graphics.Rect;
import android.os.Debug;
import android.os.IBinder;
@@ -489,6 +488,17 @@
PictureInPictureParams mPictureInPictureParams = new PictureInPictureParams.Builder().build();
/**
+ * This task was created by the task organizer which has the following implementations.
+ * <ul>
+ * <lis>The task won't be removed when it is empty. Removal has to be an explicit request
+ * from the task organizer.</li>
+ * <li>Unlike other non-root tasks, it's direct children are visible to the task
+ * organizer for ordering purposes.</li>
+ * </ul>
+ */
+ boolean mCreatedByOrganizer;
+
+ /**
* Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int,
* ActivityInfo, Intent, TaskDescription)} instead.
*/
@@ -1353,7 +1363,7 @@
if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) {
return applicationType;
}
- return getChildAt(0).getActivityType();
+ return getTopChild().getActivityType();
}
@Override
@@ -1366,6 +1376,12 @@
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this);
+ // A rootable task that is now being added to be the child of an organized task. Making
+ // sure the stack references is keep updated.
+ if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) {
+ mDisplayContent.addStackReferenceIfNeeded((ActivityStack) child);
+ }
+
// Make sure the list of display UID whitelists is updated
// now that this record is in a new task.
mRootWindowContainer.updateUIDsPresentOnDisplay();
@@ -1406,6 +1422,11 @@
@Override
void removeChild(WindowContainer child) {
+ // A rootable child task that is now being removed from an organized task. Making sure
+ // the stack references is keep updated.
+ if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) {
+ mDisplayContent.removeStackReferenceIfNeeded((ActivityStack) child);
+ }
removeChild(child, "removeChild");
}
@@ -1453,8 +1474,9 @@
mStackSupervisor.removeTask(this, false /* killProcess */,
!REMOVE_FROM_RECENTS, reason);
}
- } else if (!mReuseTask) {
+ } else if (!mReuseTask && !mCreatedByOrganizer) {
// Remove entire task if it doesn't have any activity left and it isn't marked for reuse
+ // or created by task organizer.
if (!isRootTask) {
getStack().removeChild(this, reason);
}
@@ -1866,7 +1888,12 @@
final Task parentTask = getParent().asTask();
if (parentTask != null) {
parentTask.onActivityStateChanged(record, state, reason);
- return;
+ // We still want to update the resumed activity if the parent task is created by
+ // organizer in order to keep the information synced once got reparented out from the
+ // organized task.
+ if (!parentTask.mCreatedByOrganizer) {
+ return;
+ }
}
if (record == mResumedActivity && state != RESUMED) {
@@ -2300,18 +2327,30 @@
return Configuration.reduceScreenLayout(sourceScreenLayout, longSize, shortSize);
}
- void resolveTileOverrideConfiguration(Configuration newParentConfig) {
+ private void resolveOrganizedOverrideConfiguration(Configuration newParentConfig) {
super.resolveOverrideConfiguration(newParentConfig);
+ if (!isOrganized()) {
+ return;
+ }
+
+ final Task root = getRootTask();
+ if (root == this) {
+ return;
+ }
+
+ // Ensure to have the same windowing mode for the child tasks that controlled by task org.
+ getResolvedOverrideConfiguration().windowConfiguration
+ .setWindowingMode(root.getWindowingMode());
}
@Override
void resolveOverrideConfiguration(Configuration newParentConfig) {
- if (!isLeafTask()) {
- resolveTileOverrideConfiguration(newParentConfig);
+ if (!isLeafTask() || mCreatedByOrganizer) {
+ resolveOrganizedOverrideConfiguration(newParentConfig);
return;
}
mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
- resolveTileOverrideConfiguration(newParentConfig);
+ resolveOrganizedOverrideConfiguration(newParentConfig);
int windowingMode =
getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
if (windowingMode == WINDOWING_MODE_UNDEFINED) {
@@ -2400,7 +2439,9 @@
}
Rect updateOverrideConfigurationFromLaunchBounds() {
- final Rect bounds = getLaunchBounds();
+ // If the task is controlled by another organized task, do not set override
+ // configurations and let its parent (organized task) to control it;
+ final Rect bounds = isOrganized() && !isRootTask() ? null : getLaunchBounds();
setBounds(bounds);
if (bounds != null && !bounds.isEmpty()) {
// TODO: Review if we actually want to do this - we are setting the launch bounds
@@ -2584,7 +2625,7 @@
// preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid.
if (suggestedPosition == POSITION_BOTTOM && minPosition == 0) {
return POSITION_BOTTOM;
- } else if (suggestedPosition == POSITION_TOP && maxPosition == (size - 1)) {
+ } else if (suggestedPosition == POSITION_TOP && maxPosition >= (size - 1)) {
return POSITION_TOP;
}
// Reset position based on minimum/maximum possible positions.
@@ -3368,14 +3409,12 @@
info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
info.configuration.setTo(getConfiguration());
info.token = mRemoteToken;
- // Get's the first non-undefined activity type among this and children. Can't use
- // configuration.windowConfiguration because that would only be this level.
- info.topActivityType = getActivityType();
//TODO (AM refactor): Just use local once updateEffectiveIntent is run during all child
// order changes.
final Task top = getTopMostTask();
info.resizeMode = top != null ? top.mResizeMode : mResizeMode;
+ info.topActivityType = top.getActivityType();
if (mPictureInPictureParams.empty()) {
info.pictureInPictureParams = null;
@@ -3406,10 +3445,6 @@
return this;
}
- TaskTile asTile() {
- return null;
- }
-
// TODO(task-merge): Figure-out how this should work with hierarchy tasks.
boolean shouldBeVisible(ActivityRecord starting) {
return true;
@@ -3705,8 +3740,9 @@
}
static Task create(ActivityTaskManagerService service, int taskId, int activityType,
- ActivityInfo info, Intent intent) {
- return getTaskFactory().create(service, taskId, activityType, info, intent);
+ ActivityInfo info, Intent intent, boolean createdByOrganizer) {
+ return getTaskFactory().create(service, taskId, activityType, info, intent,
+ createdByOrganizer);
}
static Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
@@ -3728,8 +3764,9 @@
*/
static class TaskFactory {
Task create(ActivityTaskManagerService service, int taskId, int activityType,
- ActivityInfo info, Intent intent) {
- return new ActivityStack(service, taskId, activityType, info, intent);
+ ActivityInfo info, Intent intent, boolean createdByOrganizer) {
+ return new ActivityStack(service, taskId, activityType, info, intent,
+ createdByOrganizer);
}
Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
@@ -4005,21 +4042,29 @@
@Override
boolean isOrganized() {
final Task rootTask = getRootTask();
- // if the rootTask is a "child" of a tile, then don't consider it a root task.
- // TODO: remove this along with removing tile.
- if (((ActivityStack) rootTask).getTile() != null) {
+ if (rootTask.mTaskOrganizer == null) {
+ // You are obviously not organized...
return false;
}
- return rootTask == this && rootTask.mTaskOrganizer != null;
+ if (rootTask == this) {
+ // Root tasks can be organized.
+ return true;
+ }
+ if (rootTask.mCreatedByOrganizer && getParent() == rootTask) {
+ // Direct children of tasks added by the organizer can the organized.
+ return true;
+ }
+
+ return false;
}
@Override
protected void reparentSurfaceControl(SurfaceControl.Transaction t, SurfaceControl newParent) {
/**
- * Avoid yanking back control from the TaskOrganizer, which has presumably reparented the
- * Surface in to its own hierarchy.
+ * Avoid reparenting SurfaceControl of the organized tasks that are always on top, since
+ * the surfaces should be controlled by the organizer itself, like bubbles.
*/
- if (isOrganized()) {
+ if (isOrganized() && isAlwaysOnTop()) {
return;
}
super.reparentSurfaceControl(t, newParent);
@@ -4054,6 +4099,9 @@
mTaskOrganizer = null;
mLastTaskOrganizerWindowingMode = -1;
onTaskOrganizerChanged();
+ if (mCreatedByOrganizer) {
+ removeImmediately();
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 5523678..05b721b 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
@@ -27,13 +28,14 @@
import android.annotation.Nullable;
import android.app.ActivityManager.RunningTaskInfo;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
-import android.window.ITaskOrganizerController;
import android.window.ITaskOrganizer;
+import android.window.ITaskOrganizerController;
import android.window.IWindowContainer;
import com.android.internal.util.ArrayUtils;
@@ -255,11 +257,12 @@
if (display == null) {
return null;
}
- final int nextId = display.getNextStackId();
- TaskTile tile = new TaskTile(mService, nextId, windowingMode);
- display.addTile(tile);
- RunningTaskInfo out = tile.getTaskInfo();
- mLastSentTaskInfos.put(tile, out);
+
+ final Task task = display.getOrCreateStack(windowingMode, ACTIVITY_TYPE_UNDEFINED,
+ false /* onTop */, new Intent(), null /* candidateTask */,
+ true /* createdByOrganizer */);
+ RunningTaskInfo out = task.getTaskInfo();
+ mLastSentTaskInfos.put(task, out);
return out;
}
} finally {
@@ -273,11 +276,13 @@
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- TaskTile tile = TaskTile.forToken(token.asBinder());
- if (tile == null) {
- return false;
+ final Task task = WindowContainer.fromBinder(token.asBinder()).asTask();
+ if (task == null) return false;
+ if (!task.mCreatedByOrganizer) {
+ throw new IllegalArgumentException(
+ "Attempt to delete task not created by organizer task=" + task);
}
- tile.removeImmediately();
+ task.removeImmediately();
return true;
}
} finally {
@@ -358,12 +363,7 @@
if (task == null) {
return null;
}
- ActivityStack rootTask = (ActivityStack) task.getRootTask();
- final TaskTile tile = rootTask.getTile();
- if (tile != null) {
- rootTask = tile;
- }
- return rootTask.mRemoteToken;
+ return task.getRootTask().mRemoteToken;
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -371,7 +371,7 @@
}
@Override
- public void setLaunchRoot(int displayId, @Nullable IWindowContainer tile) {
+ public void setLaunchRoot(int displayId, @Nullable IWindowContainer token) {
enforceStackPermission("setLaunchRoot()");
final long origId = Binder.clearCallingIdentity();
try {
@@ -380,16 +380,21 @@
if (display == null) {
return;
}
- TaskTile taskTile = tile == null ? null : TaskTile.forToken(tile.asBinder());
- if (taskTile == null) {
- display.mLaunchTile = null;
+ Task task = token == null
+ ? null : WindowContainer.fromBinder(token.asBinder()).asTask();
+ if (task == null) {
+ display.mLaunchRootTask = null;
return;
}
- if (taskTile.getDisplay() != display) {
- throw new RuntimeException("Can't set launch root for display " + displayId
- + " to task on display " + taskTile.getDisplay().getDisplayId());
+ if (!task.mCreatedByOrganizer) {
+ throw new IllegalArgumentException("Attempt to set task not created by "
+ + "organizer as launch root task=" + task);
}
- display.mLaunchTile = taskTile;
+ if (task.getDisplayContent() != display) {
+ throw new RuntimeException("Can't set launch root for display " + displayId
+ + " to task on display " + task.getDisplayContent().getDisplayId());
+ }
+ display.mLaunchRootTask = task;
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -411,25 +416,25 @@
Slog.e(TAG, "Can't get children of " + parent + " because it is not valid.");
return null;
}
- // For now, only support returning children of persistent root tasks (of which the
- // only current implementation is TaskTile).
- if (!(container instanceof TaskTile)) {
+ final Task task = container.asTask();
+ if (task == null) {
+ Slog.e(TAG, container + " is not a task...");
+ return null;
+ }
+ // For now, only support returning children of tasks created by the organizer.
+ if (!task.mCreatedByOrganizer) {
Slog.w(TAG, "Can only get children of root tasks created via createRootTask");
return null;
}
ArrayList<RunningTaskInfo> out = new ArrayList<>();
- // Tiles aren't real parents, so we need to go through stacks on the display to
- // ensure correct ordering.
- final DisplayContent dc = container.getDisplayContent();
- for (int i = dc.getStackCount() - 1; i >= 0; --i) {
- final ActivityStack as = dc.getStackAt(i);
- if (as.getTile() == container) {
- if (activityTypes != null
- && !ArrayUtils.contains(activityTypes, as.getActivityType())) {
- continue;
- }
- out.add(as.getTaskInfo());
+ for (int i = task.getChildCount() - 1; i >= 0; --i) {
+ final Task child = task.getChildAt(i).asTask();
+ if (child == null) continue;
+ if (activityTypes != null
+ && !ArrayUtils.contains(activityTypes, child.getActivityType())) {
+ continue;
}
+ out.add(child.getTaskInfo());
}
return out;
}
@@ -451,12 +456,7 @@
}
ArrayList<RunningTaskInfo> out = new ArrayList<>();
for (int i = dc.getStackCount() - 1; i >= 0; --i) {
- final ActivityStack task = dc.getStackAt(i);
- if (task.getTile() != null) {
- // a tile is supposed to look like a parent, so don't include their
- // "children" here. They can be accessed via getChildTasks()
- continue;
- }
+ final Task task = dc.getStackAt(i);
if (activityTypes != null
&& !ArrayUtils.contains(activityTypes, task.getActivityType())) {
continue;
diff --git a/services/core/java/com/android/server/wm/TaskTile.java b/services/core/java/com/android/server/wm/TaskTile.java
deleted file mode 100644
index 51142b1..0000000
--- a/services/core/java/com/android/server/wm/TaskTile.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
-
-import android.app.ActivityManager;
-import android.app.TaskInfo;
-import android.app.WindowConfiguration;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.os.IBinder;
-import android.util.Slog;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.function.Consumer;
-
-/**
- * A Tile. Right now this acts as a proxy for manipulating non-child stacks. Eventually, this
- * can become an actual parent.
- */
-// TODO(task-hierarchy): Remove when tasks can nest >2 or when single tasks can handle their
-// own lifecycles.
-public class TaskTile extends ActivityStack {
- private static final String TAG = "TaskTile";
- final ArrayList<WindowContainer> mChildren = new ArrayList<>();
-
- private static ActivityInfo createEmptyActivityInfo() {
- ActivityInfo info = new ActivityInfo();
- info.applicationInfo = new ApplicationInfo();
- return info;
- }
-
- TaskTile(ActivityTaskManagerService atmService, int id, int windowingMode) {
- super(atmService, id, new Intent() /*intent*/, null /*affinityIntent*/, null /*affinity*/,
- null /*rootAffinity*/, null /*realActivity*/, null /*origActivity*/,
- false /*rootWasReset*/, false /*autoRemoveRecents*/, false /*askedCompatMode*/,
- 0 /*userId*/, 0 /*effectiveUid*/, null /*lastDescription*/,
- System.currentTimeMillis(), true /*neverRelinquishIdentity*/,
- new ActivityManager.TaskDescription(), id, INVALID_TASK_ID, INVALID_TASK_ID,
- 0 /*taskAffiliationColor*/, 0 /*callingUid*/, "" /*callingPackage*/,
- null /*callingFeatureId*/, RESIZE_MODE_RESIZEABLE,
- false /*supportsPictureInPicture*/, false /*_realActivitySuspended*/,
- false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE,
- createEmptyActivityInfo(), null /*voiceSession*/, null /*voiceInteractor*/,
- null /*stack*/);
- getRequestedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode);
- }
-
- @Override
- void onDisplayChanged(DisplayContent dc) {
- mDisplayContent = null;
- if (dc != null) {
- dc.getPendingTransaction().merge(getPendingTransaction());
- }
- mDisplayContent = dc;
- // Virtual parent, so don't notify children.
- }
-
- @Override
- TaskTile asTile() {
- return this;
- }
-
- @Override
- protected void addChild(WindowContainer child, Comparator<WindowContainer> comparator) {
- throw new RuntimeException("Improper use of addChild() on Tile");
- }
-
- @Override
- void addChild(WindowContainer child, int index) {
- mChildren.add(child);
- if (child instanceof ActivityStack) {
- ((ActivityStack) child).setTile(this);
- }
- mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
- this, false /* force */);
- }
-
- @Override
- void removeChild(WindowContainer child) {
- if (child instanceof ActivityStack) {
- ((ActivityStack) child).setTile(null);
- }
- mChildren.remove(child);
- mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
- this, false /* force */);
- }
-
- void removeAllChildren() {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowContainer child = mChildren.get(i);
- if (child instanceof ActivityStack) {
- ((ActivityStack) child).setTile(null);
- }
- }
- mChildren.clear();
- mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
- this, false /* force */);
- }
-
- @Override
- protected int getChildCount() {
- // Currently 0 as this isn't a proper hierarchy member yet.
- return 0;
- }
-
- @Override
- public void setWindowingMode(/*@WindowConfiguration.WindowingMode*/ int windowingMode) {
- Configuration c = new Configuration(getRequestedOverrideConfiguration());
- c.windowConfiguration.setWindowingMode(windowingMode);
- onRequestedOverrideConfigurationChanged(c);
- }
-
- @Override
- public void onConfigurationChanged(Configuration newParentConfig) {
- super.onConfigurationChanged(newParentConfig);
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowContainer child = mChildren.get(i);
- child.onConfigurationChanged(child.getParent().getConfiguration());
- }
- }
-
- void forAllTileActivities(Consumer<ActivityRecord> callback) {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- mChildren.get(i).forAllActivities(callback, true /* traverseTopToBottom */);
- }
- }
-
- /**
- * Until this can be part of the hierarchy, the Stack level can use this utility during
- * resolveOverrideConfig to simulate inheritance.
- */
- void updateResolvedConfig(Configuration inOutResolvedConfig) {
- Rect resolveBounds = inOutResolvedConfig.windowConfiguration.getBounds();
- if (resolveBounds.isEmpty()) {
- resolveBounds.set(getRequestedOverrideBounds());
- }
- int stackMode = inOutResolvedConfig.windowConfiguration.getWindowingMode();
- if (stackMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED
- || stackMode == WindowConfiguration.WINDOWING_MODE_FULLSCREEN) {
- // Also replace FULLSCREEN because we interpret FULLSCREEN as "fill parent"
- inOutResolvedConfig.windowConfiguration.setWindowingMode(
- getRequestedOverrideWindowingMode());
- }
- if (inOutResolvedConfig.smallestScreenWidthDp
- == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
- inOutResolvedConfig.smallestScreenWidthDp =
- getRequestedOverrideConfiguration().smallestScreenWidthDp;
- }
- if (inOutResolvedConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
- inOutResolvedConfig.screenWidthDp = getRequestedOverrideConfiguration().screenWidthDp;
- }
- if (inOutResolvedConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
- inOutResolvedConfig.screenHeightDp = getRequestedOverrideConfiguration().screenHeightDp;
- }
- Rect resolveAppBounds = inOutResolvedConfig.windowConfiguration.getAppBounds();
- if (resolveAppBounds == null || resolveAppBounds.isEmpty()) {
- inOutResolvedConfig.windowConfiguration.setAppBounds(
- getRequestedOverrideConfiguration().windowConfiguration.getAppBounds());
- }
- }
-
- @Override
- void fillTaskInfo(TaskInfo info) {
- super.fillTaskInfo(info);
- WindowContainer top = null;
- // Check mChildren.isEmpty directly because hasChild() -> getChildCount() always returns 0
- if (!mChildren.isEmpty()) {
- // Find the top-most root task which is a virtual child of this Tile. Because this is a
- // virtual parent, the mChildren order here isn't changed during hierarchy operations.
- WindowContainer parent = mChildren.get(0).getParent();
- for (int i = parent.getChildCount() - 1; i >= 0; --i) {
- if (mChildren.contains(parent.getChildAt(i))) {
- top = parent.getChildAt(i);
- break;
- }
- }
- }
- final Task topTask = top == null ? null : top.getTopMostTask();
- boolean isResizable = topTask == null || topTask.isResizeable();
- info.resizeMode = isResizable ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_UNRESIZEABLE;
- info.topActivityType = top == null ? ACTIVITY_TYPE_UNDEFINED : top.getActivityType();
- }
-
- @Override
- void removeImmediately() {
- removeAllChildren();
- super.removeImmediately();
- }
-
- @Override
- void taskOrganizerDied() {
- super.taskOrganizerDied();
- removeImmediately();
- }
-
- static TaskTile forToken(IBinder token) {
- try {
- return (TaskTile) ((RemoteToken) token).getContainer();
- } catch (ClassCastException e) {
- Slog.w(TAG, "Bad tile token: " + token, e);
- return null;
- }
- }
-}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index e416e80..5f21e17 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -159,17 +159,7 @@
false /* preserveWindow */);
try {
for (int i = haveConfigChanges.size() - 1; i >= 0; --i) {
- final WindowContainer wc = haveConfigChanges.valueAt(i);
- final Task task = wc.asTask();
- final TaskTile tile = task != null ? task.asTile() : null;
- if (tile != null) {
- // Special case for tile. Can't override normal forAllActivities
- // because it generates duplicate calls and messes up existing
- // code-paths.
- tile.forAllTileActivities(f);
- } else {
- wc.forAllActivities(f);
- }
+ haveConfigChanges.valueAt(i).forAllActivities(f);
}
} finally {
f.recycle();
@@ -223,51 +213,65 @@
private int sanitizeAndApplyHierarchyOp(WindowContainer container,
WindowContainerTransaction.HierarchyOp hop) {
- if (!(container instanceof Task)) {
+ final Task task = container.asTask();
+ if (task == null) {
throw new IllegalArgumentException("Invalid container in hierarchy op");
}
- if (container.getDisplayContent() == null) {
- Slog.w(TAG, "Container is no longer attached: " + container);
+ final DisplayContent dc = task.getDisplayContent();
+ if (dc == null) {
+ Slog.w(TAG, "Container is no longer attached: " + task);
return 0;
}
+ final ActivityStack as = (ActivityStack) task;
+
if (hop.isReparent()) {
- // special case for tiles since they are "virtual" parents
- if (container instanceof ActivityStack && ((ActivityStack) container).isRootTask()) {
- ActivityStack as = (ActivityStack) container;
- TaskTile newParent = hop.getNewParent() == null ? null
- : (TaskTile) WindowContainer.fromBinder(hop.getNewParent());
- if (as.getTile() != newParent) {
- if (as.getTile() != null) {
- as.getTile().removeChild(as);
+ final boolean isNonOrganizedRootableTask =
+ (task.isRootTask() && !task.mCreatedByOrganizer)
+ || task.getParent().asTask().mCreatedByOrganizer;
+ if (isNonOrganizedRootableTask) {
+ Task newParent = hop.getNewParent() == null ? null
+ : WindowContainer.fromBinder(hop.getNewParent()).asTask();
+ if (task.getParent() != newParent) {
+ if (newParent == null) {
+ // Re-parent task to display as a root task.
+ dc.moveStackToDisplay(as, hop.getToTop());
+ } else if (newParent.inMultiWindowMode() && !task.isResizeable()
+ && task.isLeafTask()) {
+ Slog.w(TAG, "Can't support task that doesn't support multi-window mode in"
+ + " multi-window mode... newParent=" + newParent + " task=" + task);
+ return 0;
+ } else {
+ // Clear the window crop on root task since it may not be updated after
+ // reparent (no longer be a root task)
+ task.getSurfaceControl().setWindowCrop(null);
+ task.reparent((ActivityStack) newParent,
+ hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM,
+ false /*moveParents*/, "sanitizeAndApplyHierarchyOp");
}
- if (newParent != null) {
- if (!as.affectedBySplitScreenResize()) {
- return 0;
- }
- newParent.addChild(as, POSITION_TOP);
- }
- }
- if (hop.getToTop()) {
- as.getDisplay().positionStackAtTop(as, false /* includingParents */);
} else {
- as.getDisplay().positionStackAtBottom(as);
+ final ActivityStack rootTask =
+ (ActivityStack) (newParent != null ? newParent : task.getRootTask());
+ if (hop.getToTop()) {
+ as.getDisplay().positionStackAtTop(rootTask, false /* includingParents */);
+ } else {
+ as.getDisplay().positionStackAtBottom(rootTask);
+ }
}
- } else if (container instanceof Task) {
+ } else {
throw new RuntimeException("Reparenting leaf Tasks is not supported now.");
}
} else {
// Ugh, of course ActivityStack has its own special reorder logic...
- if (container instanceof ActivityStack && ((ActivityStack) container).isRootTask()) {
- ActivityStack as = (ActivityStack) container;
+ if (task.isRootTask()) {
if (hop.getToTop()) {
- as.getDisplay().positionStackAtTop(as, false /* includingParents */);
+ dc.positionStackAtTop(as, false /* includingParents */);
} else {
- as.getDisplay().positionStackAtBottom(as);
+ dc.positionStackAtBottom(as);
}
} else {
- container.getParent().positionChildAt(
+ task.getParent().positionChildAt(
hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM,
- container, false /* includingParents */);
+ task, false /* includingParents */);
}
}
return TRANSACT_EFFECTS_LIFECYCLE;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 161152b..0338cc3 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -131,6 +131,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.H.WINDOW_STATE_BLAST_SYNC_TIMEOUT;
import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
@@ -138,7 +139,6 @@
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
-import static com.android.server.wm.WindowManagerService.H.WINDOW_STATE_BLAST_SYNC_TIMEOUT;
import static com.android.server.wm.WindowStateAnimator.COMMIT_DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
@@ -3338,7 +3338,7 @@
}
final ActivityStack stack = task.getStack();
- if (stack == null) {
+ if (stack == null || stack.mCreatedByOrganizer) {
return;
}