Make LaunchingTaskPositioner stateless.
The initial design cached calculations based on the available bounds. This required the positioner to be involved in stack lifecycle events and tied to a particular stack. This changelist removes these dependencies and makes the ActivityStackSupervisor the owner. Bug: 64144308 Test: bit FrameworksServicesTests:com.android.server.am.LaunchBoundsTests Change-Id: I4e2df4398b0818cec71d3d90fe409012191406c0
This commit is contained in:
@@ -358,8 +358,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
|
||||
/** Run all ActivityStacks through this */
|
||||
protected final ActivityStackSupervisor mStackSupervisor;
|
||||
|
||||
private final LaunchingTaskPositioner mTaskPositioner;
|
||||
|
||||
private boolean mTopActivityOccludesKeyguard;
|
||||
private ActivityRecord mTopDismissingKeyguardActivity;
|
||||
|
||||
@@ -462,8 +460,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
|
||||
mWindowManager = mService.mWindowManager;
|
||||
mStackId = stackId;
|
||||
mCurrentUser = mService.mUserController.getCurrentUserId();
|
||||
mTaskPositioner = windowingMode == WINDOWING_MODE_FREEFORM
|
||||
? new LaunchingTaskPositioner() : null;
|
||||
mTmpRect2.setEmpty();
|
||||
setWindowingMode(windowingMode);
|
||||
setActivityType(activityType);
|
||||
@@ -504,11 +500,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
|
||||
mDisplayId = activityDisplay.mDisplayId;
|
||||
mBounds = bounds != null ? new Rect(bounds) : null;
|
||||
mFullscreen = mBounds == null;
|
||||
if (mTaskPositioner != null) {
|
||||
activityDisplay.mDisplay.getSize(mTmpSize);
|
||||
mTaskPositioner.setDisplaySize(mTmpSize);
|
||||
mTaskPositioner.configure(mBounds);
|
||||
}
|
||||
|
||||
onParentChanged();
|
||||
|
||||
activityDisplay.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM);
|
||||
@@ -536,9 +528,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
|
||||
display.removeChild(this);
|
||||
}
|
||||
mDisplayId = INVALID_DISPLAY;
|
||||
if (mTaskPositioner != null) {
|
||||
mTaskPositioner.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes the stack completely. Also calls WindowManager to do the same on its side. */
|
||||
@@ -642,9 +631,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
|
||||
|
||||
void setBounds(Rect bounds) {
|
||||
mBounds = mFullscreen ? null : new Rect(bounds);
|
||||
if (mTaskPositioner != null) {
|
||||
mTaskPositioner.configure(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
ActivityRecord topRunningActivityLocked() {
|
||||
@@ -5137,10 +5123,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
|
||||
}
|
||||
|
||||
boolean layoutTaskInStack(TaskRecord task, ActivityInfo.WindowLayout windowLayout) {
|
||||
if (mTaskPositioner == null) {
|
||||
if (!task.inFreeformWindowingMode()) {
|
||||
return false;
|
||||
}
|
||||
mTaskPositioner.updateDefaultBounds(task, mTaskHistory, windowLayout);
|
||||
mStackSupervisor.getLaunchingTaskPositioner()
|
||||
.updateDefaultBounds(task, mTaskHistory, windowLayout);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -293,6 +293,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
|
||||
WindowManagerService mWindowManager;
|
||||
DisplayManager mDisplayManager;
|
||||
|
||||
LaunchingTaskPositioner mTaskPositioner = new LaunchingTaskPositioner();
|
||||
|
||||
/** Counter for next free stack ID to use for dynamic activity stacks. */
|
||||
private int mNextFreeStackId = 0;
|
||||
|
||||
@@ -2138,6 +2140,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
|
||||
|| mService.mSupportsFreeformWindowManagement;
|
||||
}
|
||||
|
||||
LaunchingTaskPositioner getLaunchingTaskPositioner() {
|
||||
return mTaskPositioner;
|
||||
}
|
||||
|
||||
protected <T extends ActivityStack> T getStack(int stackId) {
|
||||
for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
|
||||
final T stack = mActivityDisplays.valueAt(i).getStack(stackId);
|
||||
|
||||
@@ -64,23 +64,12 @@ class LaunchingTaskPositioner {
|
||||
private static final int SHIFT_POLICY_HORIZONTAL_RIGHT = 2;
|
||||
private static final int SHIFT_POLICY_HORIZONTAL_LEFT = 3;
|
||||
|
||||
private boolean mDefaultStartBoundsConfigurationSet = false;
|
||||
private final Rect mAvailableRect = new Rect();
|
||||
private final Rect mTmpProposal = new Rect();
|
||||
private final Rect mTmpOriginal = new Rect();
|
||||
|
||||
private int mDefaultFreeformStartX;
|
||||
private int mDefaultFreeformStartY;
|
||||
private int mDefaultFreeformWidth;
|
||||
private int mDefaultFreeformHeight;
|
||||
private int mDefaultFreeformStepHorizontal;
|
||||
private int mDefaultFreeformStepVertical;
|
||||
private final Point mDisplaySize = new Point();
|
||||
|
||||
void setDisplaySize(Point size) {
|
||||
mDisplaySize.set(size.x, size.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to set task's bound in a way that it won't collide with any other task. By colliding
|
||||
* we mean that two tasks have left-top corner very close to each other, so one might get
|
||||
@@ -93,52 +82,47 @@ class LaunchingTaskPositioner {
|
||||
*/
|
||||
void updateDefaultBounds(TaskRecord task, ArrayList<TaskRecord> tasks,
|
||||
@Nullable ActivityInfo.WindowLayout windowLayout) {
|
||||
if (!mDefaultStartBoundsConfigurationSet) {
|
||||
return;
|
||||
}
|
||||
updateAvailableRect(task, mAvailableRect);
|
||||
|
||||
if (windowLayout == null) {
|
||||
positionCenter(task, tasks, mDefaultFreeformWidth, mDefaultFreeformHeight);
|
||||
positionCenter(task, tasks, mAvailableRect, getFreeformWidth(mAvailableRect),
|
||||
getFreeformHeight(mAvailableRect));
|
||||
return;
|
||||
}
|
||||
int width = getFinalWidth(windowLayout);
|
||||
int height = getFinalHeight(windowLayout);
|
||||
int width = getFinalWidth(windowLayout, mAvailableRect);
|
||||
int height = getFinalHeight(windowLayout, mAvailableRect);
|
||||
int verticalGravity = windowLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
|
||||
int horizontalGravity = windowLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
|
||||
if (verticalGravity == Gravity.TOP) {
|
||||
if (horizontalGravity == Gravity.RIGHT) {
|
||||
positionTopRight(task, tasks, width, height);
|
||||
positionTopRight(task, tasks, mAvailableRect, width, height);
|
||||
} else {
|
||||
positionTopLeft(task, tasks, width, height);
|
||||
positionTopLeft(task, tasks, mAvailableRect, width, height);
|
||||
}
|
||||
} else if (verticalGravity == Gravity.BOTTOM) {
|
||||
if (horizontalGravity == Gravity.RIGHT) {
|
||||
positionBottomRight(task, tasks, width, height);
|
||||
positionBottomRight(task, tasks, mAvailableRect, width, height);
|
||||
} else {
|
||||
positionBottomLeft(task, tasks, width, height);
|
||||
positionBottomLeft(task, tasks, mAvailableRect, width, height);
|
||||
}
|
||||
} else {
|
||||
// Some fancy gravity setting that we don't support yet. We just put the activity in the
|
||||
// center.
|
||||
Slog.w(TAG, "Received unsupported gravity: " + windowLayout.gravity
|
||||
+ ", positioning in the center instead.");
|
||||
positionCenter(task, tasks, width, height);
|
||||
positionCenter(task, tasks, mAvailableRect, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void configure(Rect availableSpace) {
|
||||
if (availableSpace == null) {
|
||||
mAvailableRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
|
||||
} else {
|
||||
mAvailableRect.set(availableSpace);
|
||||
}
|
||||
private void updateAvailableRect(TaskRecord task, Rect availableRect) {
|
||||
final Rect stackBounds = task.getStack().mBounds;
|
||||
|
||||
mDefaultFreeformStartX = getFreeformStartLeft(mAvailableRect);
|
||||
mDefaultFreeformStartY = getFreeformStartTop(mAvailableRect);
|
||||
mDefaultFreeformWidth = getFreeformWidth(mAvailableRect);
|
||||
mDefaultFreeformHeight = getFreeformHeight(mAvailableRect);
|
||||
mDefaultFreeformStepHorizontal = getHorizontalStep(mAvailableRect);
|
||||
mDefaultFreeformStepVertical = getVerticalStep(mAvailableRect);
|
||||
mDefaultStartBoundsConfigurationSet = true;
|
||||
if (stackBounds != null) {
|
||||
availableRect.set(stackBounds);
|
||||
} else {
|
||||
task.getStack().getDisplay().mDisplay.getSize(mDisplaySize);
|
||||
availableRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -173,72 +157,79 @@ class LaunchingTaskPositioner {
|
||||
|
||||
|
||||
|
||||
private int getFinalWidth(ActivityInfo.WindowLayout windowLayout) {
|
||||
int width = mDefaultFreeformWidth;
|
||||
private int getFinalWidth(ActivityInfo.WindowLayout windowLayout, Rect availableRect) {
|
||||
int width = getFreeformWidth(availableRect);
|
||||
if (windowLayout.width > 0) {
|
||||
width = windowLayout.width;
|
||||
}
|
||||
if (windowLayout.widthFraction > 0) {
|
||||
width = (int) (mAvailableRect.width() * windowLayout.widthFraction);
|
||||
width = (int) (availableRect.width() * windowLayout.widthFraction);
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
private int getFinalHeight(ActivityInfo.WindowLayout windowLayout) {
|
||||
int height = mDefaultFreeformHeight;
|
||||
private int getFinalHeight(ActivityInfo.WindowLayout windowLayout, Rect availableRect) {
|
||||
int height = getFreeformHeight(availableRect);
|
||||
if (windowLayout.height > 0) {
|
||||
height = windowLayout.height;
|
||||
}
|
||||
if (windowLayout.heightFraction > 0) {
|
||||
height = (int) (mAvailableRect.height() * windowLayout.heightFraction);
|
||||
height = (int) (availableRect.height() * windowLayout.heightFraction);
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
private void positionBottomLeft(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
|
||||
int height) {
|
||||
mTmpProposal.set(mAvailableRect.left, mAvailableRect.bottom - height,
|
||||
mAvailableRect.left + width, mAvailableRect.bottom);
|
||||
position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT);
|
||||
private void positionBottomLeft(TaskRecord task, ArrayList<TaskRecord> tasks,
|
||||
Rect availableRect, int width, int height) {
|
||||
mTmpProposal.set(availableRect.left, availableRect.bottom - height,
|
||||
availableRect.left + width, availableRect.bottom);
|
||||
position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART,
|
||||
SHIFT_POLICY_HORIZONTAL_RIGHT);
|
||||
}
|
||||
|
||||
private void positionBottomRight(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
|
||||
int height) {
|
||||
mTmpProposal.set(mAvailableRect.right - width, mAvailableRect.bottom - height,
|
||||
mAvailableRect.right, mAvailableRect.bottom);
|
||||
position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT);
|
||||
private void positionBottomRight(TaskRecord task, ArrayList<TaskRecord> tasks,
|
||||
Rect availableRect, int width, int height) {
|
||||
mTmpProposal.set(availableRect.right - width, availableRect.bottom - height,
|
||||
availableRect.right, availableRect.bottom);
|
||||
position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART,
|
||||
SHIFT_POLICY_HORIZONTAL_LEFT);
|
||||
}
|
||||
|
||||
private void positionTopLeft(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
|
||||
int height) {
|
||||
mTmpProposal.set(mAvailableRect.left, mAvailableRect.top,
|
||||
mAvailableRect.left + width, mAvailableRect.top + height);
|
||||
position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT);
|
||||
private void positionTopLeft(TaskRecord task, ArrayList<TaskRecord> tasks,
|
||||
Rect availableRect, int width, int height) {
|
||||
mTmpProposal.set(availableRect.left, availableRect.top,
|
||||
availableRect.left + width, availableRect.top + height);
|
||||
position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART,
|
||||
SHIFT_POLICY_HORIZONTAL_RIGHT);
|
||||
}
|
||||
|
||||
private void positionTopRight(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
|
||||
int height) {
|
||||
mTmpProposal.set(mAvailableRect.right - width, mAvailableRect.top,
|
||||
mAvailableRect.right, mAvailableRect.top + height);
|
||||
position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT);
|
||||
private void positionTopRight(TaskRecord task, ArrayList<TaskRecord> tasks,
|
||||
Rect availableRect, int width, int height) {
|
||||
mTmpProposal.set(availableRect.right - width, availableRect.top,
|
||||
availableRect.right, availableRect.top + height);
|
||||
position(task, tasks, availableRect, mTmpProposal, !ALLOW_RESTART,
|
||||
SHIFT_POLICY_HORIZONTAL_LEFT);
|
||||
}
|
||||
|
||||
private void positionCenter(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
|
||||
int height) {
|
||||
mTmpProposal.set(mDefaultFreeformStartX, mDefaultFreeformStartY,
|
||||
mDefaultFreeformStartX + width, mDefaultFreeformStartY + height);
|
||||
position(task, tasks, mTmpProposal, ALLOW_RESTART, SHIFT_POLICY_DIAGONAL_DOWN);
|
||||
private void positionCenter(TaskRecord task, ArrayList<TaskRecord> tasks,
|
||||
Rect availableRect, int width, int height) {
|
||||
final int defaultFreeformLeft = getFreeformStartLeft(availableRect);
|
||||
final int defaultFreeformTop = getFreeformStartTop(availableRect);
|
||||
mTmpProposal.set(defaultFreeformLeft, defaultFreeformTop,
|
||||
defaultFreeformLeft + width, defaultFreeformTop + height);
|
||||
position(task, tasks, availableRect, mTmpProposal, ALLOW_RESTART,
|
||||
SHIFT_POLICY_DIAGONAL_DOWN);
|
||||
}
|
||||
|
||||
private void position(TaskRecord task, ArrayList<TaskRecord> tasks, Rect proposal,
|
||||
boolean allowRestart, int shiftPolicy) {
|
||||
private void position(TaskRecord task, ArrayList<TaskRecord> tasks, Rect availableRect,
|
||||
Rect proposal, boolean allowRestart, int shiftPolicy) {
|
||||
mTmpOriginal.set(proposal);
|
||||
boolean restarted = false;
|
||||
while (boundsConflict(proposal, tasks)) {
|
||||
// Unfortunately there is already a task at that spot, so we need to look for some
|
||||
// other place.
|
||||
shiftStartingPoint(proposal, shiftPolicy);
|
||||
if (shiftedTooFar(proposal, shiftPolicy)) {
|
||||
shiftStartingPoint(proposal, availableRect, shiftPolicy);
|
||||
if (shiftedTooFar(proposal, availableRect, shiftPolicy)) {
|
||||
// We don't want the task to go outside of the stack, because it won't look
|
||||
// nice. Depending on the starting point we either restart, or immediately give up.
|
||||
if (!allowRestart) {
|
||||
@@ -247,13 +238,13 @@ class LaunchingTaskPositioner {
|
||||
}
|
||||
// We must have started not from the top. Let's restart from there because there
|
||||
// might be some space there.
|
||||
proposal.set(mAvailableRect.left, mAvailableRect.top,
|
||||
mAvailableRect.left + proposal.width(),
|
||||
mAvailableRect.top + proposal.height());
|
||||
proposal.set(availableRect.left, availableRect.top,
|
||||
availableRect.left + proposal.width(),
|
||||
availableRect.top + proposal.height());
|
||||
restarted = true;
|
||||
}
|
||||
if (restarted && (proposal.left > mDefaultFreeformStartX
|
||||
|| proposal.top > mDefaultFreeformStartY)) {
|
||||
if (restarted && (proposal.left > getFreeformStartLeft(availableRect)
|
||||
|| proposal.top > getFreeformStartTop(availableRect))) {
|
||||
// If we restarted and crossed the initial position, let's not struggle anymore.
|
||||
// The user already must have ton of tasks visible, we can just smack the new
|
||||
// one in the center.
|
||||
@@ -264,27 +255,30 @@ class LaunchingTaskPositioner {
|
||||
task.updateOverrideConfiguration(proposal);
|
||||
}
|
||||
|
||||
private boolean shiftedTooFar(Rect start, int shiftPolicy) {
|
||||
private boolean shiftedTooFar(Rect start, Rect availableRect, int shiftPolicy) {
|
||||
switch (shiftPolicy) {
|
||||
case SHIFT_POLICY_HORIZONTAL_LEFT:
|
||||
return start.left < mAvailableRect.left;
|
||||
return start.left < availableRect.left;
|
||||
case SHIFT_POLICY_HORIZONTAL_RIGHT:
|
||||
return start.right > mAvailableRect.right;
|
||||
return start.right > availableRect.right;
|
||||
default: // SHIFT_POLICY_DIAGONAL_DOWN
|
||||
return start.right > mAvailableRect.right || start.bottom > mAvailableRect.bottom;
|
||||
return start.right > availableRect.right || start.bottom > availableRect.bottom;
|
||||
}
|
||||
}
|
||||
|
||||
private void shiftStartingPoint(Rect posposal, int shiftPolicy) {
|
||||
private void shiftStartingPoint(Rect posposal, Rect availableRect, int shiftPolicy) {
|
||||
final int defaultFreeformStepHorizontal = getHorizontalStep(availableRect);
|
||||
final int defaultFreeformStepVertical = getVerticalStep(availableRect);
|
||||
|
||||
switch (shiftPolicy) {
|
||||
case SHIFT_POLICY_HORIZONTAL_LEFT:
|
||||
posposal.offset(-mDefaultFreeformStepHorizontal, 0);
|
||||
posposal.offset(-defaultFreeformStepHorizontal, 0);
|
||||
break;
|
||||
case SHIFT_POLICY_HORIZONTAL_RIGHT:
|
||||
posposal.offset(mDefaultFreeformStepHorizontal, 0);
|
||||
posposal.offset(defaultFreeformStepHorizontal, 0);
|
||||
break;
|
||||
default: // SHIFT_POLICY_DIAGONAL_DOWN:
|
||||
posposal.offset(mDefaultFreeformStepHorizontal, mDefaultFreeformStepVertical);
|
||||
posposal.offset(defaultFreeformStepHorizontal, defaultFreeformStepVertical);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -323,8 +317,4 @@ class LaunchingTaskPositioner {
|
||||
return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE
|
||||
&& Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
mDefaultStartBoundsConfigurationSet = false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user