blob: 59c02f7365136053403f0078342db371e0da1725 [file] [log] [blame]
Bryce Leeec55eb02017-12-05 20:51:27 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
Wale Ogunwale59507092018-10-29 09:00:30 -070017package com.android.server.wm;
Bryce Leeec55eb02017-12-05 20:51:27 -080018
Garfield Tanb5cc09f2018-09-28 10:06:52 -070019import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
Louis Chang39ba54b2018-10-18 11:28:57 +080020import static android.view.Display.DEFAULT_DISPLAY;
Garfield Tanb5cc09f2018-09-28 10:06:52 -070021import static android.view.Display.INVALID_DISPLAY;
22
Louis Chang6fb1e842018-12-03 16:07:50 +080023import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
Wale Ogunwale59507092018-10-29 09:00:30 -070024import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
25import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
26import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
Garfield Tanb5cc09f2018-09-28 10:06:52 -070027
Bryce Leeec55eb02017-12-05 20:51:27 -080028import android.annotation.IntDef;
29import android.app.ActivityOptions;
30import android.content.pm.ActivityInfo.WindowLayout;
31import android.graphics.Rect;
32
33import java.lang.annotation.Retention;
34import java.lang.annotation.RetentionPolicy;
35import java.util.ArrayList;
36import java.util.List;
37
Bryce Leeec55eb02017-12-05 20:51:27 -080038/**
39 * {@link LaunchParamsController} calculates the {@link LaunchParams} by coordinating between
40 * registered {@link LaunchParamsModifier}s.
41 */
42class LaunchParamsController {
Wale Ogunwalea6191b42018-05-09 07:41:32 -070043 private final ActivityTaskManagerService mService;
Garfield Tan891146c2018-10-09 12:14:00 -070044 private final LaunchParamsPersister mPersister;
Bryce Leeec55eb02017-12-05 20:51:27 -080045 private final List<LaunchParamsModifier> mModifiers = new ArrayList<>();
46
47 // Temporary {@link LaunchParams} for internal calculations. This is kept separate from
48 // {@code mTmpCurrent} and {@code mTmpResult} to prevent clobbering values.
49 private final LaunchParams mTmpParams = new LaunchParams();
50
51 private final LaunchParams mTmpCurrent = new LaunchParams();
52 private final LaunchParams mTmpResult = new LaunchParams();
53
Garfield Tan891146c2018-10-09 12:14:00 -070054 LaunchParamsController(ActivityTaskManagerService service, LaunchParamsPersister persister) {
55 mService = service;
56 mPersister = persister;
Bryce Leeec55eb02017-12-05 20:51:27 -080057 }
58
59 /**
60 * Creates a {@link LaunchParamsController} with default registered
61 * {@link LaunchParamsModifier}s.
62 */
63 void registerDefaultModifiers(ActivityStackSupervisor supervisor) {
64 // {@link TaskLaunchParamsModifier} handles window layout preferences.
Garfield Tanb5cc09f2018-09-28 10:06:52 -070065 registerModifier(new TaskLaunchParamsModifier(supervisor));
Bryce Leeec55eb02017-12-05 20:51:27 -080066 }
67
68 /**
69 * Returns the {@link LaunchParams} calculated by the registered modifiers
70 * @param task The {@link TaskRecord} currently being positioned.
71 * @param layout The specified {@link WindowLayout}.
72 * @param activity The {@link ActivityRecord} currently being positioned.
73 * @param source The {@link ActivityRecord} from which activity was started from.
74 * @param options The {@link ActivityOptions} specified for the activity.
75 * @param result The resulting params.
76 */
77 void calculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
Louis Chang6fb1e842018-12-03 16:07:50 +080078 ActivityRecord source, ActivityOptions options, int phase, LaunchParams result) {
Bryce Leeec55eb02017-12-05 20:51:27 -080079 result.reset();
80
Garfield Tan891146c2018-10-09 12:14:00 -070081 if (task != null || activity != null) {
82 mPersister.getLaunchParams(task, activity, result);
83 }
84
Bryce Leeec55eb02017-12-05 20:51:27 -080085 // We start at the last registered {@link LaunchParamsModifier} as this represents
86 // The modifier closest to the product level. Moving back through the list moves closer to
87 // the platform logic.
88 for (int i = mModifiers.size() - 1; i >= 0; --i) {
89 mTmpCurrent.set(result);
90 mTmpResult.reset();
91 final LaunchParamsModifier modifier = mModifiers.get(i);
92
Louis Chang6fb1e842018-12-03 16:07:50 +080093 switch(modifier.onCalculate(task, layout, activity, source, options, phase, mTmpCurrent,
Bryce Leeec55eb02017-12-05 20:51:27 -080094 mTmpResult)) {
95 case RESULT_SKIP:
96 // Do not apply any results when we are told to skip
97 continue;
98 case RESULT_DONE:
99 // Set result and return immediately.
100 result.set(mTmpResult);
101 return;
102 case RESULT_CONTINUE:
103 // Set result and continue
104 result.set(mTmpResult);
105 break;
106 }
107 }
Louis Chang39ba54b2018-10-18 11:28:57 +0800108
109 if (activity != null && activity.requestedVrComponent != null) {
110 // Check if the Activity is a VR activity. If so, it should be launched in main display.
111 result.mPreferredDisplayId = DEFAULT_DISPLAY;
112 } else if (mService.mVr2dDisplayId != INVALID_DISPLAY) {
113 // Get the virtual display ID from ActivityTaskManagerService. If that's set we
114 // should always use that.
115 result.mPreferredDisplayId = mService.mVr2dDisplayId;
116 }
Bryce Leeec55eb02017-12-05 20:51:27 -0800117 }
118
119 /**
120 * A convenience method for laying out a task.
121 * @return {@code true} if bounds were set on the task. {@code false} otherwise.
122 */
123 boolean layoutTask(TaskRecord task, WindowLayout layout) {
124 return layoutTask(task, layout, null /*activity*/, null /*source*/, null /*options*/);
125 }
126
127 boolean layoutTask(TaskRecord task, WindowLayout layout, ActivityRecord activity,
128 ActivityRecord source, ActivityOptions options) {
Louis Chang6fb1e842018-12-03 16:07:50 +0800129 calculate(task, layout, activity, source, options, PHASE_BOUNDS, mTmpParams);
Bryce Leeec55eb02017-12-05 20:51:27 -0800130
131 // No changes, return.
132 if (mTmpParams.isEmpty()) {
133 return false;
134 }
135
136 mService.mWindowManager.deferSurfaceLayout();
137
138 try {
139 if (mTmpParams.hasPreferredDisplay()
140 && mTmpParams.mPreferredDisplayId != task.getStack().getDisplay().mDisplayId) {
Wale Ogunwalea6191b42018-05-09 07:41:32 -0700141 mService.moveStackToDisplay(task.getStackId(), mTmpParams.mPreferredDisplayId);
Bryce Leeec55eb02017-12-05 20:51:27 -0800142 }
143
144 if (mTmpParams.hasWindowingMode()
145 && mTmpParams.mWindowingMode != task.getStack().getWindowingMode()) {
146 task.getStack().setWindowingMode(mTmpParams.mWindowingMode);
147 }
148
Garfield Tan891146c2018-10-09 12:14:00 -0700149 if (mTmpParams.mBounds.isEmpty()) {
Bryce Leeec55eb02017-12-05 20:51:27 -0800150 return false;
151 }
Garfield Tan891146c2018-10-09 12:14:00 -0700152
153 if (task.getStack().inFreeformWindowingMode()) {
154 // Only set bounds if it's in freeform mode.
155 task.updateOverrideConfiguration(mTmpParams.mBounds);
156 return true;
157 }
158
159 // Setting last non-fullscreen bounds to the bounds so next time the task enters
160 // freeform windowing mode it can be in this bounds.
161 task.setLastNonFullscreenBounds(mTmpParams.mBounds);
162 return false;
Bryce Leeec55eb02017-12-05 20:51:27 -0800163 } finally {
164 mService.mWindowManager.continueSurfaceLayout();
165 }
166 }
167
168 /**
169 * Adds a modifier to participate in future bounds calculation. Note that the last registered
170 * {@link LaunchParamsModifier} will be the first to calculate the bounds.
171 */
172 void registerModifier(LaunchParamsModifier modifier) {
173 if (mModifiers.contains(modifier)) {
174 return;
175 }
176
177 mModifiers.add(modifier);
178 }
179
180 /**
181 * A container for holding launch related fields.
182 */
183 static class LaunchParams {
184 /** The bounds within the parent container. */
185 final Rect mBounds = new Rect();
186
187 /** The id of the display the {@link TaskRecord} would prefer to be on. */
188 int mPreferredDisplayId;
189
190 /** The windowing mode to be in. */
191 int mWindowingMode;
192
193 /** Sets values back to default. {@link #isEmpty} will return {@code true} once called. */
194 void reset() {
195 mBounds.setEmpty();
196 mPreferredDisplayId = INVALID_DISPLAY;
197 mWindowingMode = WINDOWING_MODE_UNDEFINED;
198 }
199
200 /** Copies the values set on the passed in {@link LaunchParams}. */
201 void set(LaunchParams params) {
202 mBounds.set(params.mBounds);
203 mPreferredDisplayId = params.mPreferredDisplayId;
204 mWindowingMode = params.mWindowingMode;
205 }
206
207 /** Returns {@code true} if no values have been explicitly set. */
208 boolean isEmpty() {
209 return mBounds.isEmpty() && mPreferredDisplayId == INVALID_DISPLAY
210 && mWindowingMode == WINDOWING_MODE_UNDEFINED;
211 }
212
213 boolean hasWindowingMode() {
214 return mWindowingMode != WINDOWING_MODE_UNDEFINED;
215 }
216
217 boolean hasPreferredDisplay() {
218 return mPreferredDisplayId != INVALID_DISPLAY;
219 }
220
221 @Override
222 public boolean equals(Object o) {
223 if (this == o) return true;
224 if (o == null || getClass() != o.getClass()) return false;
225
226 LaunchParams that = (LaunchParams) o;
227
228 if (mPreferredDisplayId != that.mPreferredDisplayId) return false;
229 if (mWindowingMode != that.mWindowingMode) return false;
230 return mBounds != null ? mBounds.equals(that.mBounds) : that.mBounds == null;
231 }
232
233 @Override
234 public int hashCode() {
235 int result = mBounds != null ? mBounds.hashCode() : 0;
236 result = 31 * result + mPreferredDisplayId;
237 result = 31 * result + mWindowingMode;
238 return result;
239 }
240 }
241
242 /**
243 * An interface implemented by those wanting to participate in bounds calculation.
244 */
245 interface LaunchParamsModifier {
246 @Retention(RetentionPolicy.SOURCE)
247 @IntDef({RESULT_SKIP, RESULT_DONE, RESULT_CONTINUE})
248 @interface Result {}
249
Garfield Tanb5cc09f2018-09-28 10:06:52 -0700250 /** Returned when the modifier does not want to influence the bounds calculation */
Bryce Leeec55eb02017-12-05 20:51:27 -0800251 int RESULT_SKIP = 0;
Garfield Tanb5cc09f2018-09-28 10:06:52 -0700252 /**
253 * Returned when the modifier has changed the bounds and would like its results to be the
254 * final bounds applied.
255 */
Bryce Leeec55eb02017-12-05 20:51:27 -0800256 int RESULT_DONE = 1;
Garfield Tanb5cc09f2018-09-28 10:06:52 -0700257 /**
258 * Returned when the modifier has changed the bounds but is okay with other modifiers
259 * influencing the bounds.
260 */
Bryce Leeec55eb02017-12-05 20:51:27 -0800261 int RESULT_CONTINUE = 2;
262
Louis Chang6fb1e842018-12-03 16:07:50 +0800263 @Retention(RetentionPolicy.SOURCE)
264 @IntDef({PHASE_DISPLAY, PHASE_WINDOWING_MODE, PHASE_BOUNDS})
265 @interface Phase {}
266
267 /**
268 * Stops once we are done with preferred display calculation.
269 */
270 int PHASE_DISPLAY = 0;
271
272 /**
273 * Stops once we are done with windowing mode calculation.
274 */
275 int PHASE_WINDOWING_MODE = 1;
276
277 /**
278 * Stops once we are done with window bounds calculation.
279 */
280 int PHASE_BOUNDS = 2;
281
Bryce Leeec55eb02017-12-05 20:51:27 -0800282 /**
Garfield Tanb5cc09f2018-09-28 10:06:52 -0700283 * Returns the launch params that the provided activity launch params should be overridden
284 * to. {@link LaunchParamsModifier} can use this for various purposes, including: 1)
285 * Providing default bounds if the launch bounds have not been provided. 2) Repositioning
286 * the task so it doesn't get placed over an existing task. 3) Resizing the task so that its
287 * dimensions match the activity's requested orientation.
288 *
289 * @param task Can be: 1) the target task in which the source activity wants to
290 * launch the target activity; 2) a newly created task that Android
291 * gives a chance to override its launching bounds; 3) {@code null} if
292 * this is called to override an activity's launching bounds.
293 * @param layout Desired layout when activity is first launched.
294 * @param activity Activity that is being started. This can be {@code null} on
295 * re-parenting an activity to a new task (e.g. for
296 * Picture-In-Picture). Tasks being created because an activity was
297 * launched should have this be non-null.
298 * @param source the Activity that launched a new task. Could be {@code null}.
299 * @param options {@link ActivityOptions} used to start the activity with.
Louis Chang6fb1e842018-12-03 16:07:50 +0800300 * @param phase the calculation phase, see {@link LaunchParamsModifier.Phase}
Garfield Tanb5cc09f2018-09-28 10:06:52 -0700301 * @param currentParams launching params after the process of last {@link
302 * LaunchParamsModifier}.
303 * @param outParams the result params to be set.
304 * @return see {@link LaunchParamsModifier.Result}
Bryce Leeec55eb02017-12-05 20:51:27 -0800305 */
306 @Result
307 int onCalculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
Louis Chang6fb1e842018-12-03 16:07:50 +0800308 ActivityRecord source, ActivityOptions options, @Phase int phase,
309 LaunchParams currentParams, LaunchParams outParams);
Bryce Leeec55eb02017-12-05 20:51:27 -0800310 }
311}