Loading services/core/java/com/android/server/am/ActivityStack.java +2 −14 Original line number Diff line number Diff line Loading @@ -107,7 +107,6 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; import android.net.Uri; import android.os.Binder; Loading Loading @@ -346,7 +345,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai private final SparseArray<Rect> mTmpBounds = new SparseArray<>(); private final SparseArray<Rect> mTmpInsetBounds = new SparseArray<>(); private final Rect mTmpRect2 = new Rect(); private final Point mTmpSize = new Point(); /** Run all ActivityStacks through this */ protected final ActivityStackSupervisor mStackSupervisor; Loading Loading @@ -5053,24 +5051,14 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai addTask(task, toTop, "createTaskRecord"); final boolean isLockscreenShown = mService.mStackSupervisor.mKeyguardController .isKeyguardShowing(mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY); if (!layoutTaskInStack(task, info.windowLayout) && mBounds != null && task.isResizeable() && !isLockscreenShown) { if (!mStackSupervisor.getLaunchingBoundsController().layoutTask(task, info.windowLayout) && mBounds != null && task.isResizeable() && !isLockscreenShown) { task.updateOverrideConfiguration(mBounds); } task.createWindowContainer(toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0); return task; } boolean layoutTaskInStack(TaskRecord task, ActivityInfo.WindowLayout windowLayout) { if (!task.inFreeformWindowingMode()) { return false; } mStackSupervisor.getLaunchingTaskPositioner() .updateDefaultBounds(task, mTaskHistory, windowLayout); return true; } ArrayList<TaskRecord> getAllTasks() { return new ArrayList<>(mTaskHistory); } Loading services/core/java/com/android/server/am/ActivityStackSupervisor.java +6 −3 Original line number Diff line number Diff line Loading @@ -287,7 +287,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D WindowManagerService mWindowManager; DisplayManager mDisplayManager; LaunchingTaskPositioner mTaskPositioner = new LaunchingTaskPositioner(); private final LaunchingBoundsController mLaunchingBoundsController; /** Counter for next free stack ID to use for dynamic activity stacks. */ private int mNextFreeStackId = 0; Loading Loading @@ -568,6 +568,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mHandler = new ActivityStackSupervisorHandler(looper); mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext); mKeyguardController = new KeyguardController(service, this); mLaunchingBoundsController = new LaunchingBoundsController(); mLaunchingBoundsController.registerDefaultPositioners(this); } void setRecentTasks(RecentTasks recentTasks) { Loading Loading @@ -2154,8 +2157,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D || mService.mSupportsFreeformWindowManagement; } LaunchingTaskPositioner getLaunchingTaskPositioner() { return mTaskPositioner; LaunchingBoundsController getLaunchingBoundsController() { return mLaunchingBoundsController; } protected <T extends ActivityStack> T getStack(int stackId) { Loading services/core/java/com/android/server/am/ActivityStarter.java +13 −12 Original line number Diff line number Diff line Loading @@ -151,7 +151,7 @@ class ActivityStarter { private boolean mLaunchTaskBehind; private int mLaunchFlags; private Rect mLaunchBounds; private Rect mLaunchBounds = new Rect(); private ActivityRecord mNotTop; private boolean mDoResume; Loading Loading @@ -210,7 +210,7 @@ class ActivityStarter { mLaunchFlags = 0; mLaunchMode = INVALID_LAUNCH_MODE; mLaunchBounds = null; mLaunchBounds.setEmpty(); mNotTop = null; mDoResume = false; Loading Loading @@ -1254,7 +1254,10 @@ class ActivityStarter { mPreferredDisplayId = getPreferedDisplayId(mSourceRecord, mStartActivity, options); mLaunchBounds = getOverrideBounds(r, options, inTask); mLaunchBounds.setEmpty(); mSupervisor.getLaunchingBoundsController().calculateBounds(inTask, null /*layout*/, r, options, mLaunchBounds); mLaunchMode = r.launchMode; Loading Loading @@ -1725,7 +1728,7 @@ class ActivityStarter { // Target stack got cleared when we all activities were removed above. // Go ahead and reset it. mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */, null /* bounds */, mLaunchFlags, mOptions); mLaunchFlags, mOptions); mTargetStack.addTask(task, !mLaunchTaskBehind /* toTop */, "startActivityUnchecked"); } Loading Loading @@ -1776,8 +1779,7 @@ class ActivityStarter { private int setTaskFromReuseOrCreateNewTask( TaskRecord taskToAffiliate, ActivityStack topStack) { mTargetStack = computeStackFocus( mStartActivity, true, mLaunchBounds, mLaunchFlags, mOptions); mTargetStack = computeStackFocus(mStartActivity, true, mLaunchFlags, mOptions); // Do no move the target stack to front yet, as we might bail if // isLockTaskModeViolation fails below. Loading Loading @@ -1962,7 +1964,7 @@ class ActivityStarter { return START_TASK_TO_FRONT; } if (mLaunchBounds != null) { if (!mLaunchBounds.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()) { Loading @@ -1985,7 +1987,7 @@ class ActivityStarter { } void updateBounds(TaskRecord task, Rect bounds) { if (bounds == null) { if (bounds.isEmpty()) { return; } Loading @@ -1998,8 +2000,7 @@ class ActivityStarter { } private void setTaskToCurrentTopOrCreateNewTask() { mTargetStack = computeStackFocus(mStartActivity, false, null /* bounds */, mLaunchFlags, mOptions); mTargetStack = computeStackFocus(mStartActivity, false, mLaunchFlags, mOptions); if (mDoResume) { mTargetStack.moveToFront("addingToTopTask"); } Loading Loading @@ -2062,8 +2063,8 @@ class ActivityStarter { } } private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds, int launchFlags, ActivityOptions aOptions) { private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, int launchFlags, ActivityOptions aOptions) { final TaskRecord task = r.getTask(); ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions); if (stack != null) { Loading services/core/java/com/android/server/am/LaunchingActivityPositioner.java 0 → 100644 +62 −0 Original line number Diff line number Diff line /* * 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.graphics.Rect; import com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner; /** * An implementation of {@link LaunchingBoundsPositioner}, which applies the launch bounds specified * inside {@link ActivityOptions#getLaunchBounds()}. */ public class LaunchingActivityPositioner implements LaunchingBoundsPositioner { private final ActivityStackSupervisor mSupervisor; LaunchingActivityPositioner(ActivityStackSupervisor activityStackSupervisor) { mSupervisor = activityStackSupervisor; } @Override public int onCalculateBounds(TaskRecord task, ActivityInfo.WindowLayout layout, ActivityRecord activity, ActivityOptions options, Rect current, Rect result) { // We only care about figuring out bounds for activities. if (activity == null) { return RESULT_SKIP; } // Activity must be resizeable in the specified task. if (!(mSupervisor.canUseActivityOptionsLaunchBounds(options) && (activity.isResizeable() || (task != null && task.isResizeable())))) { return RESULT_SKIP; } final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds()); // Bounds weren't valid. if (bounds == null) { return RESULT_SKIP; } result.set(bounds); // When this is the most explicit position specification so we should not allow further // modification of the position. return RESULT_DONE; } } services/core/java/com/android/server/am/LaunchingBoundsController.java 0 → 100644 +160 −0 Original line number Diff line number Diff line /* * 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 options The {@link ActivityOptions} specified for the activity. * @param result The resulting bounds. If no bounds are set, {@link Rect#isEmpty()} will be * true. */ void calculateBounds(TaskRecord task, WindowLayout layout, ActivityRecord activity, 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, 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) { calculateBounds(task, layout, null /*activity*/, null /*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 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, ActivityOptions options, Rect current, Rect result); } } Loading
services/core/java/com/android/server/am/ActivityStack.java +2 −14 Original line number Diff line number Diff line Loading @@ -107,7 +107,6 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; import android.net.Uri; import android.os.Binder; Loading Loading @@ -346,7 +345,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai private final SparseArray<Rect> mTmpBounds = new SparseArray<>(); private final SparseArray<Rect> mTmpInsetBounds = new SparseArray<>(); private final Rect mTmpRect2 = new Rect(); private final Point mTmpSize = new Point(); /** Run all ActivityStacks through this */ protected final ActivityStackSupervisor mStackSupervisor; Loading Loading @@ -5053,24 +5051,14 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai addTask(task, toTop, "createTaskRecord"); final boolean isLockscreenShown = mService.mStackSupervisor.mKeyguardController .isKeyguardShowing(mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY); if (!layoutTaskInStack(task, info.windowLayout) && mBounds != null && task.isResizeable() && !isLockscreenShown) { if (!mStackSupervisor.getLaunchingBoundsController().layoutTask(task, info.windowLayout) && mBounds != null && task.isResizeable() && !isLockscreenShown) { task.updateOverrideConfiguration(mBounds); } task.createWindowContainer(toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0); return task; } boolean layoutTaskInStack(TaskRecord task, ActivityInfo.WindowLayout windowLayout) { if (!task.inFreeformWindowingMode()) { return false; } mStackSupervisor.getLaunchingTaskPositioner() .updateDefaultBounds(task, mTaskHistory, windowLayout); return true; } ArrayList<TaskRecord> getAllTasks() { return new ArrayList<>(mTaskHistory); } Loading
services/core/java/com/android/server/am/ActivityStackSupervisor.java +6 −3 Original line number Diff line number Diff line Loading @@ -287,7 +287,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D WindowManagerService mWindowManager; DisplayManager mDisplayManager; LaunchingTaskPositioner mTaskPositioner = new LaunchingTaskPositioner(); private final LaunchingBoundsController mLaunchingBoundsController; /** Counter for next free stack ID to use for dynamic activity stacks. */ private int mNextFreeStackId = 0; Loading Loading @@ -568,6 +568,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mHandler = new ActivityStackSupervisorHandler(looper); mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext); mKeyguardController = new KeyguardController(service, this); mLaunchingBoundsController = new LaunchingBoundsController(); mLaunchingBoundsController.registerDefaultPositioners(this); } void setRecentTasks(RecentTasks recentTasks) { Loading Loading @@ -2154,8 +2157,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D || mService.mSupportsFreeformWindowManagement; } LaunchingTaskPositioner getLaunchingTaskPositioner() { return mTaskPositioner; LaunchingBoundsController getLaunchingBoundsController() { return mLaunchingBoundsController; } protected <T extends ActivityStack> T getStack(int stackId) { Loading
services/core/java/com/android/server/am/ActivityStarter.java +13 −12 Original line number Diff line number Diff line Loading @@ -151,7 +151,7 @@ class ActivityStarter { private boolean mLaunchTaskBehind; private int mLaunchFlags; private Rect mLaunchBounds; private Rect mLaunchBounds = new Rect(); private ActivityRecord mNotTop; private boolean mDoResume; Loading Loading @@ -210,7 +210,7 @@ class ActivityStarter { mLaunchFlags = 0; mLaunchMode = INVALID_LAUNCH_MODE; mLaunchBounds = null; mLaunchBounds.setEmpty(); mNotTop = null; mDoResume = false; Loading Loading @@ -1254,7 +1254,10 @@ class ActivityStarter { mPreferredDisplayId = getPreferedDisplayId(mSourceRecord, mStartActivity, options); mLaunchBounds = getOverrideBounds(r, options, inTask); mLaunchBounds.setEmpty(); mSupervisor.getLaunchingBoundsController().calculateBounds(inTask, null /*layout*/, r, options, mLaunchBounds); mLaunchMode = r.launchMode; Loading Loading @@ -1725,7 +1728,7 @@ class ActivityStarter { // Target stack got cleared when we all activities were removed above. // Go ahead and reset it. mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */, null /* bounds */, mLaunchFlags, mOptions); mLaunchFlags, mOptions); mTargetStack.addTask(task, !mLaunchTaskBehind /* toTop */, "startActivityUnchecked"); } Loading Loading @@ -1776,8 +1779,7 @@ class ActivityStarter { private int setTaskFromReuseOrCreateNewTask( TaskRecord taskToAffiliate, ActivityStack topStack) { mTargetStack = computeStackFocus( mStartActivity, true, mLaunchBounds, mLaunchFlags, mOptions); mTargetStack = computeStackFocus(mStartActivity, true, mLaunchFlags, mOptions); // Do no move the target stack to front yet, as we might bail if // isLockTaskModeViolation fails below. Loading Loading @@ -1962,7 +1964,7 @@ class ActivityStarter { return START_TASK_TO_FRONT; } if (mLaunchBounds != null) { if (!mLaunchBounds.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()) { Loading @@ -1985,7 +1987,7 @@ class ActivityStarter { } void updateBounds(TaskRecord task, Rect bounds) { if (bounds == null) { if (bounds.isEmpty()) { return; } Loading @@ -1998,8 +2000,7 @@ class ActivityStarter { } private void setTaskToCurrentTopOrCreateNewTask() { mTargetStack = computeStackFocus(mStartActivity, false, null /* bounds */, mLaunchFlags, mOptions); mTargetStack = computeStackFocus(mStartActivity, false, mLaunchFlags, mOptions); if (mDoResume) { mTargetStack.moveToFront("addingToTopTask"); } Loading Loading @@ -2062,8 +2063,8 @@ class ActivityStarter { } } private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds, int launchFlags, ActivityOptions aOptions) { private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, int launchFlags, ActivityOptions aOptions) { final TaskRecord task = r.getTask(); ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions); if (stack != null) { Loading
services/core/java/com/android/server/am/LaunchingActivityPositioner.java 0 → 100644 +62 −0 Original line number Diff line number Diff line /* * 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.graphics.Rect; import com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner; /** * An implementation of {@link LaunchingBoundsPositioner}, which applies the launch bounds specified * inside {@link ActivityOptions#getLaunchBounds()}. */ public class LaunchingActivityPositioner implements LaunchingBoundsPositioner { private final ActivityStackSupervisor mSupervisor; LaunchingActivityPositioner(ActivityStackSupervisor activityStackSupervisor) { mSupervisor = activityStackSupervisor; } @Override public int onCalculateBounds(TaskRecord task, ActivityInfo.WindowLayout layout, ActivityRecord activity, ActivityOptions options, Rect current, Rect result) { // We only care about figuring out bounds for activities. if (activity == null) { return RESULT_SKIP; } // Activity must be resizeable in the specified task. if (!(mSupervisor.canUseActivityOptionsLaunchBounds(options) && (activity.isResizeable() || (task != null && task.isResizeable())))) { return RESULT_SKIP; } final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds()); // Bounds weren't valid. if (bounds == null) { return RESULT_SKIP; } result.set(bounds); // When this is the most explicit position specification so we should not allow further // modification of the position. return RESULT_DONE; } }
services/core/java/com/android/server/am/LaunchingBoundsController.java 0 → 100644 +160 −0 Original line number Diff line number Diff line /* * 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 options The {@link ActivityOptions} specified for the activity. * @param result The resulting bounds. If no bounds are set, {@link Rect#isEmpty()} will be * true. */ void calculateBounds(TaskRecord task, WindowLayout layout, ActivityRecord activity, 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, 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) { calculateBounds(task, layout, null /*activity*/, null /*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 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, ActivityOptions options, Rect current, Rect result); } }