diff options
| author | 2018-01-11 15:26:45 +0000 | |
|---|---|---|
| committer | 2018-01-11 15:26:45 +0000 | |
| commit | 842db5e6c20cb9a5932d6d0c4c29cbca67590492 (patch) | |
| tree | e7cc0b1e178eb13ca44a1166b123558145f1f46f | |
| parent | bd76bebadeae955db670b2d118cf5c0e3eac9046 (diff) | |
| parent | ec55eb06eb4868ca593c4b16438b3c6121701c1a (diff) | |
Merge "Allow modifiers to specify windowing mode and preferred display."
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); |