Remove StackWindowController and StackWindowListener (46/n)
TaskStack and ActivityStack hold each other as a member. ActivityStack
will create TaskStack while constructing.
Moved all pinned specific stack into general one.
PinnedStackWindowController, PinnedActivityStack are removed.
Test: go/wm-smoke
Test: atest WmTests
Bug: 80414790
Change-Id: I63e3ec429576ec62960d0280b048883a8ed5145c
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 1f638c7..0616846 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -278,12 +278,12 @@
}
// Since positionChildAt() is called during the creation process of pinned stacks,
- // ActivityStack#getWindowContainerController() can be null. In this special case,
+ // ActivityStack#getStack() can be null. In this special case,
// since DisplayContest#positionStackAt() is called in TaskStack#onConfigurationChanged(),
// we don't have to call WindowContainerController#positionChildAt() here.
- if (stack.getWindowContainerController() != null && mDisplayContent != null) {
+ if (stack.getTaskStack() != null && mDisplayContent != null) {
mDisplayContent.positionStackAt(insertPosition,
- stack.getWindowContainerController().mContainer, includingParents);
+ stack.getTaskStack(), includingParents);
}
if (!wasContained) {
stack.setParent(this);
@@ -450,13 +450,12 @@
@VisibleForTesting
<T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
int stackId, boolean onTop) {
- if (windowingMode == WINDOWING_MODE_PINNED) {
- return (T) new PinnedActivityStack(this, stackId,
- mRootActivityContainer.mStackSupervisor, onTop);
+ if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
+ throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
+ + "activity type.");
}
return (T) new ActivityStack(this, stackId,
- mRootActivityContainer.mStackSupervisor, windowingMode, activityType,
- onTop);
+ mRootActivityContainer.mStackSupervisor, windowingMode, activityType, onTop);
}
/**
@@ -1019,8 +1018,8 @@
return mSplitScreenPrimaryStack != null;
}
- PinnedActivityStack getPinnedStack() {
- return (PinnedActivityStack) mPinnedStack;
+ ActivityStack getPinnedStack() {
+ return mPinnedStack;
}
boolean hasPinnedStack() {
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 4d7de90..891c3da 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -114,6 +114,7 @@
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.IActivityController;
+import android.app.RemoteAction;
import android.app.ResultInfo;
import android.app.WindowConfiguration.ActivityType;
import android.app.WindowConfiguration.WindowingMode;
@@ -173,8 +174,7 @@
/**
* State and management of a single stack of activities.
*/
-class ActivityStack<T extends StackWindowController> extends ConfigurationContainer
- implements StackWindowListener {
+class ActivityStack extends ConfigurationContainer {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_ATM;
private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
private static final String TAG_APP = TAG + POSTFIX_APP;
@@ -297,8 +297,7 @@
static final int REMOVE_TASK_MODE_MOVING_TO_TOP = 2;
final ActivityTaskManagerService mService;
- private final WindowManagerService mWindowManager;
- T mWindowContainerController;
+ final WindowManagerService mWindowManager;
/**
* The back history of all previous (and possibly still
@@ -397,6 +396,9 @@
static final int DESTROY_ACTIVITIES_MSG = FIRST_ACTIVITY_STACK_MSG + 5;
static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 6;
+ // TODO: remove after unification.
+ TaskStack mTaskStack;
+
private static class ScheduleDestroyArgs {
final WindowProcessController mOwner;
final String mReason;
@@ -495,21 +497,30 @@
// stacks on a wrong display.
mDisplayId = display.mDisplayId;
setActivityType(activityType);
- mWindowContainerController = createStackWindowController(display.mDisplayId, onTop,
- mTmpRect2);
+ createTaskStack(display.mDisplayId, onTop, mTmpRect2);
setWindowingMode(windowingMode, false /* animate */, false /* showRecents */,
false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */,
true /* creating */);
display.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM);
}
- T createStackWindowController(int displayId, boolean onTop, Rect outBounds) {
- return (T) new StackWindowController(mStackId, this, displayId, onTop, outBounds,
- mRootActivityContainer.mWindowManager);
+ void createTaskStack(int displayId, boolean onTop, Rect outBounds) {
+ final DisplayContent dc = mWindowManager.mRoot.getDisplayContent(displayId);
+ if (dc == null) {
+ throw new IllegalArgumentException("Trying to add stackId=" + mStackId
+ + " to unknown displayId=" + displayId);
+ }
+ mTaskStack = new TaskStack(mWindowManager, mStackId, this);
+ dc.setStackOnDisplay(mStackId, onTop, mTaskStack);
+ if (mTaskStack.matchParentBounds()) {
+ outBounds.setEmpty();
+ } else {
+ mTaskStack.getRawBounds(outBounds);
+ }
}
- T getWindowContainerController() {
- return mWindowContainerController;
+ TaskStack getTaskStack() {
+ return mTaskStack;
}
/**
@@ -553,6 +564,9 @@
if (display == null) {
return;
}
+ if (getTaskStack() == null) {
+ return;
+ }
// Update bounds if applicable
boolean hasNewOverrideBounds = false;
@@ -560,8 +574,7 @@
if (getRequestedOverrideWindowingMode() == WINDOWING_MODE_PINNED) {
// Pinned calculation already includes rotation
mTmpRect2.set(mTmpRect);
- hasNewOverrideBounds = getWindowContainerController().mContainer
- .calculatePinnedBoundsForConfigChange(mTmpRect2);
+ hasNewOverrideBounds = getTaskStack().calculatePinnedBoundsForConfigChange(mTmpRect2);
} else {
final int newRotation = getWindowConfiguration().getRotation();
if (!matchParentBounds()) {
@@ -588,7 +601,7 @@
|| getRequestedOverrideWindowingMode()
== WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
mTmpRect2.set(mTmpRect);
- getWindowContainerController().mContainer
+ getTaskStack()
.calculateDockedBoundsForConfigChange(newParentConfig, mTmpRect2);
hasNewOverrideBounds = true;
}
@@ -786,7 +799,11 @@
mTmpRect2.setEmpty();
if (windowingMode != WINDOWING_MODE_FULLSCREEN) {
- mWindowContainerController.getRawBounds(mTmpRect2);
+ if (mTaskStack.matchParentBounds()) {
+ mTmpRect2.setEmpty();
+ } else {
+ mTaskStack.getRawBounds(mTmpRect2);
+ }
}
if (!Objects.equals(getRequestedOverrideBounds(), mTmpRect2)) {
@@ -843,7 +860,12 @@
// Reparent the window container before we try to update the position when adding it to
// the new display below
mTmpRect2.setEmpty();
- mWindowContainerController.reparent(activityDisplay.mDisplayId, mTmpRect2, onTop);
+ if (mTaskStack == null) {
+ // TODO: Remove after unification.
+ Log.w(TAG, "Task stack is not valid when reparenting.");
+ } else {
+ mTaskStack.reparent(activityDisplay.mDisplayId, mTmpRect2, onTop);
+ }
setBounds(mTmpRect2.isEmpty() ? null : mTmpRect2);
activityDisplay.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM);
if (!displayRemoved) {
@@ -876,8 +898,10 @@
/** Removes the stack completely. Also calls WindowManager to do the same on its side. */
void remove() {
removeFromDisplay();
- mWindowContainerController.removeContainer();
- mWindowContainerController = null;
+ if (mTaskStack != null) {
+ mTaskStack.removeIfPossible();
+ mTaskStack = null;
+ }
onParentChanged();
}
@@ -890,26 +914,35 @@
*/
void getStackDockedModeBounds(Rect dockedBounds, Rect currentTempTaskBounds,
Rect outStackBounds, Rect outTempTaskBounds) {
- mWindowContainerController.getStackDockedModeBounds(getParent().getConfiguration(),
- dockedBounds, currentTempTaskBounds,
- outStackBounds, outTempTaskBounds);
+ if (mTaskStack != null) {
+ mTaskStack.getStackDockedModeBoundsLocked(getParent().getConfiguration(), dockedBounds,
+ currentTempTaskBounds, outStackBounds, outTempTaskBounds);
+ } else {
+ outStackBounds.setEmpty();
+ outTempTaskBounds.setEmpty();
+ }
}
void prepareFreezingTaskBounds() {
- mWindowContainerController.prepareFreezingTaskBounds();
+ if (mTaskStack != null) {
+ // TODO: This cannot be false after unification.
+ mTaskStack.prepareFreezingTaskBounds();
+ }
}
void getWindowContainerBounds(Rect outBounds) {
- if (mWindowContainerController != null) {
- mWindowContainerController.getBounds(outBounds);
+ if (mTaskStack != null) {
+ mTaskStack.getBounds(outBounds);
return;
}
outBounds.setEmpty();
}
void positionChildWindowContainerAtTop(TaskRecord child) {
- mWindowContainerController.positionChildAtTop(child.getTask(),
- true /* includingParents */);
+ if (mTaskStack != null) {
+ // TODO: Remove after unification. This cannot be false after that.
+ mTaskStack.positionChildAtTop(child.getTask(), true /* includingParents */);
+ }
}
void positionChildWindowContainerAtBottom(TaskRecord child) {
@@ -918,14 +951,27 @@
// task to bottom, the next focusable stack on the same display should be focused.
final ActivityStack nextFocusableStack = getDisplay().getNextFocusableStack(
child.getStack(), true /* ignoreCurrent */);
- mWindowContainerController.positionChildAtBottom(child.getTask(),
- nextFocusableStack == null /* includingParents */);
+ if (mTaskStack != null) {
+ // TODO: Remove after unification. This cannot be false after that.
+ mTaskStack.positionChildAtBottom(child.getTask(),
+ nextFocusableStack == null /* includingParents */);
+ }
}
/**
* Returns whether to defer the scheduling of the multi-window mode.
*/
boolean deferScheduleMultiWindowModeChanged() {
+ if (inPinnedWindowingMode()) {
+ // For the pinned stack, the deferring of the multi-window mode changed is tied to the
+ // transition animation into picture-in-picture, and is called once the animation
+ // completes, or is interrupted in a way that would leave the stack in a non-fullscreen
+ // state.
+ // @see BoundsAnimationController
+ // @see BoundsAnimationControllerTests
+ if (getTaskStack() == null) return false;
+ return getTaskStack().deferScheduleMultiWindowModeChanged();
+ }
return false;
}
@@ -2994,7 +3040,10 @@
position = getAdjustedPositionForTask(task, position, null /* starting */);
mTaskHistory.remove(task);
mTaskHistory.add(position, task);
- mWindowContainerController.positionChildAt(task.getTask(), position);
+ if (mTaskStack != null) {
+ // TODO: this could not be false after unification.
+ mTaskStack.positionChildAt(task.getTask(), position);
+ }
updateTaskMovement(task, true);
}
@@ -4909,8 +4958,7 @@
}
// TODO: Figure-out a way to consolidate with resize() method below.
- @Override
- public void requestResize(Rect bounds) {
+ void requestResize(Rect bounds) {
mService.resizeStack(mStackId, bounds,
true /* allowResizeInDockedMode */, false /* preserveWindows */,
false /* animate */, -1 /* animationDuration */);
@@ -4948,7 +4996,8 @@
}
void onPipAnimationEndResize() {
- mWindowContainerController.onPipAnimationEndResize();
+ if (mTaskStack == null) return;
+ mTaskStack.onPipAnimationEndResize();
}
@@ -5494,6 +5543,65 @@
}
}
+
+ Rect getDefaultPictureInPictureBounds(float aspectRatio) {
+ if (getTaskStack() == null) return null;
+ return getTaskStack().getPictureInPictureBounds(aspectRatio, null /* currentStackBounds */);
+ }
+
+ void animateResizePinnedStack(Rect sourceHintBounds, Rect toBounds, int animationDuration,
+ boolean fromFullscreen) {
+ if (!inPinnedWindowingMode()) return;
+ if (skipResizeAnimation(toBounds == null /* toFullscreen */)) {
+ mService.moveTasksToFullscreenStack(mStackId, true /* onTop */);
+ } else {
+ if (getTaskStack() == null) return;
+ getTaskStack().animateResizePinnedStack(toBounds, sourceHintBounds,
+ animationDuration, fromFullscreen);
+ }
+ }
+
+ private boolean skipResizeAnimation(boolean toFullscreen) {
+ if (!toFullscreen) {
+ return false;
+ }
+ final Configuration parentConfig = getParent().getConfiguration();
+ final ActivityRecord top = topRunningNonOverlayTaskActivity();
+ return top != null && !top.isConfigurationCompatible(parentConfig);
+ }
+
+ void setPictureInPictureAspectRatio(float aspectRatio) {
+ if (getTaskStack() == null) return;
+ getTaskStack().setPictureInPictureAspectRatio(aspectRatio);
+ }
+
+ void setPictureInPictureActions(List<RemoteAction> actions) {
+ if (getTaskStack() == null) return;
+ getTaskStack().setPictureInPictureActions(actions);
+ }
+
+ boolean isAnimatingBoundsToFullscreen() {
+ if (getTaskStack() == null) return false;
+ return getTaskStack().isAnimatingBoundsToFullscreen();
+ }
+
+ public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
+ boolean forceUpdate) {
+ // It is guaranteed that the activities requiring the update will be in the pinned stack at
+ // this point (either reparented before the animation into PiP, or before reparenting after
+ // the animation out of PiP)
+ synchronized (mService.mGlobalLock) {
+ if (!isAttached()) {
+ return;
+ }
+ ArrayList<TaskRecord> tasks = getAllTasks();
+ for (int i = 0; i < tasks.size(); i++) {
+ mStackSupervisor.updatePictureInPictureMode(tasks.get(i), targetStackBounds,
+ forceUpdate);
+ }
+ }
+ }
+
public int getStackId() {
return mStackId;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index a50ae84..a4cda5a 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -1674,8 +1674,8 @@
}
void resizePinnedStackLocked(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
- // TODO(multi-display): Pinned stack display should be passed in.
- final PinnedActivityStack stack =
+ // TODO(multi-display): The display containing the stack should be passed in.
+ final ActivityStack stack =
mRootActivityContainer.getDefaultDisplay().getPinnedStack();
if (stack == null) {
Slog.w(TAG, "resizePinnedStackLocked: pinned stack not found");
@@ -1686,7 +1686,7 @@
// another AM call that is holding the AMS lock. In such a case, the pinnedBounds may be
// incorrect if AMS.resizeStackWithBoundsFromWindowManager() is already called while waiting
// for the AMS lock to be freed. So check and make sure these bounds are still good.
- final PinnedStackWindowController stackController = stack.getWindowContainerController();
+ final TaskStack stackController = stack.getTaskStack();
if (stackController.pinnedStackResizeDisallowed()) {
return;
}
@@ -1730,15 +1730,14 @@
* invisible as well and added to the stopping list. After which we process the
* stopping list by handling the idle.
*/
- final PinnedActivityStack pinnedStack = (PinnedActivityStack) stack;
- pinnedStack.mForceHidden = true;
- pinnedStack.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
- pinnedStack.mForceHidden = false;
+ stack.mForceHidden = true;
+ stack.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
+ stack.mForceHidden = false;
activityIdleInternalLocked(null, false /* fromTimeout */,
true /* processPausingActivites */, null /* configuration */);
// Move all the tasks to the bottom of the fullscreen stack
- moveTasksToFullscreenStackLocked(pinnedStack, !ON_TOP);
+ moveTasksToFullscreenStackLocked(stack, !ON_TOP);
} else {
for (int i = tasks.size() - 1; i >= 0; i--) {
removeTaskByIdLocked(tasks.get(i).taskId, true /* killProcess */,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index e82e748..fe5bc25 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -82,13 +82,10 @@
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.HOME_PROC;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.LAUNCHING_ACTIVITY;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC;
-import static com.android.server.am.ActivityManagerServiceDumpProcessesProto
- .PREVIOUS_PROC_VISIBLE_TIME_MS;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.SCREEN_COMPAT_PACKAGES;
-import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage
- .MODE;
-import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage
- .PACKAGE;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.MODE;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE;
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
@@ -245,7 +242,6 @@
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.server.appop.AppOpsService;
import com.android.server.AttributeCache;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -261,6 +257,7 @@
import com.android.server.am.PendingIntentController;
import com.android.server.am.PendingIntentRecord;
import com.android.server.am.UserState;
+import com.android.server.appop.AppOpsService;
import com.android.server.firewall.IntentFirewall;
import com.android.server.pm.UserManagerService;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -2407,7 +2404,7 @@
try {
synchronized (mGlobalLock) {
if (animate) {
- final PinnedActivityStack stack = mRootActivityContainer.getStack(stackId);
+ final ActivityStack stack = mRootActivityContainer.getStack(stackId);
if (stack == null) {
Slog.w(TAG, "resizeStack: stackId " + stackId + " not found.");
return;
@@ -3712,7 +3709,7 @@
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- final PinnedActivityStack stack =
+ final ActivityStack stack =
mRootActivityContainer.getDefaultDisplay().getPinnedStack();
if (stack == null) {
Slog.w(TAG, "dismissPip: pinned stack not found.");
@@ -3834,9 +3831,8 @@
// If we are animating to fullscreen then we have already dispatched the PIP mode
// changed, so we should reflect that check here as well.
- final PinnedActivityStack stack = r.getActivityStack();
- final PinnedStackWindowController windowController = stack.getWindowContainerController();
- return !windowController.mContainer.isAnimatingBoundsToFullscreen();
+ final TaskStack taskStack = r.getActivityStack().getTaskStack();
+ return !taskStack.isAnimatingBoundsToFullscreen();
}
@Override
@@ -3870,7 +3866,7 @@
r.pictureInPictureArgs.getSourceRectHint());
mRootActivityContainer.moveActivityToPinnedStack(
r, sourceBounds, aspectRatio, "enterPictureInPictureMode");
- final PinnedActivityStack stack = r.getActivityStack();
+ final ActivityStack stack = r.getActivityStack();
stack.setPictureInPictureAspectRatio(aspectRatio);
stack.setPictureInPictureActions(actions);
MetricsLoggerWrapper.logPictureInPictureEnter(mContext, r.appInfo.uid,
@@ -3914,7 +3910,7 @@
// If the activity is already in picture-in-picture, update the pinned stack now
// if it is not already expanding to fullscreen. Otherwise, the arguments will
// be used the next time the activity enters PiP
- final PinnedActivityStack stack = r.getActivityStack();
+ final ActivityStack stack = r.getActivityStack();
if (!stack.isAnimatingBoundsToFullscreen()) {
stack.setPictureInPictureAspectRatio(
r.pictureInPictureArgs.getAspectRatio());
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 740d472..50311c2 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2307,13 +2307,12 @@
out.set(mDisplayFrames.mStable);
}
- TaskStack createStack(int stackId, boolean onTop, StackWindowController controller) {
- if (DEBUG_STACK) Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId="
- + mDisplayId);
+ void setStackOnDisplay(int stackId, boolean onTop, TaskStack stack) {
+ if (DEBUG_STACK) {
+ Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId=" + mDisplayId);
+ }
- final TaskStack stack = new TaskStack(mWmService, stackId, controller);
mTaskStackContainers.addStackToDisplay(stack, onTop);
- return stack;
}
void moveStackToDisplay(TaskStack stack, boolean onTop) {
@@ -4015,7 +4014,6 @@
/**
* Adds the stack to this container.
- * @see DisplayContent#createStack(int, boolean, StackWindowController)
*/
void addStackToDisplay(TaskStack stack, boolean onTop) {
addStackReferenceIfNeeded(stack);
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index 3062d34..86dc66d 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -221,7 +221,7 @@
}
private boolean saveTaskToLaunchParam(TaskRecord task, PersistableLaunchParams params) {
- final ActivityStack<?> stack = task.getStack();
+ final ActivityStack stack = task.getStack();
final int displayId = stack.mDisplayId;
final ActivityDisplay display =
mSupervisor.mRootActivityContainer.getActivityDisplay(displayId);
diff --git a/services/core/java/com/android/server/wm/PinnedActivityStack.java b/services/core/java/com/android/server/wm/PinnedActivityStack.java
deleted file mode 100644
index 2a05af4..0000000
--- a/services/core/java/com/android/server/wm/PinnedActivityStack.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2017 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.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-
-import android.app.RemoteAction;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * State and management of the pinned stack of activities.
- */
-class PinnedActivityStack extends ActivityStack<PinnedStackWindowController>
- implements PinnedStackWindowListener {
-
- PinnedActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
- boolean onTop) {
- super(display, stackId, supervisor, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, onTop);
- }
-
- @Override
- PinnedStackWindowController createStackWindowController(int displayId, boolean onTop,
- Rect outBounds) {
- return new PinnedStackWindowController(mStackId, this, displayId, onTop, outBounds,
- mRootActivityContainer.mWindowManager);
- }
-
- Rect getDefaultPictureInPictureBounds(float aspectRatio) {
- return getWindowContainerController().getPictureInPictureBounds(aspectRatio,
- null /* currentStackBounds */);
- }
-
- void animateResizePinnedStack(Rect sourceHintBounds, Rect toBounds, int animationDuration,
- boolean fromFullscreen) {
- if (skipResizeAnimation(toBounds == null /* toFullscreen */)) {
- mService.moveTasksToFullscreenStack(mStackId, true /* onTop */);
- } else {
- getWindowContainerController().animateResizePinnedStack(toBounds, sourceHintBounds,
- animationDuration, fromFullscreen);
- }
- }
-
- private boolean skipResizeAnimation(boolean toFullscreen) {
- if (!toFullscreen) {
- return false;
- }
- final Configuration parentConfig = getParent().getConfiguration();
- final ActivityRecord top = topRunningNonOverlayTaskActivity();
- return top != null && !top.isConfigurationCompatible(parentConfig);
- }
-
- void setPictureInPictureAspectRatio(float aspectRatio) {
- getWindowContainerController().setPictureInPictureAspectRatio(aspectRatio);
- }
-
- void setPictureInPictureActions(List<RemoteAction> actions) {
- getWindowContainerController().setPictureInPictureActions(actions);
- }
-
- boolean isAnimatingBoundsToFullscreen() {
- return getWindowContainerController().mContainer.isAnimatingBoundsToFullscreen();
- }
-
- /**
- * Returns whether to defer the scheduling of the multi-window mode.
- */
- boolean deferScheduleMultiWindowModeChanged() {
- // For the pinned stack, the deferring of the multi-window mode changed is tied to the
- // transition animation into picture-in-picture, and is called once the animation completes,
- // or is interrupted in a way that would leave the stack in a non-fullscreen state.
- // @see BoundsAnimationController
- // @see BoundsAnimationControllerTests
- return mWindowContainerController.deferScheduleMultiWindowModeChanged();
- }
-
- public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
- boolean forceUpdate) {
- // It is guaranteed that the activities requiring the update will be in the pinned stack at
- // this point (either reparented before the animation into PiP, or before reparenting after
- // the animation out of PiP)
- synchronized (mService.mGlobalLock) {
- if (!isAttached()) {
- return;
- }
- ArrayList<TaskRecord> tasks = getAllTasks();
- for (int i = 0; i < tasks.size(); i++ ) {
- mStackSupervisor.updatePictureInPictureMode(tasks.get(i), targetStackBounds,
- forceUpdate);
- }
- }
- }
-}
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowController.java b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
deleted file mode 100644
index 518e39b..0000000
--- a/services/core/java/com/android/server/wm/PinnedStackWindowController.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2017 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.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-
-import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
-import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
-import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
-import static com.android.server.wm.BoundsAnimationController.SchedulePipModeChangedState;
-
-import android.app.RemoteAction;
-import android.graphics.Rect;
-
-import java.util.List;
-
-/**
- * Controller for the pinned stack container. See {@link StackWindowController}.
- */
-public class PinnedStackWindowController extends StackWindowController {
-
- private Rect mTmpFromBounds = new Rect();
- private Rect mTmpToBounds = new Rect();
-
- public PinnedStackWindowController(int stackId, PinnedStackWindowListener listener,
- int displayId, boolean onTop, Rect outBounds, WindowManagerService service) {
- super(stackId, listener, displayId, onTop, outBounds, service);
- }
-
- /**
- * @return the {@param currentStackBounds} transformed to the give {@param aspectRatio}. If
- * {@param currentStackBounds} is null, then the {@param aspectRatio} is applied to the
- * default bounds.
- */
- public Rect getPictureInPictureBounds(float aspectRatio, Rect stackBounds) {
- synchronized (mGlobalLock) {
- if (!mService.mSupportsPictureInPicture || mContainer == null) {
- return null;
- }
-
- final DisplayContent displayContent = mContainer.getDisplayContent();
- if (displayContent == null) {
- return null;
- }
-
- final PinnedStackController pinnedStackController =
- displayContent.getPinnedStackController();
- if (stackBounds == null) {
- // Calculate the aspect ratio bounds from the default bounds
- stackBounds = pinnedStackController.getDefaultOrLastSavedBounds();
- }
-
- if (pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)) {
- return pinnedStackController.transformBoundsToAspectRatio(stackBounds, aspectRatio,
- true /* useCurrentMinEdgeSize */);
- } else {
- return stackBounds;
- }
- }
- }
-
- /**
- * Animates the pinned stack.
- */
- public void animateResizePinnedStack(Rect toBounds, Rect sourceHintBounds,
- int animationDuration, boolean fromFullscreen) {
- synchronized (mGlobalLock) {
- if (mContainer == null) {
- throw new IllegalArgumentException("Pinned stack container not found :(");
- }
-
- // Get the from-bounds
- final Rect fromBounds = new Rect();
- mContainer.getBounds(fromBounds);
-
- // Get non-null fullscreen to-bounds for animating if the bounds are null
- @SchedulePipModeChangedState int schedulePipModeChangedState =
- NO_PIP_MODE_CHANGED_CALLBACKS;
- final boolean toFullscreen = toBounds == null;
- if (toFullscreen) {
- if (fromFullscreen) {
- throw new IllegalArgumentException("Should not defer scheduling PiP mode"
- + " change on animation to fullscreen.");
- }
- schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_START;
-
- mService.getStackBounds(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mTmpToBounds);
- if (!mTmpToBounds.isEmpty()) {
- // If there is a fullscreen bounds, use that
- toBounds = new Rect(mTmpToBounds);
- } else {
- // Otherwise, use the display bounds
- toBounds = new Rect();
- mContainer.getDisplayContent().getBounds(toBounds);
- }
- } else if (fromFullscreen) {
- schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END;
- }
-
- mContainer.setAnimationFinalBounds(sourceHintBounds, toBounds, toFullscreen);
-
- final Rect finalToBounds = toBounds;
- final @SchedulePipModeChangedState int finalSchedulePipModeChangedState =
- schedulePipModeChangedState;
- final DisplayContent displayContent = mContainer.getDisplayContent();
- displayContent.mBoundsAnimationController.getHandler().post(() -> {
- if (mContainer == null) {
- return;
- }
- displayContent.mBoundsAnimationController.animateBounds(mContainer, fromBounds,
- finalToBounds, animationDuration, finalSchedulePipModeChangedState,
- fromFullscreen, toFullscreen);
- });
- }
- }
-
- /**
- * Sets the current picture-in-picture aspect ratio.
- */
- public void setPictureInPictureAspectRatio(float aspectRatio) {
- synchronized (mGlobalLock) {
- if (!mService.mSupportsPictureInPicture || mContainer == null) {
- return;
- }
-
- final PinnedStackController pinnedStackController =
- mContainer.getDisplayContent().getPinnedStackController();
-
- if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) != 0) {
- mContainer.getAnimationOrCurrentBounds(mTmpFromBounds);
- mTmpToBounds.set(mTmpFromBounds);
- getPictureInPictureBounds(aspectRatio, mTmpToBounds);
- if (!mTmpToBounds.equals(mTmpFromBounds)) {
- animateResizePinnedStack(mTmpToBounds, null /* sourceHintBounds */,
- -1 /* duration */, false /* fromFullscreen */);
- }
- pinnedStackController.setAspectRatio(
- pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
- ? aspectRatio : -1f);
- }
- }
- }
-
- /**
- * Sets the current picture-in-picture actions.
- */
- public void setPictureInPictureActions(List<RemoteAction> actions) {
- synchronized (mGlobalLock) {
- if (!mService.mSupportsPictureInPicture || mContainer == null) {
- return;
- }
-
- mContainer.getDisplayContent().getPinnedStackController().setActions(actions);
- }
- }
-
- /**
- * @return whether the multi-window mode change should be deferred as a part of a transition
- * from fullscreen to non-fullscreen bounds.
- */
- public boolean deferScheduleMultiWindowModeChanged() {
- synchronized (mGlobalLock) {
- return mContainer.deferScheduleMultiWindowModeChanged();
- }
- }
-
- /**
- * @return whether the stack can be resized from the bounds animation.
- */
- public boolean pinnedStackResizeDisallowed() {
- synchronized (mGlobalLock) {
- return mContainer.pinnedStackResizeDisallowed();
- }
- }
-
- /**
- * The following calls are made from WM to AM.
- */
-
- /** Calls directly into activity manager so window manager lock shouldn't held. */
- public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
- boolean forceUpdate) {
- if (mListener != null) {
- PinnedStackWindowListener listener = (PinnedStackWindowListener) mListener;
- listener.updatePictureInPictureModeForPinnedStackAnimation(targetStackBounds,
- forceUpdate);
- }
- }
-}
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowListener.java b/services/core/java/com/android/server/wm/PinnedStackWindowListener.java
deleted file mode 100644
index 33e8a60..0000000
--- a/services/core/java/com/android/server/wm/PinnedStackWindowListener.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2017 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 android.graphics.Rect;
-
-/**
- * Interface used by the creator of {@link PinnedStackWindowController} to listen to changes with
- * the stack container.
- */
-public interface PinnedStackWindowListener extends StackWindowListener {
-
- /**
- * Called when the stack container pinned stack animation will change the picture-in-picture
- * mode. This is a direct call into ActivityManager.
- */
- default void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
- boolean forceUpdate) {}
-}
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index f55c7c9..55554a7 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -955,7 +955,7 @@
mWindowManager.deferSurfaceLayout();
final ActivityDisplay display = r.getActivityStack().getDisplay();
- PinnedActivityStack stack = display.getPinnedStack();
+ ActivityStack stack = display.getPinnedStack();
// This will clear the pinned stack by moving an existing task to the full screen stack,
// ensuring only one task is present.
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
deleted file mode 100644
index ada807b..0000000
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2016 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 com.android.server.wm.WindowContainer.POSITION_BOTTOM;
-import static com.android.server.wm.WindowContainer.POSITION_TOP;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.lang.ref.WeakReference;
-
-/**
- * Controller for the stack container. This is created by activity manager to link activity stacks
- * to the stack container they use in window manager.
- *
- * Test class: {@link StackWindowControllerTests}
- */
-public class StackWindowController
- extends WindowContainerController<TaskStack, StackWindowListener> {
-
- private final int mStackId;
-
- private final H mHandler;
-
- final Rect mTmpBounds = new Rect();
-
- public StackWindowController(int stackId, StackWindowListener listener, int displayId,
- boolean onTop, Rect outBounds) {
- this(stackId, listener, displayId, onTop, outBounds, WindowManagerService.getInstance());
- }
-
- @VisibleForTesting
- public StackWindowController(int stackId, StackWindowListener listener,
- int displayId, boolean onTop, Rect outBounds, WindowManagerService service) {
- super(listener, service);
- mStackId = stackId;
- mHandler = new H(new WeakReference<>(this), service.mH.getLooper());
-
- final DisplayContent dc = mRoot.getDisplayContent(displayId);
- if (dc == null) {
- throw new IllegalArgumentException("Trying to add stackId=" + stackId
- + " to unknown displayId=" + displayId);
- }
-
- dc.createStack(stackId, onTop, this);
- getRawBounds(outBounds);
- }
-
- @Override
- public void removeContainer() {
- if (mContainer != null) {
- mContainer.removeIfPossible();
- super.removeContainer();
- }
- }
-
- void reparent(int displayId, Rect outStackBounds, boolean onTop) {
- if (mContainer == null) {
- throw new IllegalArgumentException("Trying to move unknown stackId=" + mStackId
- + " to displayId=" + displayId);
- }
-
- final DisplayContent targetDc = mRoot.getDisplayContent(displayId);
- if (targetDc == null) {
- throw new IllegalArgumentException("Trying to move stackId=" + mStackId
- + " to unknown displayId=" + displayId);
- }
-
- targetDc.moveStackToDisplay(mContainer, onTop);
- getRawBounds(outStackBounds);
- }
-
- void positionChildAt(Task child, int position) {
- if (DEBUG_STACK) {
- Slog.i(TAG_WM, "positionChildAt: positioning task=" + child + " at " + position);
- }
- if (child == null) {
- if (DEBUG_STACK) {
- Slog.i(TAG_WM, "positionChildAt: could not find task=" + this);
- }
- return;
- }
- if (mContainer == null) {
- if (DEBUG_STACK) {
- Slog.i(TAG_WM, "positionChildAt: could not find stack for task=" + mContainer);
- }
- return;
- }
- child.positionAt(position);
- mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
- }
-
- void positionChildAtTop(Task child, boolean includingParents) {
- if (child == null) {
- // TODO: Fix the call-points that cause this to happen.
- return;
- }
-
- mContainer.positionChildAt(POSITION_TOP, child, includingParents);
-
- final DisplayContent displayContent = mContainer.getDisplayContent();
- if (displayContent.mAppTransition.isTransitionSet()) {
- child.setSendingToBottom(false);
- }
- displayContent.layoutAndAssignWindowLayersIfNeeded();
- }
-
- void positionChildAtBottom(Task child, boolean includingParents) {
- if (child == null) {
- // TODO: Fix the call-points that cause this to happen.
- return;
- }
-
- mContainer.positionChildAt(POSITION_BOTTOM, child, includingParents);
-
- if (mContainer.getDisplayContent().mAppTransition.isTransitionSet()) {
- child.setSendingToBottom(true);
- }
- mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
- }
-
- /**
- * Re-sizes a stack and its containing tasks.
- *
- * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
- * @param taskBounds Bounds for tasks in the resized stack, keyed by task id.
- * @param taskTempInsetBounds Inset bounds for individual tasks, keyed by task id.
- */
- public void resize(Rect bounds, SparseArray<Rect> taskBounds,
- SparseArray<Rect> taskTempInsetBounds) {
- if (mContainer == null) {
- throw new IllegalArgumentException("resizeStack: stack " + this + " not found.");
- }
- // We might trigger a configuration change. Save the current task bounds for freezing.
- mContainer.prepareFreezingTaskBounds();
- if (mContainer.setBounds(bounds, taskBounds, taskTempInsetBounds)
- && mContainer.isVisible()) {
- mContainer.getDisplayContent().setLayoutNeeded();
- mService.mWindowPlacerLocked.performSurfacePlacement();
- }
- }
-
- public void onPipAnimationEndResize() {
- mContainer.onPipAnimationEndResize();
- }
-
- /**
- * @see TaskStack.getStackDockedModeBoundsLocked(ConfigurationContainer, Rect, Rect, Rect)
- */
- public void getStackDockedModeBounds(Configuration parentConfig, Rect dockedBounds,
- Rect currentTempTaskBounds,
- Rect outStackBounds, Rect outTempTaskBounds) {
- if (mContainer != null) {
- mContainer.getStackDockedModeBoundsLocked(parentConfig, dockedBounds,
- currentTempTaskBounds, outStackBounds, outTempTaskBounds);
- return;
- }
- outStackBounds.setEmpty();
- outTempTaskBounds.setEmpty();
- }
-
- public void prepareFreezingTaskBounds() {
- if (mContainer == null) {
- throw new IllegalArgumentException("prepareFreezingTaskBounds: stack " + this
- + " not found.");
- }
- mContainer.prepareFreezingTaskBounds();
- }
-
- public void getRawBounds(Rect outBounds) {
- if (mContainer.matchParentBounds()) {
- outBounds.setEmpty();
- } else {
- mContainer.getRawBounds(outBounds);
- }
- }
-
- public void getBounds(Rect outBounds) {
- if (mContainer != null) {
- mContainer.getBounds(outBounds);
- return;
- }
- outBounds.setEmpty();
- }
-
- void requestResize(Rect bounds) {
- mHandler.obtainMessage(H.REQUEST_RESIZE, bounds).sendToTarget();
- }
-
- @Override
- public String toString() {
- return "{StackWindowController stackId=" + mStackId + "}";
- }
-
- private static final class H extends Handler {
-
- static final int REQUEST_RESIZE = 0;
-
- private final WeakReference<StackWindowController> mController;
-
- H(WeakReference<StackWindowController> controller, Looper looper) {
- super(looper);
- mController = controller;
- }
-
- @Override
- public void handleMessage(Message msg) {
- final StackWindowController controller = mController.get();
- final StackWindowListener listener = (controller != null)
- ? controller.mListener : null;
- if (listener == null) {
- return;
- }
- switch (msg.what) {
- case REQUEST_RESIZE:
- listener.requestResize((Rect) msg.obj);
- break;
- }
- }
- }
-}
diff --git a/services/core/java/com/android/server/wm/StackWindowListener.java b/services/core/java/com/android/server/wm/StackWindowListener.java
deleted file mode 100644
index c763c17..0000000
--- a/services/core/java/com/android/server/wm/StackWindowListener.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2017 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 android.graphics.Rect;
-
-/**
- * Interface used by the creator of {@link StackWindowController} to listen to changes with
- * the stack container.
- */
-public interface StackWindowListener extends WindowContainerListener {
-
- /** Called when the stack container would like its controller to resize. */
- void requestResize(Rect bounds);
-}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index d334bd2..a7dd55b 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -209,26 +209,14 @@
super.removeImmediately();
}
- void reparent(StackWindowController stackController, int position, boolean moveParents) {
- if (DEBUG_STACK) {
- Slog.i(TAG_WM, "reparent: moving taskId=" + mTaskId
- + " to stack=" + stackController + " at " + position);
- }
- final TaskStack stack = stackController.mContainer;
- if (stack == null) {
- throw new IllegalArgumentException("reparent: could not find stack="
- + stackController);
- }
- reparent(stack, position, moveParents);
- getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
- }
-
-
void reparent(TaskStack stack, int position, boolean moveParents) {
if (stack == mStack) {
throw new IllegalArgumentException(
"task=" + this + " already child of stack=" + mStack);
}
+ if (stack == null) {
+ throw new IllegalArgumentException("reparent: could not find stack.");
+ }
if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
+ " from stack=" + mStack);
EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask");
@@ -254,6 +242,7 @@
onDisplayChanged(displayContent);
prevDisplayContent.setLayoutNeeded();
}
+ getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
}
/** @see ActivityTaskManagerService#positionTaskInStack(int, int, int). */
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 6acd864..f3050a9 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -709,7 +709,7 @@
final List<TaskRecord> tasksToCheck = new ArrayList<>();
for (int i = 0; i < display.getChildCount(); ++i) {
- ActivityStack<?> stack = display.getChildAt(i);
+ final ActivityStack stack = display.getChildAt(i);
if (!stack.inFreeformWindowingMode()) {
continue;
}
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index e944858..69dcaf4 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -455,17 +455,10 @@
}
final Rect bounds = updateOverrideConfigurationFromLaunchBounds();
- final StackWindowController stackController = getStack().getWindowContainerController();
+ final TaskStack stack = getStack().getTaskStack();
- if (DEBUG_STACK) {
- Slog.i(TAG_WM, "TaskRecord: taskId=" + taskId
- + " stack=" + stackController + " bounds=" + bounds);
- }
-
- final TaskStack stack = stackController.mContainer;
if (stack == null) {
- throw new IllegalArgumentException("TaskRecord: invalid stack="
- + stackController);
+ throw new IllegalArgumentException("TaskRecord: invalid stack=" + mStack);
}
EventLog.writeEvent(WM_TASK_CREATED, taskId, stack.mStackId);
mTask = new Task(taskId, stack, userId, mService.mWindowManager, mResizeMode,
@@ -742,7 +735,7 @@
// Must reparent first in window manager to avoid a situation where AM can delete the
// we are coming from in WM before we reparent because it became empty.
- mTask.reparent(toStack.getWindowContainerController(), position,
+ mTask.reparent(toStack.getTaskStack(), position,
moveStackMode == REPARENT_MOVE_STACK_TO_FRONT);
final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index ee74bdf..8ed7d04 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -21,6 +21,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
@@ -33,6 +34,10 @@
import static android.view.WindowManager.DOCKED_RIGHT;
import static android.view.WindowManager.DOCKED_TOP;
+import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
+import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
+import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
+import static com.android.server.wm.BoundsAnimationController.SchedulePipModeChangedState;
import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
import static com.android.server.wm.StackProto.ADJUSTED_BOUNDS;
import static com.android.server.wm.StackProto.ADJUSTED_FOR_IME;
@@ -47,10 +52,12 @@
import static com.android.server.wm.StackProto.MINIMIZE_AMOUNT;
import static com.android.server.wm.StackProto.TASKS;
import static com.android.server.wm.StackProto.WINDOW_CONTAINER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.CallSuper;
+import android.app.RemoteAction;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
@@ -71,9 +78,10 @@
import com.android.server.EventLogTags;
import java.io.PrintWriter;
+import java.util.List;
public class TaskStack extends WindowContainer<Task> implements
- BoundsAnimationTarget {
+ BoundsAnimationTarget, ConfigurationContainerListener {
/** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to
* restrict IME adjustment so that a min portion of top stack remains visible.*/
private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f;
@@ -93,6 +101,10 @@
private Rect mTmpRect2 = new Rect();
private Rect mTmpRect3 = new Rect();
+ /** For Pinned stack controlling. */
+ private Rect mTmpFromBounds = new Rect();
+ private Rect mTmpToBounds = new Rect();
+
/** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
private final Rect mAdjustedBounds = new Rect();
@@ -141,6 +153,9 @@
private Dimmer mDimmer = new Dimmer(this);
+ // TODO: remove after unification.
+ ActivityStack mActivityStack;
+
/**
* For {@link #prepareSurfaces}.
*/
@@ -150,10 +165,11 @@
private final AnimatingAppWindowTokenRegistry mAnimatingAppWindowTokenRegistry =
new AnimatingAppWindowTokenRegistry();
- TaskStack(WindowManagerService service, int stackId, StackWindowController controller) {
+ TaskStack(WindowManagerService service, int stackId, ActivityStack activityStack) {
super(service);
mStackId = stackId;
- setController(controller);
+ mActivityStack = activityStack;
+ activityStack.registerConfigurationChangeListener(this);
mDockedStackMinimizeThickness = service.mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_minimize_thickness);
EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId);
@@ -572,6 +588,49 @@
positionChildAt(position, task, moveParents /* includingParents */, showForAllUsers);
}
+ void positionChildAt(Task child, int position) {
+ if (DEBUG_STACK) {
+ Slog.i(TAG_WM, "positionChildAt: positioning task=" + child + " at " + position);
+ }
+ if (child == null) {
+ if (DEBUG_STACK) {
+ Slog.i(TAG_WM, "positionChildAt: could not find task=" + this);
+ }
+ return;
+ }
+ child.positionAt(position);
+ getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+ }
+
+ void positionChildAtTop(Task child, boolean includingParents) {
+ if (child == null) {
+ // TODO: Fix the call-points that cause this to happen.
+ return;
+ }
+
+ positionChildAt(POSITION_TOP, child, includingParents);
+
+ final DisplayContent displayContent = getDisplayContent();
+ if (displayContent.mAppTransition.isTransitionSet()) {
+ child.setSendingToBottom(false);
+ }
+ displayContent.layoutAndAssignWindowLayersIfNeeded();
+ }
+
+ void positionChildAtBottom(Task child, boolean includingParents) {
+ if (child == null) {
+ // TODO: Fix the call-points that cause this to happen.
+ return;
+ }
+
+ positionChildAt(POSITION_BOTTOM, child, includingParents);
+
+ if (getDisplayContent().mAppTransition.isTransitionSet()) {
+ child.setSendingToBottom(true);
+ }
+ getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+ }
+
@Override
void positionChildAt(int position, Task child, boolean includingParents) {
positionChildAt(position, child, includingParents, child.showForAllUsers());
@@ -596,6 +655,21 @@
EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, child.mTaskId, toTop, targetPosition);
}
+ void reparent(int displayId, Rect outStackBounds, boolean onTop) {
+ final DisplayContent targetDc = mWmService.mRoot.getDisplayContent(displayId);
+ if (targetDc == null) {
+ throw new IllegalArgumentException("Trying to move stackId=" + mStackId
+ + " to unknown displayId=" + displayId);
+ }
+
+ targetDc.moveStackToDisplay(this, onTop);
+ if (matchParentBounds()) {
+ outStackBounds.setEmpty();
+ } else {
+ getRawBounds(outStackBounds);
+ }
+ }
+
// TODO: We should really have users as a window container in the hierarchy so that we don't
// have to do complicated things like we are doing in this method.
private int findPositionForTask(Task task, int targetPosition, boolean showForAllUsers,
@@ -725,6 +799,23 @@
}
/**
+ * Re-sizes a stack and its containing tasks.
+ *
+ * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
+ * @param taskBounds Bounds for tasks in the resized stack, keyed by task id.
+ * @param taskTempInsetBounds Inset bounds for individual tasks, keyed by task id.
+ */
+ void resize(Rect bounds, SparseArray<Rect> taskBounds,
+ SparseArray<Rect> taskTempInsetBounds) {
+ // We might trigger a configuration change. Save the current task bounds for freezing.
+ prepareFreezingTaskBounds();
+ if (setBounds(bounds, taskBounds, taskTempInsetBounds) && isVisible()) {
+ getDisplayContent().setLayoutNeeded();
+ mWmService.mWindowPlacerLocked.performSurfacePlacement();
+ }
+ }
+
+ /**
* Calculate an amount by which to expand the stack bounds in each direction.
* Used to make room for shadows in the pinned windowing mode.
*/
@@ -929,12 +1020,7 @@
(dockedStack == null || dockedStack == this) ? null : dockedStack.getRawBounds();
getStackDockedModeBoundsLocked(mDisplayContent.getConfiguration(), dockedBounds,
null /* currentTempTaskBounds */, bounds, tempBounds);
- getController().requestResize(bounds);
- }
-
- @Override
- StackWindowController getController() {
- return (StackWindowController) super.getController();
+ mActivityStack.requestResize(bounds);
}
@Override
@@ -947,6 +1033,14 @@
}
@Override
+ void removeImmediately() {
+ if (mActivityStack != null) {
+ mActivityStack.unregisterConfigurationChangeListener(this);
+ }
+ super.removeImmediately();
+ }
+
+ @Override
void onParentSet() {
super.onParentSet();
@@ -1572,14 +1666,13 @@
// I don't believe you...
}
- final PinnedStackWindowController controller =
- (PinnedStackWindowController) getController();
- if (schedulePipModeChangedCallback && controller != null) {
+ if (schedulePipModeChangedCallback && mActivityStack != null) {
// We need to schedule the PiP mode change before the animation up. It is possible
// in this case for the animation down to not have been completed, so always
// force-schedule and update to the client to ensure that it is notified that it
// is no longer in picture-in-picture mode
- controller.updatePictureInPictureModeForPinnedStackAnimation(null, forceUpdate);
+ mActivityStack.updatePictureInPictureModeForPinnedStackAnimation(null,
+ forceUpdate);
}
}
return true;
@@ -1592,12 +1685,10 @@
// Update to the final bounds if requested. This is done here instead of in the bounds
// animator to allow us to coordinate this after we notify the PiP mode changed
- final PinnedStackWindowController controller =
- (PinnedStackWindowController) getController();
- if (schedulePipModeChangedCallback && controller != null) {
+ if (schedulePipModeChangedCallback) {
// We need to schedule the PiP mode change after the animation down, so use the
// final bounds
- controller.updatePictureInPictureModeForPinnedStackAnimation(
+ mActivityStack.updatePictureInPictureModeForPinnedStackAnimation(
mBoundsAnimationTarget, false /* forceUpdate */);
}
@@ -1624,6 +1715,135 @@
}
}
+ /**
+ * @return the current stack bounds transformed to the given {@param aspectRatio}. If
+ * the default bounds is {@code null}, then the {@param aspectRatio} is applied to the
+ * default bounds.
+ */
+ Rect getPictureInPictureBounds(float aspectRatio, Rect stackBounds) {
+ if (!mWmService.mSupportsPictureInPicture) {
+ return null;
+ }
+
+ final DisplayContent displayContent = getDisplayContent();
+ if (displayContent == null) {
+ return null;
+ }
+
+ if (!inPinnedWindowingMode()) {
+ return null;
+ }
+
+ final PinnedStackController pinnedStackController =
+ displayContent.getPinnedStackController();
+ if (stackBounds == null) {
+ // Calculate the aspect ratio bounds from the default bounds
+ stackBounds = pinnedStackController.getDefaultOrLastSavedBounds();
+ }
+
+ if (pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)) {
+ return pinnedStackController.transformBoundsToAspectRatio(stackBounds, aspectRatio,
+ true /* useCurrentMinEdgeSize */);
+ } else {
+ return stackBounds;
+ }
+ }
+
+ /**
+ * Animates the pinned stack.
+ */
+ void animateResizePinnedStack(Rect toBounds, Rect sourceHintBounds,
+ int animationDuration, boolean fromFullscreen) {
+ if (!inPinnedWindowingMode()) {
+ return;
+ }
+ // Get the from-bounds
+ final Rect fromBounds = new Rect();
+ getBounds(fromBounds);
+
+ // Get non-null fullscreen to-bounds for animating if the bounds are null
+ @SchedulePipModeChangedState int schedulePipModeChangedState =
+ NO_PIP_MODE_CHANGED_CALLBACKS;
+ final boolean toFullscreen = toBounds == null;
+ if (toFullscreen) {
+ if (fromFullscreen) {
+ throw new IllegalArgumentException("Should not defer scheduling PiP mode"
+ + " change on animation to fullscreen.");
+ }
+ schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_START;
+
+ mWmService.getStackBounds(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mTmpToBounds);
+ if (!mTmpToBounds.isEmpty()) {
+ // If there is a fullscreen bounds, use that
+ toBounds = new Rect(mTmpToBounds);
+ } else {
+ // Otherwise, use the display bounds
+ toBounds = new Rect();
+ getDisplayContent().getBounds(toBounds);
+ }
+ } else if (fromFullscreen) {
+ schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END;
+ }
+
+ setAnimationFinalBounds(sourceHintBounds, toBounds, toFullscreen);
+
+ final Rect finalToBounds = toBounds;
+ final @SchedulePipModeChangedState int finalSchedulePipModeChangedState =
+ schedulePipModeChangedState;
+ final DisplayContent displayContent = getDisplayContent();
+ displayContent.mBoundsAnimationController.getHandler().post(() -> {
+ displayContent.mBoundsAnimationController.animateBounds(this, fromBounds,
+ finalToBounds, animationDuration, finalSchedulePipModeChangedState,
+ fromFullscreen, toFullscreen);
+ });
+ }
+
+ /**
+ * Sets the current picture-in-picture aspect ratio.
+ */
+ void setPictureInPictureAspectRatio(float aspectRatio) {
+ if (!mWmService.mSupportsPictureInPicture) {
+ return;
+ }
+
+ if (!inPinnedWindowingMode()) {
+ return;
+ }
+
+ final PinnedStackController pinnedStackController =
+ getDisplayContent().getPinnedStackController();
+
+ if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) == 0) {
+ return;
+ }
+ getAnimationOrCurrentBounds(mTmpFromBounds);
+ mTmpToBounds.set(mTmpFromBounds);
+ getPictureInPictureBounds(aspectRatio, mTmpToBounds);
+ if (!mTmpToBounds.equals(mTmpFromBounds)) {
+ animateResizePinnedStack(mTmpToBounds, null /* sourceHintBounds */,
+ -1 /* duration */, false /* fromFullscreen */);
+ }
+ pinnedStackController.setAspectRatio(
+ pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
+ ? aspectRatio : -1f);
+ }
+
+ /**
+ * Sets the current picture-in-picture actions.
+ */
+ void setPictureInPictureActions(List<RemoteAction> actions) {
+ if (!mWmService.mSupportsPictureInPicture) {
+ return;
+ }
+
+ if (!inPinnedWindowingMode()) {
+ return;
+ }
+
+ getDisplayContent().getPinnedStackController().setActions(actions);
+ }
+
@Override
public boolean isAttached() {
synchronized (mWmService.mGlobalLock) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 8f9d2ba..1659baf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -68,7 +68,7 @@
@Before
public void setUp() throws Exception {
setupActivityTaskManagerService();
- mStack = new StackBuilder(mRootActivityContainer).build();
+ mStack = (TestActivityStack) new StackBuilder(mRootActivityContainer).build();
mTask = mStack.getChildAt(0);
mActivity = mTask.getTopActivity();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index b2a2869..61bd306 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -264,13 +264,13 @@
// Do not move display to back because there is still another stack.
stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.topTask());
- verify(stack2.getWindowContainerController()).positionChildAtBottom(any(),
+ verify(stack2.getTaskStack()).positionChildAtBottom(any(),
eq(false) /* includingParents */);
// Also move display to back because there is only one stack left.
display.removeChild(stack1);
stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.topTask());
- verify(stack2.getWindowContainerController()).positionChildAtBottom(any(),
+ verify(stack2.getTaskStack()).positionChildAtBottom(any(),
eq(true) /* includingParents */);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index ec88718..898d107 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -143,7 +143,7 @@
.setStack(mService.mRootActivityContainer.getDefaultDisplay().createStack(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */))
.build();
- assertThat((Object) task2.getStack()).isInstanceOf(PinnedActivityStack.class);
+ assertThat((Object) task2.getStack()).isInstanceOf(ActivityStack.class);
mStarter.updateBounds(task2, bounds);
verify(mService, times(1)).resizeStack(eq(task2.getStack().mStackId),
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 5589ca1..d462e69 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -39,9 +39,6 @@
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doCallRealMethod;
-
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
@@ -66,11 +63,11 @@
import android.view.DisplayInfo;
import com.android.internal.app.IVoiceInteractor;
-import com.android.server.appop.AppOpsService;
import com.android.server.AttributeCache;
import com.android.server.ServiceThread;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.PendingIntentController;
+import com.android.server.appop.AppOpsService;
import com.android.server.firewall.IntentFirewall;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -377,7 +374,7 @@
mStack.addTask(task, true, "creating test task");
task.setStack(mStack);
task.setTask();
- mStack.getWindowContainerController().mContainer.addChild(task.mTask, 0);
+ mStack.getTaskStack().addChild(task.mTask, 0);
}
task.touchActiveTime();
@@ -632,7 +629,7 @@
@SuppressWarnings("TypeParameterUnusedInFormals")
@Override
- <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
+ ActivityStack createStackUnchecked(int windowingMode, int activityType,
int stackId, boolean onTop) {
return new StackBuilder(mSupervisor.mRootActivityContainer).setDisplay(this)
.setWindowingMode(windowingMode).setActivityType(activityType)
@@ -681,10 +678,9 @@
* method is called. Note that its functionality depends on the implementations of the
* construction arguments.
*/
- protected static class TestActivityStack<T extends StackWindowController>
- extends ActivityStack<T> {
+ protected static class TestActivityStack
+ extends ActivityStack {
private int mOnActivityRemovedFromStackCount = 0;
- private T mContainerController;
static final int IS_TRANSLUCENT_UNSET = 0;
static final int IS_TRANSLUCENT_FALSE = 1;
@@ -724,20 +720,20 @@
}
@Override
- protected T createStackWindowController(int displayId, boolean onTop, Rect outBounds) {
- mContainerController = (T) WindowTestUtils.createMockStackWindowContainerController();
+ protected void createTaskStack(int displayId, boolean onTop, Rect outBounds) {
+ mTaskStack = WindowTestUtils.createMockTaskStack();
// Primary pinned stacks require a non-empty out bounds to be set or else all tasks
// will be moved to the full screen stack.
if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
outBounds.set(0, 0, 100, 100);
}
- return mContainerController;
+
}
@Override
- T getWindowContainerController() {
- return mContainerController;
+ TaskStack getTaskStack() {
+ return mTaskStack;
}
void setIsTranslucent(boolean isTranslucent) {
@@ -827,27 +823,23 @@
}
@SuppressWarnings("TypeParameterUnusedInFormals")
- <T extends ActivityStack> T build() {
+ ActivityStack build() {
final int stackId = mStackId >= 0 ? mStackId : mDisplay.getNextStackId();
if (mWindowingMode == WINDOWING_MODE_PINNED) {
- return (T) new PinnedActivityStack(mDisplay, stackId,
- mRootActivityContainer.mStackSupervisor, mOnTop) {
+ return new ActivityStack(mDisplay, stackId, mRootActivityContainer.mStackSupervisor,
+ mWindowingMode, ACTIVITY_TYPE_STANDARD, mOnTop) {
@Override
Rect getDefaultPictureInPictureBounds(float aspectRatio) {
return new Rect(50, 50, 100, 100);
}
@Override
- PinnedStackWindowController createStackWindowController(int displayId,
- boolean onTop, Rect outBounds) {
- PinnedStackWindowController controller =
- mock(PinnedStackWindowController.class);
- controller.mContainer = mock(TaskStack.class);
- return controller;
+ void createTaskStack(int displayId, boolean onTop, Rect outBounds) {
+ mTaskStack = mock(TaskStack.class);
}
};
} else {
- return (T) new TestActivityStack(mDisplay, stackId,
+ return new TestActivityStack(mDisplay, stackId,
mRootActivityContainer.mStackSupervisor, mWindowingMode,
mActivityType, mOnTop, mCreateActivity);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 51bebbb..0c6e632 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -181,7 +181,7 @@
assertTrue(dc1.mOpeningApps.size() > 0);
// Move stack to another display.
- stack1.getController().reparent(dc2.getDisplayId(), new Rect(), true);
+ stack1.reparent(dc2.getDisplayId(), new Rect(), true);
// Verify if token are cleared from both pending transition list in former display.
assertFalse(dc1.mOpeningApps.contains(token1));
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index bb3ab35..68d8bc0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -94,8 +94,8 @@
private WindowState createDropTargetWindow(String name, int ownerId) {
final WindowTestUtils.TestAppWindowToken token = WindowTestUtils.createTestAppWindowToken(
mDisplayContent);
- final TaskStack stack = createStackControllerOnStackOnDisplay(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
+ final TaskStack stack = createTaskStackOnDisplay(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent);
final Task task = createTaskInStack(stack, ownerId);
task.addChild(token, 0);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 58302d6..a3f535a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -323,8 +323,8 @@
public void testFindTaskToMoveToFrontWhenRecentsOnTop() {
// Create stack/task on default display.
final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
- final TestActivityStack targetStack =
- new StackBuilder(mRootActivityContainer).setOnTop(false).build();
+ final TestActivityStack targetStack = (TestActivityStack) new StackBuilder(
+ mRootActivityContainer).setOnTop(false).build();
final TaskRecord targetTask = targetStack.getChildAt(0);
// Create Recents on top of the display.
diff --git a/services/tests/wmtests/src/com/android/server/wm/StackWindowControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/StackWindowControllerTests.java
deleted file mode 100644
index 5690b58..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/StackWindowControllerTests.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2017 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 org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-
-/**
- * Test class for {@link StackWindowController}.
- *
- * Build/Install/Run:
- * atest FrameworksServicesTests:StackWindowControllerTests
- */
-@SmallTest
-@Presubmit
-public class StackWindowControllerTests extends WindowTestsBase {
- @Test
- public void testRemoveContainer() {
- final StackWindowController stackController =
- createStackControllerOnDisplay(mDisplayContent);
- final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController);
-
- final TaskStack stack = stackController.mContainer;
- assertNotNull(stack);
- assertNotNull(task);
- stackController.removeContainer();
- // Assert that the container was removed.
- assertNull(stackController.mContainer);
- assertNull(stack.getDisplayContent());
- assertNull(task.getDisplayContent());
- assertNull(task.mStack);
- }
-
- @Test
- public void testRemoveContainer_deferRemoval() {
- final StackWindowController stackController =
- createStackControllerOnDisplay(mDisplayContent);
- final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController);
-
- final TaskStack stack = stackController.mContainer;
- // Stack removal is deferred if one of its child is animating.
- task.setLocalIsAnimating(true);
-
- stackController.removeContainer();
- // For the case of deferred removal the stack controller will no longer be connected to the
- // container, but the task controller will still be connected to the its container until
- // the stack window container is removed.
- assertNull(stackController.mContainer);
- assertNull(stack.getController());
- assertNotNull(task);
-
- stack.removeImmediately();
- // After removing, the task will be isolated.
- assertNull(task.getParent());
- assertEquals(task.getChildCount(), 0);
- assertNull(task.getController());
- }
-
- @Test
- public void testReparent() {
- // Create first stack on primary display.
- final StackWindowController stack1Controller =
- createStackControllerOnDisplay(mDisplayContent);
- final TaskStack stack1 = stack1Controller.mContainer;
- final WindowTestUtils.TestTask task1 = WindowTestUtils.createTestTask(stack1Controller);
- task1.mOnDisplayChangedCalled = false;
-
- // Create second display and put second stack on it.
- final DisplayContent dc = createNewDisplay();
- final StackWindowController stack2Controller =
- createStackControllerOnDisplay(dc);
- final TaskStack stack2 = stack2Controller.mContainer;
-
- // Reparent
- stack1Controller.reparent(dc.getDisplayId(), new Rect(), true /* onTop */);
- assertEquals(dc, stack1.getDisplayContent());
- final int stack1PositionInParent = stack1.getParent().mChildren.indexOf(stack1);
- final int stack2PositionInParent = stack1.getParent().mChildren.indexOf(stack2);
- assertEquals(stack1PositionInParent, stack2PositionInParent + 1);
- assertTrue(task1.mOnDisplayChangedCalled);
- }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
index f01e9f0..74ccccc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -47,8 +47,8 @@
@Before
public void setUp() throws Exception {
- mPinnedStack = createStackControllerOnStackOnDisplay(
- WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
+ mPinnedStack = createTaskStackOnDisplay(
+ WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
// Stack should contain visible app window to be considered visible.
final Task pinnedTask = createTaskInStack(mPinnedStack, 0 /* userId */);
assertFalse(mPinnedStack.isVisible());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
index 7ac3318..2554237 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -20,8 +20,12 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -106,4 +110,62 @@
assertNull(stack.getDisplayContent());
assertNull(task.mStack);
}
+
+ @Test
+ public void testRemoveContainer() {
+ final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+ final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack);
+
+ assertNotNull(stack);
+ assertNotNull(task);
+ stack.removeIfPossible();
+ // Assert that the container was removed.
+ assertNull(stack.getParent());
+ assertEquals(0, stack.getChildCount());
+ assertNull(stack.getDisplayContent());
+ assertNull(task.getDisplayContent());
+ assertNull(task.mStack);
+ }
+
+ @Test
+ public void testRemoveContainer_deferRemoval() {
+ final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+ final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack);
+
+ // Stack removal is deferred if one of its child is animating.
+ task.setLocalIsAnimating(true);
+
+ stack.removeIfPossible();
+ // For the case of deferred removal the task controller will still be connected to the its
+ // container until the stack window container is removed.
+ assertNotNull(stack.getParent());
+ assertNotEquals(0, stack.getChildCount());
+ assertNotNull(task);
+
+ stack.removeImmediately();
+ // After removing, the task will be isolated.
+ assertNull(task.getParent());
+ assertEquals(0, task.getChildCount());
+ assertNull(task.getController());
+ }
+
+ @Test
+ public void testReparent() {
+ // Create first stack on primary display.
+ final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
+ final WindowTestUtils.TestTask task1 = WindowTestUtils.createTestTask(stack1);
+ task1.mOnDisplayChangedCalled = false;
+
+ // Create second display and put second stack on it.
+ final DisplayContent dc = createNewDisplay();
+ final TaskStack stack2 = createTaskStackOnDisplay(dc);
+
+ // Reparent
+ stack1.reparent(dc.getDisplayId(), new Rect(), true /* onTop */);
+ assertEquals(dc, stack1.getDisplayContent());
+ final int stack1PositionInParent = stack1.getParent().mChildren.indexOf(stack1);
+ final int stack2PositionInParent = stack1.getParent().mChildren.indexOf(stack2);
+ assertEquals(stack1PositionInParent, stack2PositionInParent + 1);
+ assertTrue(task1.mOnDisplayChangedCalled);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 3e32ed3..ae211d3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -40,8 +40,7 @@
@Test
public void testRemoveContainer() {
- final StackWindowController stackController1 =
- createStackControllerOnDisplay(mDisplayContent);
+ final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1);
final WindowTestUtils.TestAppWindowToken appToken =
WindowTestUtils.createAppWindowTokenInTask(mDisplayContent, task);
@@ -49,14 +48,13 @@
task.removeIfPossible();
// Assert that the container was removed.
assertNull(task.getParent());
- assertEquals(task.getChildCount(), 0);
+ assertEquals(0, task.getChildCount());
assertNull(appToken.getParent());
}
@Test
public void testRemoveContainer_deferRemoval() {
- final StackWindowController stackController1 =
- createStackControllerOnDisplay(mDisplayContent);
+ final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1);
final WindowTestUtils.TestAppWindowToken appToken =
WindowTestUtils.createAppWindowTokenInTask(mDisplayContent, task);
@@ -67,22 +65,20 @@
// For the case of deferred removal the task will still be connected to the its app token
// until the task window container is removed.
assertNotNull(task.getParent());
- assertNotEquals(task.getChildCount(), 0);
+ assertNotEquals(0, task.getChildCount());
assertNotNull(appToken.getParent());
task.removeImmediately();
assertNull(task.getParent());
- assertEquals(task.getChildCount(), 0);
+ assertEquals(0, task.getChildCount());
assertNull(appToken.getParent());
}
@Test
public void testReparent() {
- final StackWindowController stackController1 =
- createStackControllerOnDisplay(mDisplayContent);
+ final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1);
- final StackWindowController stackController2 =
- createStackControllerOnDisplay(mDisplayContent);
+ final TaskStack stackController2 = createTaskStackOnDisplay(mDisplayContent);
final WindowTestUtils.TestTask task2 = WindowTestUtils.createTestTask(stackController2);
boolean gotException = false;
@@ -93,20 +89,17 @@
}
assertTrue("Should not be able to reparent to the same parent", gotException);
- final StackWindowController stackController3 =
- createStackControllerOnDisplay(mDisplayContent);
- stackController3.setContainer(null);
gotException = false;
try {
- task.reparent(stackController3, 0, false/* moveParents */);
+ task.reparent(null, 0, false/* moveParents */);
} catch (IllegalArgumentException e) {
gotException = true;
}
- assertTrue("Should not be able to reparent to a stack that doesn't have a container",
+ assertTrue("Should not be able to reparent to a stack that doesn't exist",
gotException);
task.reparent(stackController2, 0, false/* moveParents */);
- assertEquals(stackController2.mContainer, task.getParent());
+ assertEquals(stackController2, task.getParent());
assertEquals(0, task.positionInParent());
assertEquals(1, task2.positionInParent());
}
@@ -114,20 +107,17 @@
@Test
public void testReparent_BetweenDisplays() {
// Create first stack on primary display.
- final StackWindowController stack1Controller =
- createStackControllerOnDisplay(mDisplayContent);
- final TaskStack stack1 = stack1Controller.mContainer;
- final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack1Controller);
+ final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
+ final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack1);
task.mOnDisplayChangedCalled = false;
assertEquals(mDisplayContent, stack1.getDisplayContent());
// Create second display and put second stack on it.
final DisplayContent dc = createNewDisplay();
- final StackWindowController stack2Controller = createStackControllerOnDisplay(dc);
- final TaskStack stack2 = stack2Controller.mContainer;
- final WindowTestUtils.TestTask task2 = WindowTestUtils.createTestTask(stack2Controller);
+ final TaskStack stack2 = createTaskStackOnDisplay(dc);
+ final WindowTestUtils.TestTask task2 = WindowTestUtils.createTestTask(stack2);
// Reparent and check state
- task.reparent(stack2Controller, 0, false /* moveParents */);
+ task.reparent(stack2, 0, false /* moveParents */);
assertEquals(stack2, task.getParent());
assertEquals(0, task.positionInParent());
assertEquals(1, task2.positionInParent());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index d9ef10d..0a4a8a4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -16,12 +16,15 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
import static android.view.DisplayCutout.fromBoundingRect;
import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
import android.app.ActivityManager.TaskDescription;
import android.content.res.Configuration;
@@ -58,7 +61,7 @@
boolean mDockedResizingForTest = false;
WindowStateWithTask(WindowManagerService wm, IWindow iWindow, WindowToken windowToken,
WindowManager.LayoutParams attrs, Task t) {
- super(wm, null, iWindow, windowToken, null, 0, 0, attrs, 0, 0,
+ super(wm, mock(Session.class), iWindow, windowToken, null, 0, 0, attrs, 0, 0,
false /* ownerCanAddInternalSystemWindow */);
mTask = t;
}
@@ -113,9 +116,9 @@
@Before
public void setUp() throws Exception {
- mWindowToken = WindowTestUtils.createTestAppWindowToken(
- mWm.getDefaultDisplayContentLocked());
- mStubStack = new TaskStack(mWm, 0, null);
+ mWindowToken = createAppWindowToken(mWm.getDefaultDisplayContentLocked(),
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ mStubStack = WindowTestUtils.createMockTaskStack();
}
// Do not use this function directly in the tests below. Instead, use more explicit function
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 20fc5ae..44e998b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -103,12 +103,10 @@
}
/**
- * Creates a mock instance of {@link StackWindowController}.
+ * Creates a mock instance of {@link TestTaskStack}.
*/
- public static StackWindowController createMockStackWindowContainerController() {
- StackWindowController controller = mock(StackWindowController.class);
- controller.mContainer = mock(TestTaskStack.class);
- return controller;
+ public static TaskStack createMockTaskStack() {
+ return mock(TestTaskStack.class);
}
/** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
@@ -201,6 +199,11 @@
}
@Override
+ void onParentSet() {
+ // Do nothing.
+ }
+
+ @Override
boolean isOnTop() {
return mOnTop;
}
@@ -283,10 +286,9 @@
}
}
- public static TestTask createTestTask(StackWindowController stackWindowController) {
- return new TestTask(sNextTaskId++, stackWindowController.mContainer, 0,
- stackWindowController.mService, RESIZE_MODE_UNRESIZEABLE, false,
- mock(TaskRecord.class));
+ public static TestTask createTestTask(TaskStack stack) {
+ return new TestTask(sNextTaskId++, stack, 0, stack.mWmService, RESIZE_MODE_UNRESIZEABLE,
+ false, mock(TaskRecord.class));
}
public static class TestIApplicationToken implements IApplicationToken {
@@ -334,5 +336,10 @@
mHasSurface = hadSurface;
}
+
+ @Override
+ void onParentSet() {
+ // Do nothing;
+ }
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index cdc0a47..89c1551 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -41,7 +41,6 @@
import android.content.Context;
import android.content.res.Configuration;
-import android.graphics.Rect;
import android.hardware.display.DisplayManagerGlobal;
import android.testing.DexmakerShareClassLoaderRule;
import android.util.Log;
@@ -240,8 +239,7 @@
WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
windowingMode, int activityType) {
- final TaskStack stack = createStackControllerOnStackOnDisplay(windowingMode, activityType,
- dc).mContainer;
+ final TaskStack stack = createTaskStackOnDisplay(windowingMode, activityType, dc);
final Task task = createTaskInStack(stack, 0 /* userId */);
final WindowTestUtils.TestAppWindowToken appWindowToken =
WindowTestUtils.createTestAppWindowToken(dc);
@@ -350,28 +348,20 @@
/** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */
TaskStack createTaskStackOnDisplay(DisplayContent dc) {
synchronized (mWm.mGlobalLock) {
- return createStackControllerOnDisplay(dc).mContainer;
+ return createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
}
}
- StackWindowController createStackControllerOnDisplay(DisplayContent dc) {
- synchronized (mWm.mGlobalLock) {
- return createStackControllerOnStackOnDisplay(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
- }
- }
-
- StackWindowController createStackControllerOnStackOnDisplay(
- int windowingMode, int activityType, DisplayContent dc) {
+ TaskStack createTaskStackOnDisplay(int windowingMode, int activityType, DisplayContent dc) {
synchronized (mWm.mGlobalLock) {
final Configuration overrideConfig = new Configuration();
overrideConfig.windowConfiguration.setWindowingMode(windowingMode);
overrideConfig.windowConfiguration.setActivityType(activityType);
final int stackId = ++sNextStackId;
- final StackWindowController controller = new StackWindowController(stackId, null,
- dc.getDisplayId(), true /* onTop */, new Rect(), mWm);
- controller.onRequestedOverrideConfigurationChanged(overrideConfig);
- return controller;
+ final TaskStack stack = new TaskStack(mWm, stackId, mock(ActivityStack.class));
+ dc.setStackOnDisplay(stackId, true, stack);
+ stack.onRequestedOverrideConfigurationChanged(overrideConfig);
+ return stack;
}
}