summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Bryce Lee <brycelee@google.com> 2018-01-11 15:26:45 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2018-01-11 15:26:45 +0000
commit842db5e6c20cb9a5932d6d0c4c29cbca67590492 (patch)
treee7cc0b1e178eb13ca44a1166b123558145f1f46f
parentbd76bebadeae955db670b2d118cf5c0e3eac9046 (diff)
parentec55eb06eb4868ca593c4b16438b3c6121701c1a (diff)
Merge "Allow modifiers to specify windowing mode and preferred display."
-rw-r--r--services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java (renamed from services/core/java/com/android/server/am/LaunchingActivityPositioner.java)20
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java2
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java10
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java32
-rw-r--r--services/core/java/com/android/server/am/LaunchParamsController.java256
-rw-r--r--services/core/java/com/android/server/am/LaunchingBoundsController.java167
-rw-r--r--services/core/java/com/android/server/am/TaskLaunchParamsModifier.java (renamed from services/core/java/com/android/server/am/LaunchingTaskPositioner.java)31
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java (renamed from services/tests/servicestests/src/com/android/server/am/LaunchingActivityPositionerTests.java)44
-rw-r--r--services/tests/servicestests/src/com/android/server/am/LaunchParamsControllerTests.java255
-rw-r--r--services/tests/servicestests/src/com/android/server/am/LaunchingBoundsControllerTests.java194
-rw-r--r--services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java (renamed from services/tests/servicestests/src/com/android/server/am/LaunchingTaskPositionerTests.java)55
12 files changed, 618 insertions, 452 deletions
diff --git a/services/core/java/com/android/server/am/LaunchingActivityPositioner.java b/services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java
index 793884d08c08..f44ee7a234ca 100644
--- a/services/core/java/com/android/server/am/LaunchingActivityPositioner.java
+++ b/services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java
@@ -19,23 +19,25 @@ package com.android.server.am;
import android.app.ActivityOptions;
import android.content.pm.ActivityInfo;
import android.graphics.Rect;
-import com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner;
+
+import com.android.server.am.LaunchParamsController.LaunchParams;
+import com.android.server.am.LaunchParamsController.LaunchParamsModifier;
/**
- * An implementation of {@link LaunchingBoundsPositioner}, which applies the launch bounds specified
+ * An implementation of {@link LaunchParamsModifier}, which applies the launch bounds specified
* inside {@link ActivityOptions#getLaunchBounds()}.
*/
-public class LaunchingActivityPositioner implements LaunchingBoundsPositioner {
+public class ActivityLaunchParamsModifier implements LaunchParamsModifier {
private final ActivityStackSupervisor mSupervisor;
- LaunchingActivityPositioner(ActivityStackSupervisor activityStackSupervisor) {
+ ActivityLaunchParamsModifier(ActivityStackSupervisor activityStackSupervisor) {
mSupervisor = activityStackSupervisor;
}
@Override
- public int onCalculateBounds(TaskRecord task, ActivityInfo.WindowLayout layout,
- ActivityRecord activity, ActivityRecord source,
- ActivityOptions options, Rect current, Rect result) {
+ public int onCalculate(TaskRecord task, ActivityInfo.WindowLayout layout,
+ ActivityRecord activity, ActivityRecord source, ActivityOptions options,
+ LaunchParams currentParams, LaunchParams outParams) {
// We only care about figuring out bounds for activities.
if (activity == null) {
return RESULT_SKIP;
@@ -43,7 +45,7 @@ public class LaunchingActivityPositioner implements LaunchingBoundsPositioner {
// Activity must be resizeable in the specified task.
if (!(mSupervisor.canUseActivityOptionsLaunchBounds(options)
- && (activity.isResizeable() || (task != null && task.isResizeable())))) {
+ && (activity.isResizeable() || (task != null && task.isResizeable())))) {
return RESULT_SKIP;
}
@@ -54,7 +56,7 @@ public class LaunchingActivityPositioner implements LaunchingBoundsPositioner {
return RESULT_SKIP;
}
- result.set(bounds);
+ outParams.mBounds.set(bounds);
// When this is the most explicit position specification so we should not allow further
// modification of the position.
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 831b31ed89c2..a343965ab848 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -5052,7 +5052,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
addTask(task, toTop, "createTaskRecord");
final boolean isLockscreenShown = mService.mStackSupervisor.getKeyguardController()
.isKeyguardShowing(mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY);
- if (!mStackSupervisor.getLaunchingBoundsController()
+ if (!mStackSupervisor.getLaunchParamsController()
.layoutTask(task, info.windowLayout, activity, source, options)
&& !matchParentBounds() && task.isResizeable() && !isLockscreenShown) {
task.updateOverrideConfiguration(getOverrideBounds());
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 21085fa2f717..b567303b3ae5 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -300,7 +300,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
WindowManagerService mWindowManager;
DisplayManager mDisplayManager;
- private LaunchingBoundsController mLaunchingBoundsController;
+ private LaunchParamsController mLaunchParamsController;
/**
* Maps the task identifier that activities are currently being started in to the userId of the
@@ -593,8 +593,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mHandler.getLooper());
mKeyguardController = new KeyguardController(mService, this);
- mLaunchingBoundsController = new LaunchingBoundsController();
- mLaunchingBoundsController.registerDefaultPositioners(this);
+ mLaunchParamsController = new LaunchParamsController(mService);
+ mLaunchParamsController.registerDefaultModifiers(this);
}
@@ -2220,8 +2220,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
|| mService.mSupportsFreeformWindowManagement;
}
- LaunchingBoundsController getLaunchingBoundsController() {
- return mLaunchingBoundsController;
+ LaunchParamsController getLaunchParamsController() {
+ return mLaunchParamsController;
}
protected <T extends ActivityStack> T getStack(int stackId) {
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index c98e33727c9e..3a13155d88e1 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -96,7 +96,6 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.voice.IVoiceInteractionSession;
@@ -109,6 +108,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.app.IVoiceInteractor;
import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
+import com.android.server.am.LaunchParamsController.LaunchParams;
import com.android.server.pm.InstantAppResolver;
import java.io.PrintWriter;
@@ -144,7 +144,7 @@ class ActivityStarter {
private boolean mLaunchTaskBehind;
private int mLaunchFlags;
- private Rect mLaunchBounds = new Rect();
+ private LaunchParams mLaunchParams = new LaunchParams();
private ActivityRecord mNotTop;
private boolean mDoResume;
@@ -419,7 +419,7 @@ class ActivityStarter {
mLaunchFlags = starter.mLaunchFlags;
mLaunchMode = starter.mLaunchMode;
- mLaunchBounds.set(starter.mLaunchBounds);
+ mLaunchParams.set(starter.mLaunchParams);
mNotTop = starter.mNotTop;
mDoResume = starter.mDoResume;
@@ -1154,6 +1154,18 @@ class ActivityStarter {
preferredLaunchDisplayId = mOptions.getLaunchDisplayId();
}
+ // windowing mode and preferred launch display values from {@link LaunchParams} take
+ // priority over those specified in {@link ActivityOptions}.
+ if (!mLaunchParams.isEmpty()) {
+ if (mLaunchParams.hasPreferredDisplay()) {
+ preferredLaunchDisplayId = mLaunchParams.mPreferredDisplayId;
+ }
+
+ if (mLaunchParams.hasWindowingMode()) {
+ preferredWindowingMode = mLaunchParams.mWindowingMode;
+ }
+ }
+
if (reusedActivity != null) {
// When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
// still needs to be a lock task mode violation since the task gets cleared out and
@@ -1378,7 +1390,7 @@ class ActivityStarter {
mLaunchFlags = 0;
mLaunchMode = INVALID_LAUNCH_MODE;
- mLaunchBounds.setEmpty();
+ mLaunchParams.reset();
mNotTop = null;
mDoResume = false;
@@ -1425,10 +1437,10 @@ class ActivityStarter {
mPreferredDisplayId = getPreferedDisplayId(mSourceRecord, mStartActivity, options);
- mLaunchBounds.setEmpty();
+ mLaunchParams.reset();
- mSupervisor.getLaunchingBoundsController().calculateBounds(inTask, null /*layout*/, r,
- sourceRecord, options, mLaunchBounds);
+ mSupervisor.getLaunchParamsController().calculate(inTask, null /*layout*/, r, sourceRecord,
+ options, mLaunchParams);
mLaunchMode = r.launchMode;
@@ -1938,7 +1950,7 @@ class ActivityStarter {
mVoiceInteractor, !mLaunchTaskBehind /* toTop */, mStartActivity, mSourceRecord,
mOptions);
addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
- updateBounds(mStartActivity.getTask(), mLaunchBounds);
+ updateBounds(mStartActivity.getTask(), mLaunchParams.mBounds);
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
+ " in new task " + mStartActivity.getTask());
@@ -2102,7 +2114,7 @@ class ActivityStarter {
return START_TASK_TO_FRONT;
}
- if (!mLaunchBounds.isEmpty()) {
+ if (!mLaunchParams.mBounds.isEmpty()) {
// TODO: Shouldn't we already know what stack to use by the time we get here?
ActivityStack stack = mSupervisor.getLaunchStack(null, null, mInTask, ON_TOP);
if (stack != mInTask.getStack()) {
@@ -2111,7 +2123,7 @@ class ActivityStarter {
mTargetStack = mInTask.getStack();
}
- updateBounds(mInTask, mLaunchBounds);
+ updateBounds(mInTask, mLaunchParams.mBounds);
}
mTargetStack.moveTaskToFrontLocked(
diff --git a/services/core/java/com/android/server/am/LaunchParamsController.java b/services/core/java/com/android/server/am/LaunchParamsController.java
new file mode 100644
index 000000000000..7ab7f987d301
--- /dev/null
+++ b/services/core/java/com/android/server/am/LaunchParamsController.java
@@ -0,0 +1,256 @@
+/*
+ * 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.am;
+
+import android.annotation.IntDef;
+import android.app.ActivityOptions;
+import android.content.pm.ActivityInfo.WindowLayout;
+import android.graphics.Rect;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
+
+/**
+ * {@link LaunchParamsController} calculates the {@link LaunchParams} by coordinating between
+ * registered {@link LaunchParamsModifier}s.
+ */
+class LaunchParamsController {
+ private final ActivityManagerService mService;
+ private final List<LaunchParamsModifier> mModifiers = new ArrayList<>();
+
+ // Temporary {@link LaunchParams} for internal calculations. This is kept separate from
+ // {@code mTmpCurrent} and {@code mTmpResult} to prevent clobbering values.
+ private final LaunchParams mTmpParams = new LaunchParams();
+
+ private final LaunchParams mTmpCurrent = new LaunchParams();
+ private final LaunchParams mTmpResult = new LaunchParams();
+
+ LaunchParamsController(ActivityManagerService service) {
+ mService = service;
+ }
+
+ /**
+ * Creates a {@link LaunchParamsController} with default registered
+ * {@link LaunchParamsModifier}s.
+ */
+ void registerDefaultModifiers(ActivityStackSupervisor supervisor) {
+ // {@link TaskLaunchParamsModifier} handles window layout preferences.
+ registerModifier(new TaskLaunchParamsModifier());
+
+ // {@link ActivityLaunchParamsModifier} is the most specific modifier and thus should be
+ // registered last (applied first) out of the defaults.
+ registerModifier(new ActivityLaunchParamsModifier(supervisor));
+ }
+
+ /**
+ * Returns the {@link LaunchParams} calculated by the registered modifiers
+ * @param task The {@link TaskRecord} currently being positioned.
+ * @param layout The specified {@link WindowLayout}.
+ * @param activity The {@link ActivityRecord} currently being positioned.
+ * @param source The {@link ActivityRecord} from which activity was started from.
+ * @param options The {@link ActivityOptions} specified for the activity.
+ * @param result The resulting params.
+ */
+ void calculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
+ ActivityRecord source, ActivityOptions options, LaunchParams result) {
+ result.reset();
+
+ // We start at the last registered {@link LaunchParamsModifier} as this represents
+ // The modifier closest to the product level. Moving back through the list moves closer to
+ // the platform logic.
+ for (int i = mModifiers.size() - 1; i >= 0; --i) {
+ mTmpCurrent.set(result);
+ mTmpResult.reset();
+ final LaunchParamsModifier modifier = mModifiers.get(i);
+
+ switch(modifier.onCalculate(task, layout, activity, source, options, mTmpCurrent,
+ mTmpResult)) {
+ case RESULT_SKIP:
+ // Do not apply any results when we are told to skip
+ continue;
+ case RESULT_DONE:
+ // Set result and return immediately.
+ result.set(mTmpResult);
+ return;
+ case RESULT_CONTINUE:
+ // Set result and continue
+ result.set(mTmpResult);
+ break;
+ }
+ }
+ }
+
+ /**
+ * A convenience method for laying out a task.
+ * @return {@code true} if bounds were set on the task. {@code false} otherwise.
+ */
+ boolean layoutTask(TaskRecord task, WindowLayout layout) {
+ return layoutTask(task, layout, null /*activity*/, null /*source*/, null /*options*/);
+ }
+
+ boolean layoutTask(TaskRecord task, WindowLayout layout, ActivityRecord activity,
+ ActivityRecord source, ActivityOptions options) {
+ calculate(task, layout, activity, source, options, mTmpParams);
+
+ // No changes, return.
+ if (mTmpParams.isEmpty()) {
+ return false;
+ }
+
+ mService.mWindowManager.deferSurfaceLayout();
+
+ try {
+ if (mTmpParams.hasPreferredDisplay()
+ && mTmpParams.mPreferredDisplayId != task.getStack().getDisplay().mDisplayId) {
+ mService.moveStackToDisplay(task.getStackId(), mTmpParams.mPreferredDisplayId);
+ }
+
+ if (mTmpParams.hasWindowingMode()
+ && mTmpParams.mWindowingMode != task.getStack().getWindowingMode()) {
+ task.getStack().setWindowingMode(mTmpParams.mWindowingMode);
+ }
+
+ if (!mTmpParams.mBounds.isEmpty()) {
+ task.updateOverrideConfiguration(mTmpParams.mBounds);
+ return true;
+ } else {
+ return false;
+ }
+ } finally {
+ mService.mWindowManager.continueSurfaceLayout();
+ }
+ }
+
+ /**
+ * Adds a modifier to participate in future bounds calculation. Note that the last registered
+ * {@link LaunchParamsModifier} will be the first to calculate the bounds.
+ */
+ void registerModifier(LaunchParamsModifier modifier) {
+ if (mModifiers.contains(modifier)) {
+ return;
+ }
+
+ mModifiers.add(modifier);
+ }
+
+ /**
+ * A container for holding launch related fields.
+ */
+ static class LaunchParams {
+ /** The bounds within the parent container. */
+ final Rect mBounds = new Rect();
+
+ /** The id of the display the {@link TaskRecord} would prefer to be on. */
+ int mPreferredDisplayId;
+
+ /** The windowing mode to be in. */
+ int mWindowingMode;
+
+ /** Sets values back to default. {@link #isEmpty} will return {@code true} once called. */
+ void reset() {
+ mBounds.setEmpty();
+ mPreferredDisplayId = INVALID_DISPLAY;
+ mWindowingMode = WINDOWING_MODE_UNDEFINED;
+ }
+
+ /** Copies the values set on the passed in {@link LaunchParams}. */
+ void set(LaunchParams params) {
+ mBounds.set(params.mBounds);
+ mPreferredDisplayId = params.mPreferredDisplayId;
+ mWindowingMode = params.mWindowingMode;
+ }
+
+ /** Returns {@code true} if no values have been explicitly set. */
+ boolean isEmpty() {
+ return mBounds.isEmpty() && mPreferredDisplayId == INVALID_DISPLAY
+ && mWindowingMode == WINDOWING_MODE_UNDEFINED;
+ }
+
+ boolean hasWindowingMode() {
+ return mWindowingMode != WINDOWING_MODE_UNDEFINED;
+ }
+
+ boolean hasPreferredDisplay() {
+ return mPreferredDisplayId != INVALID_DISPLAY;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ LaunchParams that = (LaunchParams) o;
+
+ if (mPreferredDisplayId != that.mPreferredDisplayId) return false;
+ if (mWindowingMode != that.mWindowingMode) return false;
+ return mBounds != null ? mBounds.equals(that.mBounds) : that.mBounds == null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mBounds != null ? mBounds.hashCode() : 0;
+ result = 31 * result + mPreferredDisplayId;
+ result = 31 * result + mWindowingMode;
+ return result;
+ }
+ }
+
+ /**
+ * An interface implemented by those wanting to participate in bounds calculation.
+ */
+ interface LaunchParamsModifier {
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({RESULT_SKIP, RESULT_DONE, RESULT_CONTINUE})
+ @interface Result {}
+
+ // Returned when the modifier does not want to influence the bounds calculation
+ int RESULT_SKIP = 0;
+ // Returned when the modifier has changed the bounds and would like its results to be the
+ // final bounds applied.
+ int RESULT_DONE = 1;
+ // Returned when the modifier has changed the bounds but is okay with other modifiers
+ // influencing the bounds.
+ int RESULT_CONTINUE = 2;
+
+ /**
+ * Called when asked to calculate {@link LaunchParams}.
+ * @param task The {@link TaskRecord} currently being positioned.
+ * @param layout The specified {@link WindowLayout}.
+ * @param activity The {@link ActivityRecord} currently being positioned.
+ * @param source The {@link ActivityRecord} activity was started from.
+ * @param options The {@link ActivityOptions} specified for the activity.
+ * @param currentParams The current {@link LaunchParams}. This can differ from the initial
+ * params as it represents the modified params up to this point.
+ * @param outParams The resulting {@link LaunchParams} after all calculations.
+ * @return A {@link Result} representing the result of the
+ * {@link LaunchParams} calculation.
+ */
+ @Result
+ int onCalculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
+ ActivityRecord source, ActivityOptions options, LaunchParams currentParams,
+ LaunchParams outParams);
+ }
+}
diff --git a/services/core/java/com/android/server/am/LaunchingBoundsController.java b/services/core/java/com/android/server/am/LaunchingBoundsController.java
deleted file mode 100644
index 5aa7f58f0968..000000000000
--- a/services/core/java/com/android/server/am/LaunchingBoundsController.java
+++ /dev/null
@@ -1,167 +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.am;
-
-import android.annotation.IntDef;
-import android.app.ActivityOptions;
-import android.content.pm.ActivityInfo.WindowLayout;
-import android.graphics.Rect;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_CONTINUE;
-import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_DONE;
-import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_SKIP;
-
-/**
- * {@link LaunchingBoundsController} calculates the launch bounds by coordinating between registered
- * {@link LaunchingBoundsPositioner}.
- */
-class LaunchingBoundsController {
- private final List<LaunchingBoundsPositioner> mPositioners = new ArrayList<>();
-
- // Temporary {@link Rect} for calculations. This is kept separate from {@code mTmpCurrent} and
- // {@code mTmpResult} to prevent clobbering values.
- private final Rect mTmpRect = new Rect();
-
- private final Rect mTmpCurrent = new Rect();
- private final Rect mTmpResult = new Rect();
-
- /**
- * Creates a {@link LaunchingBoundsController} with default registered
- * {@link LaunchingBoundsPositioner}s.
- */
- void registerDefaultPositioners(ActivityStackSupervisor supervisor) {
- // {@link LaunchingTaskPositioner} handles window layout preferences.
- registerPositioner(new LaunchingTaskPositioner());
-
- // {@link LaunchingActivityPositioner} is the most specific positioner and thus should be
- // registered last (applied first) out of the defaults.
- registerPositioner(new LaunchingActivityPositioner(supervisor));
- }
-
- /**
- * Returns the position calculated by the registered positioners
- * @param task The {@link TaskRecord} currently being positioned.
- * @param layout The specified {@link WindowLayout}.
- * @param activity The {@link ActivityRecord} currently being positioned.
- * @param source The {@link ActivityRecord} from which activity was started from.
- * @param options The {@link ActivityOptions} specified for the activity.
- * @param result The resulting bounds. If no bounds are set, {@link Rect#isEmpty()} will be
- * {@code true}.
- */
- void calculateBounds(TaskRecord task, WindowLayout layout, ActivityRecord activity,
- ActivityRecord source, ActivityOptions options, Rect result) {
- result.setEmpty();
-
- // We start at the last registered {@link LaunchingBoundsPositioner} as this represents
- // The positioner closest to the product level. Moving back through the list moves closer to
- // the platform logic.
- for (int i = mPositioners.size() - 1; i >= 0; --i) {
- mTmpResult.setEmpty();
- mTmpCurrent.set(result);
- final LaunchingBoundsPositioner positioner = mPositioners.get(i);
-
- switch(positioner.onCalculateBounds(task, layout, activity, source, options,
- mTmpCurrent, mTmpResult)) {
- case RESULT_SKIP:
- // Do not apply any results when we are told to skip
- continue;
- case RESULT_DONE:
- // Set result and return immediately.
- result.set(mTmpResult);
- return;
- case RESULT_CONTINUE:
- // Set result and continue
- result.set(mTmpResult);
- break;
- }
- }
- }
-
- /**
- * A convenience method for laying out a task.
- * @return {@code true} if bounds were set on the task. {@code false} otherwise.
- */
- boolean layoutTask(TaskRecord task, WindowLayout layout) {
- return layoutTask(task, layout, null /*activity*/, null /*source*/, null /*options*/);
- }
-
- boolean layoutTask(TaskRecord task, WindowLayout layout, ActivityRecord activity,
- ActivityRecord source, ActivityOptions options) {
- calculateBounds(task, layout, activity, source, options, mTmpRect);
-
- if (mTmpRect.isEmpty()) {
- return false;
- }
-
- task.updateOverrideConfiguration(mTmpRect);
-
- return true;
- }
-
- /**
- * Adds a positioner to participate in future bounds calculation. Note that the last registered
- * {@link LaunchingBoundsPositioner} will be the first to calculate the bounds.
- */
- void registerPositioner(LaunchingBoundsPositioner positioner) {
- if (mPositioners.contains(positioner)) {
- return;
- }
-
- mPositioners.add(positioner);
- }
-
- /**
- * An interface implemented by those wanting to participate in bounds calculation.
- */
- interface LaunchingBoundsPositioner {
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({RESULT_SKIP, RESULT_DONE, RESULT_CONTINUE})
- @interface Result {}
-
- // Returned when the positioner does not want to influence the bounds calculation
- int RESULT_SKIP = 0;
- // Returned when the positioner has changed the bounds and would like its results to be the
- // final bounds applied.
- int RESULT_DONE = 1;
- // Returned when the positioner has changed the bounds but is okay with other positioners
- // influencing the bounds.
- int RESULT_CONTINUE = 2;
-
- /**
- * Called when asked to calculate bounds.
- * @param task The {@link TaskRecord} currently being positioned.
- * @param layout The specified {@link WindowLayout}.
- * @param activity The {@link ActivityRecord} currently being positioned.
- * @param source The {@link ActivityRecord} activity was started from.
- * @param options The {@link ActivityOptions} specified for the activity.
- * @param current The current bounds. This can differ from the initial bounds as it
- * represents the modified bounds up to this point.
- * @param result The {@link Rect} which the positioner should return its modified bounds.
- * Any merging of the current bounds should be already applied to this
- * value as well before returning.
- * @return A {@link Result} representing the result of the bounds calculation.
- */
- @Result
- int onCalculateBounds(TaskRecord task, WindowLayout layout, ActivityRecord activity,
- ActivityRecord source, ActivityOptions options, Rect current, Rect result);
- }
-}
diff --git a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java b/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
index d89568e27506..92f1cc34be92 100644
--- a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
+++ b/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
@@ -21,26 +21,27 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NA
import android.app.ActivityOptions;
import android.content.pm.ActivityInfo;
-import android.graphics.Point;
import android.graphics.Rect;
import android.util.Slog;
import android.view.Gravity;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.am.LaunchParamsController.LaunchParams;
+import com.android.server.am.LaunchParamsController.LaunchParamsModifier;
import java.util.ArrayList;
/**
* Determines where a launching task should be positioned and sized on the display.
*
- * The positioner is fairly simple. For the new task it tries default position based on the gravity
+ * The modifier is fairly simple. For the new task it tries default position based on the gravity
* and compares corners of the task with corners of existing tasks. If some two pairs of corners are
* sufficiently close enough, it shifts the bounds of the new task and tries again. When it exhausts
* all possible shifts, it gives up and puts the task in the original position.
*
* Note that the only gravities of concern are the corners and the center.
*/
-class LaunchingTaskPositioner implements LaunchingBoundsController.LaunchingBoundsPositioner {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "LaunchingTaskPositioner" : TAG_AM;
+class TaskLaunchParamsModifier implements LaunchParamsModifier {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskLaunchParamsModifier" : TAG_AM;
// Determines how close window frames/corners have to be to call them colliding.
private static final int BOUNDS_CONFLICT_MIN_DISTANCE = 4;
@@ -70,17 +71,15 @@ class LaunchingTaskPositioner implements LaunchingBoundsController.LaunchingBoun
private final Rect mTmpProposal = new Rect();
private final Rect mTmpOriginal = new Rect();
- private final Point mDisplaySize = new Point();
-
/**
* 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
* obfuscated by the other one.
*/
@Override
- public int onCalculateBounds(TaskRecord task, ActivityInfo.WindowLayout layout,
- ActivityRecord activity, ActivityRecord source,
- ActivityOptions options, Rect current, Rect result) {
+ public int onCalculate(TaskRecord task, ActivityInfo.WindowLayout layout,
+ ActivityRecord activity, ActivityRecord source, ActivityOptions options,
+ LaunchParams currentParams, LaunchParams outParams) {
// We can only apply positioning if we're in a freeform stack.
if (task == null || task.getStack() == null || !task.inFreeformWindowingMode()) {
return RESULT_SKIP;
@@ -90,9 +89,11 @@ class LaunchingTaskPositioner implements LaunchingBoundsController.LaunchingBoun
mAvailableRect.set(task.getParent().getBounds());
+ final Rect resultBounds = outParams.mBounds;
+
if (layout == null) {
positionCenter(tasks, mAvailableRect, getFreeformWidth(mAvailableRect),
- getFreeformHeight(mAvailableRect), result);
+ getFreeformHeight(mAvailableRect), resultBounds);
return RESULT_CONTINUE;
}
@@ -102,22 +103,22 @@ class LaunchingTaskPositioner implements LaunchingBoundsController.LaunchingBoun
int horizontalGravity = layout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
if (verticalGravity == Gravity.TOP) {
if (horizontalGravity == Gravity.RIGHT) {
- positionTopRight(tasks, mAvailableRect, width, height, result);
+ positionTopRight(tasks, mAvailableRect, width, height, resultBounds);
} else {
- positionTopLeft(tasks, mAvailableRect, width, height, result);
+ positionTopLeft(tasks, mAvailableRect, width, height, resultBounds);
}
} else if (verticalGravity == Gravity.BOTTOM) {
if (horizontalGravity == Gravity.RIGHT) {
- positionBottomRight(tasks, mAvailableRect, width, height, result);
+ positionBottomRight(tasks, mAvailableRect, width, height, resultBounds);
} else {
- positionBottomLeft(tasks, mAvailableRect, width, height, result);
+ positionBottomLeft(tasks, mAvailableRect, width, height, resultBounds);
}
} 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: " + layout.gravity
+ ", positioning in the center instead.");
- positionCenter(tasks, mAvailableRect, width, height, result);
+ positionCenter(tasks, mAvailableRect, width, height, resultBounds);
}
return RESULT_CONTINUE;
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 4aef95d23ce9..b131e86d83ed 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -714,7 +714,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
} else if (toStackWindowingMode == WINDOWING_MODE_FREEFORM) {
Rect bounds = getLaunchBounds();
if (bounds == null) {
- mService.mStackSupervisor.getLaunchingBoundsController().layoutTask(this, null);
+ mService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
bounds = configBounds;
}
kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume);
@@ -1838,7 +1838,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
if (mLastNonFullscreenBounds != null) {
updateOverrideConfiguration(mLastNonFullscreenBounds);
} else {
- mService.mStackSupervisor.getLaunchingBoundsController().layoutTask(this, null);
+ mService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
}
} else {
updateOverrideConfiguration(inStack.getOverrideBounds());
diff --git a/services/tests/servicestests/src/com/android/server/am/LaunchingActivityPositionerTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java
index 62fa764550d8..f741c70e4821 100644
--- a/services/tests/servicestests/src/com/android/server/am/LaunchingActivityPositionerTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java
@@ -17,55 +17,55 @@
package com.android.server.am;
import android.app.ActivityOptions;
-import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
+import com.android.server.am.LaunchParamsController.LaunchParams;
import org.junit.runner.RunWith;
import org.junit.Before;
import org.junit.Test;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_DONE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.doAnswer;
-import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_SKIP;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
/**
* Tests for exercising resizing bounds due to activity options.
*
* Build/Install/Run:
- * bit FrameworksServicesTests:com.android.server.am.LaunchingActivityPositionerTests
+ * atest FrameworksServicesTests:ActivityLaunchParamsModifierTests
*/
@MediumTest
@Presubmit
@RunWith(AndroidJUnit4.class)
-public class LaunchingActivityPositionerTests extends ActivityTestsBase {
- private LaunchingActivityPositioner mPositioner;
+public class ActivityLaunchParamsModifierTests extends ActivityTestsBase {
+ private ActivityLaunchParamsModifier mModifier;
private ActivityManagerService mService;
private ActivityStack mStack;
private TaskRecord mTask;
private ActivityRecord mActivity;
- private Rect mCurrent;
- private Rect mResult;
+ private LaunchParams mCurrent;
+ private LaunchParams mResult;
@Before
@Override
public void setUp() throws Exception {
super.setUp();
mService = createActivityManagerService();
- mPositioner = new LaunchingActivityPositioner(mService.mStackSupervisor);
- mCurrent = new Rect();
- mResult = new Rect();
+ mModifier = new ActivityLaunchParamsModifier(mService.mStackSupervisor);
+ mCurrent = new LaunchParams();
+ mResult = new LaunchParams();
mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
@@ -78,35 +78,35 @@ public class LaunchingActivityPositionerTests extends ActivityTestsBase {
@Test
public void testSkippedInvocations() throws Exception {
// No specified activity should be ignored
- assertEquals(RESULT_SKIP, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+ assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
null /*activity*/, null /*source*/, null /*options*/, mCurrent, mResult));
// No specified activity options should be ignored
- assertEquals(RESULT_SKIP, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+ assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
mActivity, null /*source*/, null /*options*/, mCurrent, mResult));
// launch bounds specified should be ignored.
final ActivityOptions options = ActivityOptions.makeBasic();
- assertEquals(RESULT_SKIP, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+ assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
// Non-resizeable records should be ignored
mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
assertFalse(mActivity.isResizeable());
- assertEquals(RESULT_SKIP, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+ assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
// make record resizeable
mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
assertTrue(mActivity.isResizeable());
- assertEquals(RESULT_SKIP, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+ assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
// Does not support freeform
mService.mSupportsFreeformWindowManagement = false;
assertFalse(mService.mStackSupervisor.canUseActivityOptionsLaunchBounds(options));
- assertEquals(RESULT_SKIP, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+ assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
mService.mSupportsFreeformWindowManagement = true;
@@ -114,15 +114,15 @@ public class LaunchingActivityPositionerTests extends ActivityTestsBase {
assertTrue(mService.mStackSupervisor.canUseActivityOptionsLaunchBounds(options));
// Invalid bounds
- assertEquals(RESULT_SKIP, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+ assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
options.setLaunchBounds(new Rect(0, 0, -1, -1));
- assertEquals(RESULT_SKIP, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+ assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
// Valid bounds should cause the positioner to be applied.
options.setLaunchBounds(new Rect(0, 0, 100, 100));
- assertEquals(RESULT_DONE, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+ assertEquals(RESULT_DONE, mModifier.onCalculate(null /*task*/, null /*layout*/,
mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
}
@@ -136,8 +136,8 @@ public class LaunchingActivityPositionerTests extends ActivityTestsBase {
final Rect proposedBounds = new Rect(20, 30, 45, 40);
options.setLaunchBounds(proposedBounds);
- assertEquals(RESULT_DONE, mPositioner.onCalculateBounds(null /*task*/, null /*layout*/,
+ assertEquals(RESULT_DONE, mModifier.onCalculate(null /*task*/, null /*layout*/,
mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
- assertEquals(mResult, proposedBounds);
+ assertEquals(mResult.mBounds, proposedBounds);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/am/LaunchParamsControllerTests.java b/services/tests/servicestests/src/com/android/server/am/LaunchParamsControllerTests.java
new file mode 100644
index 000000000000..161c2875bf49
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/LaunchParamsControllerTests.java
@@ -0,0 +1,255 @@
+/*
+ * 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.am;
+
+import android.app.ActivityOptions;
+import android.content.pm.ActivityInfo.WindowLayout;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.server.am.LaunchParamsController.LaunchParams;
+import org.junit.runner.RunWith;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.android.server.am.LaunchParamsController.LaunchParamsModifier;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+/**
+ * Tests for exercising {@link LaunchParamsController}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:LaunchParamsControllerTests
+ */
+@MediumTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class LaunchParamsControllerTests extends ActivityTestsBase {
+ private ActivityManagerService mService;
+ private LaunchParamsController mController;
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mService = createActivityManagerService();
+ mController = new LaunchParamsController(mService);
+ }
+
+ /**
+ * Makes sure positioners get values passed to controller.
+ */
+ @Test
+ public void testArgumentPropagation() {
+ final LaunchParamsModifier
+ positioner = mock(LaunchParamsModifier.class);
+ mController.registerModifier(positioner);
+
+ final ActivityRecord record = new ActivityBuilder(mService).build();
+ final ActivityRecord source = new ActivityBuilder(mService).build();
+ final WindowLayout layout = new WindowLayout(0, 0, 0, 0, 0, 0, 0);
+ final ActivityOptions options = mock(ActivityOptions.class);
+
+ mController.calculate(record.getTask(), layout, record, source, options,
+ new LaunchParams());
+ verify(positioner, times(1)).onCalculate(eq(record.getTask()), eq(layout), eq(record),
+ eq(source), eq(options), any(), any());
+ }
+
+ /**
+ * Ensures positioners further down the chain are not called when RESULT_DONE is returned.
+ */
+ @Test
+ public void testEarlyExit() {
+ final LaunchParamsModifier
+ ignoredPositioner = mock(LaunchParamsModifier.class);
+ final LaunchParamsModifier earlyExitPositioner =
+ (task, layout, activity, source, options, currentParams, outParams) -> RESULT_DONE;
+
+ mController.registerModifier(ignoredPositioner);
+ mController.registerModifier(earlyExitPositioner);
+
+ mController.calculate(null /*task*/, null /*layout*/, null /*activity*/,
+ null /*source*/, null /*options*/, new LaunchParams());
+ verify(ignoredPositioner, never()).onCalculate(any(), any(), any(), any(), any(),
+ any(), any());
+ }
+
+ /**
+ * Ensures that positioners are called in the correct order.
+ */
+ @Test
+ public void testRegistration() {
+ LaunchParamsModifier earlyExitPositioner =
+ new InstrumentedPositioner(RESULT_DONE, new LaunchParams());
+
+ final LaunchParamsModifier firstPositioner = spy(earlyExitPositioner);
+
+ mController.registerModifier(firstPositioner);
+
+ mController.calculate(null /*task*/, null /*layout*/, null /*activity*/,
+ null /*source*/, null /*options*/, new LaunchParams());
+ verify(firstPositioner, times(1)).onCalculate(any(), any(), any(), any(), any(), any(),
+ any());
+
+ final LaunchParamsModifier secondPositioner = spy(earlyExitPositioner);
+
+ mController.registerModifier(secondPositioner);
+
+ mController.calculate(null /*task*/, null /*layout*/, null /*activity*/,
+ null /*source*/, null /*options*/, new LaunchParams());
+ verify(firstPositioner, times(1)).onCalculate(any(), any(), any(), any(), any(), any(),
+ any());
+ verify(secondPositioner, times(1)).onCalculate(any(), any(), any(), any(), any(), any(),
+ any());
+ }
+
+ /**
+ * Makes sure positioners further down the registration chain are called.
+ */
+ @Test
+ public void testPassThrough() {
+ final LaunchParamsModifier
+ positioner1 = mock(LaunchParamsModifier.class);
+ final LaunchParams params = new LaunchParams();
+ params.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ params.mBounds.set(0, 0, 30, 20);
+ params.mPreferredDisplayId = 3;
+
+ final InstrumentedPositioner positioner2 = new InstrumentedPositioner(RESULT_CONTINUE,
+ params);
+
+ mController.registerModifier(positioner1);
+ mController.registerModifier(positioner2);
+
+ mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, null /*source*/,
+ null /*options*/, new LaunchParams());
+
+ verify(positioner1, times(1)).onCalculate(any(), any(), any(), any(), any(),
+ eq(positioner2.getLaunchParams()), any());
+ }
+
+ /**
+ * Ensures skipped results are not propagated.
+ */
+ @Test
+ public void testSkip() {
+ final LaunchParams params1 = new LaunchParams();
+ params1.mBounds.set(0, 0, 10, 10);
+ final InstrumentedPositioner positioner1 = new InstrumentedPositioner(RESULT_SKIP, params1);
+
+ final LaunchParams params2 = new LaunchParams();
+ params2.mBounds.set(0, 0, 20, 30);
+ final InstrumentedPositioner positioner2 =
+ new InstrumentedPositioner(RESULT_CONTINUE, params2);
+
+ mController.registerModifier(positioner1);
+ mController.registerModifier(positioner2);
+
+ final LaunchParams
+ result = new LaunchParams();
+
+ mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, null /*source*/,
+ null /*options*/, result);
+
+ assertEquals(result, positioner2.getLaunchParams());
+ }
+
+ /**
+ * Ensures that {@link LaunchParamsModifier} requests specifying display id during
+ * layout are honored.
+ */
+ @Test
+ public void testLayoutTaskPreferredDisplayChange() {
+ final LaunchParams params = new LaunchParams();
+ params.mPreferredDisplayId = 2;
+ final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
+ final TaskRecord task = new TaskBuilder(mService.mStackSupervisor).build();
+
+ mController.registerModifier(positioner);
+
+ doNothing().when(mService).moveStackToDisplay(anyInt(), anyInt());
+ mController.layoutTask(task, null /* windowLayout */);
+ verify(mService, times(1)).moveStackToDisplay(eq(task.getStackId()),
+ eq(params.mPreferredDisplayId));
+ }
+
+ /**
+ * Ensures that {@link LaunchParamsModifier} requests specifying windowingMode during
+ * layout are honored.
+ */
+ @Test
+ public void testLayoutTaskWindowingModeChange() {
+ final LaunchParams params = new LaunchParams();
+ final int windowingMode = WINDOWING_MODE_FREEFORM;
+ params.mWindowingMode = windowingMode;
+ final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
+ final TaskRecord task = new TaskBuilder(mService.mStackSupervisor).build();
+
+ mController.registerModifier(positioner);
+
+ final int beforeWindowMode = task.getStack().getWindowingMode();
+ assertNotEquals(beforeWindowMode, windowingMode);
+
+ mController.layoutTask(task, null /* windowLayout */);
+
+ final int afterWindowMode = task.getStack().getWindowingMode();
+ assertEquals(afterWindowMode, windowingMode);
+ }
+
+ public static class InstrumentedPositioner implements
+ LaunchParamsModifier {
+
+ final private int mReturnVal;
+ final private LaunchParams mParams;
+
+ InstrumentedPositioner(int returnVal, LaunchParams params) {
+ mReturnVal = returnVal;
+ mParams = params;
+ }
+
+ @Override
+ public int onCalculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
+ ActivityRecord source, ActivityOptions options,
+ LaunchParams currentParams, LaunchParams outParams) {
+ outParams.set(mParams);
+ return mReturnVal;
+ }
+
+ LaunchParams getLaunchParams() {
+ return mParams;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/LaunchingBoundsControllerTests.java b/services/tests/servicestests/src/com/android/server/am/LaunchingBoundsControllerTests.java
deleted file mode 100644
index 0715174512b5..000000000000
--- a/services/tests/servicestests/src/com/android/server/am/LaunchingBoundsControllerTests.java
+++ /dev/null
@@ -1,194 +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.am;
-
-import android.app.ActivityOptions;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ActivityInfo.WindowLayout;
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.MediumTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.runner.RunWith;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner;
-
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_DONE;
-import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_CONTINUE;
-import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_SKIP;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Tests for exercising {@link LaunchingBoundsController}.
- *
- * Build/Install/Run:
- * bit FrameworksServicesTests:com.android.server.am.LaunchingBoundsControllerTests
- */
-@MediumTest
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-public class LaunchingBoundsControllerTests extends ActivityTestsBase {
- private LaunchingBoundsController mController;
-
- @Before
- @Override
- public void setUp() throws Exception {
- super.setUp();
- mController = new LaunchingBoundsController();
- }
-
- /**
- * Makes sure positioners get values passed to controller.
- */
- @Test
- public void testArgumentPropagation() {
- final ActivityManagerService service = createActivityManagerService();
- final LaunchingBoundsPositioner positioner = mock(LaunchingBoundsPositioner.class);
- mController.registerPositioner(positioner);
-
- final ActivityRecord record = new ActivityBuilder(service).build();
- final ActivityRecord source = new ActivityBuilder(service).build();
- final WindowLayout layout = new WindowLayout(0, 0, 0, 0, 0, 0, 0);
- final ActivityOptions options = mock(ActivityOptions.class);
-
- mController.calculateBounds(record.getTask(), layout, record, source, options, new Rect());
- verify(positioner, times(1)).onCalculateBounds(eq(record.getTask()), eq(layout), eq(record),
- eq(source), eq(options), any(), any());
- }
-
- /**
- * Ensures positioners further down the chain are not called when RESULT_DONE is returned.
- */
- @Test
- public void testEarlyExit() {
- final LaunchingBoundsPositioner ignoredPositioner = mock(LaunchingBoundsPositioner.class);
- final LaunchingBoundsPositioner earlyExitPositioner =
- (task, layout, activity, source, options, current, result) -> RESULT_DONE;
-
- mController.registerPositioner(ignoredPositioner);
- mController.registerPositioner(earlyExitPositioner);
-
- mController.calculateBounds(null /*task*/, null /*layout*/, null /*activity*/,
- null /*source*/, null /*options*/, new Rect());
- verify(ignoredPositioner, never()).onCalculateBounds(any(), any(), any(), any(), any(),
- any(), any());
- }
-
- /**
- * Ensures that positioners are called in the correct order.
- */
- @Test
- public void testRegistration() {
- LaunchingBoundsPositioner earlyExitPositioner =
- new InstrumentedPositioner(RESULT_DONE, new Rect());
-
- final LaunchingBoundsPositioner firstPositioner = spy(earlyExitPositioner);
-
- mController.registerPositioner(firstPositioner);
-
- mController.calculateBounds(null /*task*/, null /*layout*/, null /*activity*/,
- null /*source*/, null /*options*/, new Rect());
- verify(firstPositioner, times(1)).onCalculateBounds(any(), any(), any(), any(), any(),
- any(), any());
-
- final LaunchingBoundsPositioner secondPositioner = spy(earlyExitPositioner);
-
- mController.registerPositioner(secondPositioner);
-
- mController.calculateBounds(null /*task*/, null /*layout*/, null /*activity*/,
- null /*source*/, null /*options*/, new Rect());
- verify(firstPositioner, times(1)).onCalculateBounds(any(), any(), any(), any(), any(),
- any(), any());
- verify(secondPositioner, times(1)).onCalculateBounds(any(), any(), any(), any(), any(),
- any(), any());
- }
-
- /**
- * Makes sure positioners further down the registration chain are called.
- */
- @Test
- public void testPassThrough() {
- final LaunchingBoundsPositioner positioner1 = mock(LaunchingBoundsPositioner.class);
- final InstrumentedPositioner positioner2 = new InstrumentedPositioner(RESULT_CONTINUE,
- new Rect (0, 0, 30, 20));
-
- mController.registerPositioner(positioner1);
- mController.registerPositioner(positioner2);
-
- mController.calculateBounds(null /*task*/, null /*layout*/, null /*activity*/,
- null /*source*/, null /*options*/, new Rect());
-
- verify(positioner1, times(1)).onCalculateBounds(any(), any(), any(), any(), any(),
- eq(positioner2.getLaunchBounds()), any());
- }
-
- /**
- * Ensures skipped results are not propagated.
- */
- @Test
- public void testSkip() {
- final InstrumentedPositioner positioner1 =
- new InstrumentedPositioner(RESULT_SKIP, new Rect(0, 0, 10, 10));
-
-
- final InstrumentedPositioner positioner2 =
- new InstrumentedPositioner(RESULT_CONTINUE, new Rect(0, 0, 20, 30));
-
- mController.registerPositioner(positioner1);
- mController.registerPositioner(positioner2);
-
- final Rect resultBounds = new Rect();
-
- mController.calculateBounds(null /*task*/, null /*layout*/, null /*activity*/,
- null /*source*/, null /*options*/, resultBounds);
-
- assertEquals(resultBounds, positioner2.getLaunchBounds());
- }
-
- public static class InstrumentedPositioner implements LaunchingBoundsPositioner {
- private int mReturnVal;
- private Rect mBounds;
- InstrumentedPositioner(int returnVal, Rect bounds) {
- mReturnVal = returnVal;
- mBounds = bounds;
- }
-
- @Override
- public int onCalculateBounds(TaskRecord task, ActivityInfo.WindowLayout layout,
- ActivityRecord activity, ActivityRecord source,
- ActivityOptions options, Rect current, Rect result) {
- result.set(mBounds);
- return mReturnVal;
- }
-
- Rect getLaunchBounds() {
- return mBounds;
- }
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/am/LaunchingTaskPositionerTests.java b/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
index 13daf3e94508..3d323f0eb783 100644
--- a/services/tests/servicestests/src/com/android/server/am/LaunchingTaskPositionerTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
@@ -23,6 +23,7 @@ import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.Gravity;
+
import org.junit.runner.RunWith;
import org.junit.Before;
import org.junit.Test;
@@ -32,7 +33,7 @@ import org.mockito.invocation.InvocationOnMock;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_CONTINUE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
@@ -42,15 +43,15 @@ import static org.junit.Assert.assertEquals;
/**
- * Tests for exercising resizing bounds.
+ * Tests for exercising resizing task bounds.
*
* Build/Install/Run:
- * bit FrameworksServicesTests:com.android.server.am.LaunchingTaskPositionerTests
+ * atest FrameworksServicesTests:TaskLaunchParamsModifierTests
*/
@MediumTest
@Presubmit
@RunWith(AndroidJUnit4.class)
-public class LaunchingTaskPositionerTests extends ActivityTestsBase {
+public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
private final static int STACK_WIDTH = 100;
private final static int STACK_HEIGHT = 200;
@@ -60,10 +61,10 @@ public class LaunchingTaskPositionerTests extends ActivityTestsBase {
private ActivityStack mStack;
private TaskRecord mTask;
- private LaunchingTaskPositioner mPositioner;
+ private TaskLaunchParamsModifier mPositioner;
- private Rect mCurrent;
- private Rect mResult;
+ private LaunchParamsController.LaunchParams mCurrent;
+ private LaunchParamsController.LaunchParams mResult;
@Before
@Override
@@ -79,10 +80,10 @@ public class LaunchingTaskPositionerTests extends ActivityTestsBase {
// dimensions on resize.
mTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
- mPositioner = new LaunchingTaskPositioner();
+ mPositioner = new TaskLaunchParamsModifier();
- mResult = new Rect();
- mCurrent = new Rect();
+ mResult = new LaunchParamsController.LaunchParams();
+ mCurrent = new LaunchParamsController.LaunchParams();
}
/**
@@ -103,9 +104,9 @@ public class LaunchingTaskPositionerTests extends ActivityTestsBase {
*/
@Test
public void testLaunchNoWindowLayout() throws Exception {
- assertEquals(RESULT_CONTINUE, mPositioner.onCalculateBounds(mTask, null /*layout*/,
+ assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask, null /*layout*/,
null /*record*/, null /*source*/, null /*options*/, mCurrent, mResult));
- assertEquals(getDefaultBounds(Gravity.NO_GRAVITY), mResult);
+ assertEquals(getDefaultBounds(Gravity.NO_GRAVITY), mResult.mBounds);
}
/**
@@ -115,10 +116,10 @@ public class LaunchingTaskPositionerTests extends ActivityTestsBase {
*/
@Test
public void testlaunchEmptyWindowLayout() throws Exception {
- assertEquals(RESULT_CONTINUE, mPositioner.onCalculateBounds(mTask,
+ assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask,
new WindowLayout(0, 0, 0, 0, Gravity.NO_GRAVITY, 0, 0), null /*activity*/,
null /*source*/, null /*options*/, mCurrent, mResult));
- assertEquals(mResult, getDefaultBounds(Gravity.NO_GRAVITY));
+ assertEquals(mResult.mBounds, getDefaultBounds(Gravity.NO_GRAVITY));
}
/**
@@ -148,13 +149,13 @@ public class LaunchingTaskPositionerTests extends ActivityTestsBase {
private void testGravity(int gravity) {
try {
- assertEquals(RESULT_CONTINUE, mPositioner.onCalculateBounds(mTask,
+ assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask,
new WindowLayout(0, 0, 0, 0, gravity, 0, 0), null /*activity*/,
null /*source*/, null /*options*/, mCurrent, mResult));
- assertEquals(mResult, getDefaultBounds(gravity));
+ assertEquals(mResult.mBounds, getDefaultBounds(gravity));
} finally {
- mCurrent.setEmpty();
- mResult.setEmpty();
+ mCurrent.reset();
+ mResult.reset();
}
}
@@ -178,7 +179,7 @@ public class LaunchingTaskPositionerTests extends ActivityTestsBase {
final WindowLayout layout = new WindowLayout(0, 0, 0, 0, gravity, 0, 0);
// layout first task
- mService.mStackSupervisor.getLaunchingBoundsController().layoutTask(mTask, layout);
+ mService.mStackSupervisor.getLaunchParamsController().layoutTask(mTask, layout);
// Second task will be laid out on top of the first so starting bounds is the same.
final Rect expectedBounds = new Rect(mTask.getOverrideBounds());
@@ -196,25 +197,25 @@ public class LaunchingTaskPositionerTests extends ActivityTestsBase {
// layout second task
assertEquals(RESULT_CONTINUE,
- mPositioner.onCalculateBounds(secondTask, layout, null /*activity*/,
+ mPositioner.onCalculate(secondTask, layout, null /*activity*/,
null /*source*/, null /*options*/, mCurrent, mResult));
if ((gravity & (Gravity.TOP | Gravity.RIGHT)) == (Gravity.TOP | Gravity.RIGHT)
|| (gravity & (Gravity.BOTTOM | Gravity.RIGHT))
== (Gravity.BOTTOM | Gravity.RIGHT)) {
- expectedBounds.offset(-LaunchingTaskPositioner.getHorizontalStep(
+ expectedBounds.offset(-TaskLaunchParamsModifier.getHorizontalStep(
mStack.getOverrideBounds()), 0);
} else if ((gravity & Gravity.TOP) == Gravity.TOP
|| (gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
expectedBounds.offset(
- LaunchingTaskPositioner.getHorizontalStep(mStack.getOverrideBounds()), 0);
+ TaskLaunchParamsModifier.getHorizontalStep(mStack.getOverrideBounds()), 0);
} else {
expectedBounds.offset(
- LaunchingTaskPositioner.getHorizontalStep(mStack.getOverrideBounds()),
- LaunchingTaskPositioner.getVerticalStep(mStack.getOverrideBounds()));
+ TaskLaunchParamsModifier.getHorizontalStep(mStack.getOverrideBounds()),
+ TaskLaunchParamsModifier.getVerticalStep(mStack.getOverrideBounds()));
}
- assertEquals(mResult, expectedBounds);
+ assertEquals(mResult.mBounds, expectedBounds);
} finally {
// Remove task and activity to prevent influencing future tests
if (activity != null) {
@@ -232,9 +233,9 @@ public class LaunchingTaskPositionerTests extends ActivityTestsBase {
bounds.set(mStack.getOverrideBounds());
final int verticalInset =
- LaunchingTaskPositioner.getFreeformStartTop(mStack.getOverrideBounds());
+ TaskLaunchParamsModifier.getFreeformStartTop(mStack.getOverrideBounds());
final int horizontalInset =
- LaunchingTaskPositioner.getFreeformStartLeft(mStack.getOverrideBounds());
+ TaskLaunchParamsModifier.getFreeformStartLeft(mStack.getOverrideBounds());
bounds.inset(horizontalInset, verticalInset);