blob: 5aa7f58f0968e28da42ce63f5cee107ff0f02685 [file] [log] [blame]
Bryce Leedacefc42017-10-10 12:56:02 -07001/*
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
17package com.android.server.am;
18
19import android.annotation.IntDef;
20import android.app.ActivityOptions;
21import android.content.pm.ActivityInfo.WindowLayout;
22import android.graphics.Rect;
23
24import java.lang.annotation.Retention;
25import java.lang.annotation.RetentionPolicy;
26import java.util.ArrayList;
27import java.util.List;
28
29import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_CONTINUE;
30import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_DONE;
31import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_SKIP;
32
33/**
34 * {@link LaunchingBoundsController} calculates the launch bounds by coordinating between registered
35 * {@link LaunchingBoundsPositioner}.
36 */
37class LaunchingBoundsController {
38 private final List<LaunchingBoundsPositioner> mPositioners = new ArrayList<>();
39
40 // Temporary {@link Rect} for calculations. This is kept separate from {@code mTmpCurrent} and
41 // {@code mTmpResult} to prevent clobbering values.
42 private final Rect mTmpRect = new Rect();
43
44 private final Rect mTmpCurrent = new Rect();
45 private final Rect mTmpResult = new Rect();
46
47 /**
48 * Creates a {@link LaunchingBoundsController} with default registered
49 * {@link LaunchingBoundsPositioner}s.
50 */
51 void registerDefaultPositioners(ActivityStackSupervisor supervisor) {
52 // {@link LaunchingTaskPositioner} handles window layout preferences.
53 registerPositioner(new LaunchingTaskPositioner());
54
55 // {@link LaunchingActivityPositioner} is the most specific positioner and thus should be
56 // registered last (applied first) out of the defaults.
57 registerPositioner(new LaunchingActivityPositioner(supervisor));
58 }
59
60 /**
61 * Returns the position calculated by the registered positioners
62 * @param task The {@link TaskRecord} currently being positioned.
63 * @param layout The specified {@link WindowLayout}.
64 * @param activity The {@link ActivityRecord} currently being positioned.
Bryce Leee4ad7452017-10-26 08:44:04 -070065 * @param source The {@link ActivityRecord} from which activity was started from.
Bryce Leedacefc42017-10-10 12:56:02 -070066 * @param options The {@link ActivityOptions} specified for the activity.
67 * @param result The resulting bounds. If no bounds are set, {@link Rect#isEmpty()} will be
Bryce Leee4ad7452017-10-26 08:44:04 -070068 * {@code true}.
Bryce Leedacefc42017-10-10 12:56:02 -070069 */
70 void calculateBounds(TaskRecord task, WindowLayout layout, ActivityRecord activity,
Bryce Leee4ad7452017-10-26 08:44:04 -070071 ActivityRecord source, ActivityOptions options, Rect result) {
Bryce Leedacefc42017-10-10 12:56:02 -070072 result.setEmpty();
73
74 // We start at the last registered {@link LaunchingBoundsPositioner} as this represents
75 // The positioner closest to the product level. Moving back through the list moves closer to
76 // the platform logic.
77 for (int i = mPositioners.size() - 1; i >= 0; --i) {
78 mTmpResult.setEmpty();
79 mTmpCurrent.set(result);
80 final LaunchingBoundsPositioner positioner = mPositioners.get(i);
81
Bryce Leee4ad7452017-10-26 08:44:04 -070082 switch(positioner.onCalculateBounds(task, layout, activity, source, options,
83 mTmpCurrent, mTmpResult)) {
Bryce Leedacefc42017-10-10 12:56:02 -070084 case RESULT_SKIP:
85 // Do not apply any results when we are told to skip
86 continue;
87 case RESULT_DONE:
88 // Set result and return immediately.
89 result.set(mTmpResult);
90 return;
91 case RESULT_CONTINUE:
92 // Set result and continue
93 result.set(mTmpResult);
94 break;
95 }
96 }
97 }
98
99 /**
100 * A convenience method for laying out a task.
101 * @return {@code true} if bounds were set on the task. {@code false} otherwise.
102 */
103 boolean layoutTask(TaskRecord task, WindowLayout layout) {
Bryce Leeb802ea12017-11-15 21:25:03 -0800104 return layoutTask(task, layout, null /*activity*/, null /*source*/, null /*options*/);
105 }
106
107 boolean layoutTask(TaskRecord task, WindowLayout layout, ActivityRecord activity,
108 ActivityRecord source, ActivityOptions options) {
109 calculateBounds(task, layout, activity, source, options, mTmpRect);
Bryce Leedacefc42017-10-10 12:56:02 -0700110
111 if (mTmpRect.isEmpty()) {
112 return false;
113 }
114
115 task.updateOverrideConfiguration(mTmpRect);
116
117 return true;
118 }
119
120 /**
121 * Adds a positioner to participate in future bounds calculation. Note that the last registered
122 * {@link LaunchingBoundsPositioner} will be the first to calculate the bounds.
123 */
124 void registerPositioner(LaunchingBoundsPositioner positioner) {
125 if (mPositioners.contains(positioner)) {
126 return;
127 }
128
129 mPositioners.add(positioner);
130 }
131
132 /**
133 * An interface implemented by those wanting to participate in bounds calculation.
134 */
135 interface LaunchingBoundsPositioner {
136 @Retention(RetentionPolicy.SOURCE)
137 @IntDef({RESULT_SKIP, RESULT_DONE, RESULT_CONTINUE})
138 @interface Result {}
139
140 // Returned when the positioner does not want to influence the bounds calculation
141 int RESULT_SKIP = 0;
142 // Returned when the positioner has changed the bounds and would like its results to be the
143 // final bounds applied.
144 int RESULT_DONE = 1;
145 // Returned when the positioner has changed the bounds but is okay with other positioners
146 // influencing the bounds.
147 int RESULT_CONTINUE = 2;
148
149 /**
150 * Called when asked to calculate bounds.
151 * @param task The {@link TaskRecord} currently being positioned.
152 * @param layout The specified {@link WindowLayout}.
153 * @param activity The {@link ActivityRecord} currently being positioned.
Bryce Leee4ad7452017-10-26 08:44:04 -0700154 * @param source The {@link ActivityRecord} activity was started from.
Bryce Leedacefc42017-10-10 12:56:02 -0700155 * @param options The {@link ActivityOptions} specified for the activity.
156 * @param current The current bounds. This can differ from the initial bounds as it
157 * represents the modified bounds up to this point.
158 * @param result The {@link Rect} which the positioner should return its modified bounds.
159 * Any merging of the current bounds should be already applied to this
160 * value as well before returning.
Bryce Leee4ad7452017-10-26 08:44:04 -0700161 * @return A {@link Result} representing the result of the bounds calculation.
Bryce Leedacefc42017-10-10 12:56:02 -0700162 */
163 @Result
164 int onCalculateBounds(TaskRecord task, WindowLayout layout, ActivityRecord activity,
Bryce Leee4ad7452017-10-26 08:44:04 -0700165 ActivityRecord source, ActivityOptions options, Rect current, Rect result);
Bryce Leedacefc42017-10-10 12:56:02 -0700166 }
167}