blob: 5c528c7f6047455cff972bf690e1c14b852dab5e [file] [log] [blame]
Andrii Kulian1779e612016-10-12 21:58:25 -07001/*
Wale Ogunwale98d62312017-07-12 09:24:56 -07002 * Copyright (C) 2017 The Android Open Source Project
Andrii Kulian1779e612016-10-12 21:58:25 -07003 *
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 Ogunwale98d62312017-07-12 09:24:56 -070017package com.android.server.wm;
Andrii Kulian1779e612016-10-12 21:58:25 -070018
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -070019import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
20import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
21import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
22import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
23import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
Wale Ogunwale44f036f2017-09-29 05:09:09 -070024import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070025import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
Wale Ogunwale44f036f2017-09-29 05:09:09 -070026import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
Wale Ogunwale926aade2017-08-29 11:24:37 -070027import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
28import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070029import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -070030import static android.app.WindowConfiguration.activityTypeToString;
Wale Ogunwaleab5de372017-10-18 06:46:31 -070031import static android.app.WindowConfiguration.windowingModeToString;
Evan Rosky10475742018-09-05 19:02:48 -070032
Yi Jin6c6e9ca2018-03-20 16:53:35 -070033import static com.android.server.wm.ConfigurationContainerProto.FULL_CONFIGURATION;
34import static com.android.server.wm.ConfigurationContainerProto.MERGED_OVERRIDE_CONFIGURATION;
35import static com.android.server.wm.ConfigurationContainerProto.OVERRIDE_CONFIGURATION;
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -070036
Wale Ogunwale0d5609b2017-09-13 05:55:07 -070037import android.annotation.CallSuper;
Wale Ogunwale687b4272017-07-27 02:56:23 -070038import android.app.WindowConfiguration;
Andrii Kulian1779e612016-10-12 21:58:25 -070039import android.content.res.Configuration;
Adrian Roos7af9d972018-11-30 15:26:27 +010040import android.graphics.Point;
Bryce Leef3c6a472017-11-14 14:53:06 -080041import android.graphics.Rect;
Wale Ogunwale0d5609b2017-09-13 05:55:07 -070042import android.util.proto.ProtoOutputStream;
Andrii Kulian1779e612016-10-12 21:58:25 -070043
Yunfan Chenb29cbfd2019-01-24 17:30:33 +090044import com.android.internal.annotations.VisibleForTesting;
45
Wale Ogunwaleab5de372017-10-18 06:46:31 -070046import java.io.PrintWriter;
Wale Ogunwale034a8ec2017-09-02 17:14:40 -070047import java.util.ArrayList;
48
Andrii Kulian1779e612016-10-12 21:58:25 -070049/**
50 * Contains common logic for classes that have override configurations and are organized in a
51 * hierarchy.
52 */
Wale Ogunwale98d62312017-07-12 09:24:56 -070053public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
Bryce Leef3c6a472017-11-14 14:53:06 -080054 /**
Evan Roskydfe3da72018-10-26 17:21:06 -070055 * {@link #Rect} returned from {@link #getRequestedOverrideBounds()} to prevent original value
56 * from being set directly.
Bryce Leef3c6a472017-11-14 14:53:06 -080057 */
58 private Rect mReturnBounds = new Rect();
Andrii Kulian1779e612016-10-12 21:58:25 -070059
Evan Roskydfe3da72018-10-26 17:21:06 -070060 /**
61 * Contains requested override configuration settings applied to this configuration container.
62 */
63 private Configuration mRequestedOverrideConfiguration = new Configuration();
Andrii Kulian1779e612016-10-12 21:58:25 -070064
Evan Roskydfe3da72018-10-26 17:21:06 -070065 /**
66 * Contains the requested override configuration with parent and policy constraints applied.
67 * This is the set of overrides that gets applied to the full and merged configurations.
68 */
69 private Configuration mResolvedOverrideConfiguration = new Configuration();
70
71 /** True if mRequestedOverrideConfiguration is not empty */
Adrian Roos4921ccf2017-09-28 16:54:06 +020072 private boolean mHasOverrideConfiguration;
73
Andrii Kulian1779e612016-10-12 21:58:25 -070074 /**
75 * Contains full configuration applied to this configuration container. Corresponds to full
Evan Roskydfe3da72018-10-26 17:21:06 -070076 * parent's config with applied {@link #mResolvedOverrideConfiguration}.
Andrii Kulian1779e612016-10-12 21:58:25 -070077 */
78 private Configuration mFullConfiguration = new Configuration();
79
80 /**
81 * Contains merged override configuration settings from the top of the hierarchy down to this
82 * particular instance. It is different from {@link #mFullConfiguration} because it starts from
83 * topmost container's override config instead of global config.
84 */
85 private Configuration mMergedOverrideConfiguration = new Configuration();
86
Wale Ogunwale034a8ec2017-09-02 17:14:40 -070087 private ArrayList<ConfigurationContainerListener> mChangeListeners = new ArrayList<>();
88
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -070089 // TODO: Can't have ag/2592611 soon enough!
90 private final Configuration mTmpConfig = new Configuration();
91
Bryce Leef3c6a472017-11-14 14:53:06 -080092 // Used for setting bounds
93 private final Rect mTmpRect = new Rect();
94
95 static final int BOUNDS_CHANGE_NONE = 0;
96 // Return value from {@link setBounds} indicating the position of the override bounds changed.
97 static final int BOUNDS_CHANGE_POSITION = 1;
98 // Return value from {@link setBounds} indicating the size of the override bounds changed.
99 static final int BOUNDS_CHANGE_SIZE = 1 << 1;
100
101
Andrii Kulian1779e612016-10-12 21:58:25 -0700102 /**
103 * Returns full configuration applied to this configuration container.
104 * This method should be used for getting settings applied in each particular level of the
105 * hierarchy.
106 */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700107 public Configuration getConfiguration() {
Andrii Kulian1779e612016-10-12 21:58:25 -0700108 return mFullConfiguration;
109 }
110
111 /**
112 * Notify that parent config changed and we need to update full configuration.
113 * @see #mFullConfiguration
114 */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700115 public void onConfigurationChanged(Configuration newParentConfig) {
Evan Roskydfe3da72018-10-26 17:21:06 -0700116 mTmpConfig.setTo(mResolvedOverrideConfiguration);
117 resolveOverrideConfiguration(newParentConfig);
Andrii Kulian1779e612016-10-12 21:58:25 -0700118 mFullConfiguration.setTo(newParentConfig);
Evan Roskydfe3da72018-10-26 17:21:06 -0700119 mFullConfiguration.updateFrom(mResolvedOverrideConfiguration);
120 if (!mTmpConfig.equals(mResolvedOverrideConfiguration)) {
121 onMergedOverrideConfigurationChanged();
122 // This depends on the assumption that change-listeners don't do
123 // their own override resolution. This way, dependent hierarchies
124 // can stay properly synced-up with a primary hierarchy's constraints.
125 // Since the hierarchies will be merged, this whole thing will go away
126 // before the assumption will be broken.
127 // Inform listeners of the change.
128 for (int i = mChangeListeners.size() - 1; i >= 0; --i) {
129 mChangeListeners.get(i).onRequestedOverrideConfigurationChanged(
130 mResolvedOverrideConfiguration);
131 }
132 }
Andrii Kulian1779e612016-10-12 21:58:25 -0700133 for (int i = getChildCount() - 1; i >= 0; --i) {
134 final ConfigurationContainer child = getChildAt(i);
135 child.onConfigurationChanged(mFullConfiguration);
136 }
137 }
138
Evan Roskydfe3da72018-10-26 17:21:06 -0700139 /**
140 * Resolves the current requested override configuration into
141 * {@link #mResolvedOverrideConfiguration}
142 *
143 * @param newParentConfig The new parent configuration to resolve overrides against.
144 */
145 void resolveOverrideConfiguration(Configuration newParentConfig) {
146 mResolvedOverrideConfiguration.setTo(mRequestedOverrideConfiguration);
147 }
148
149 /** Returns requested override configuration applied to this configuration container. */
150 public Configuration getRequestedOverrideConfiguration() {
151 return mRequestedOverrideConfiguration;
152 }
153
154 /** Returns the resolved override configuration. */
155 Configuration getResolvedOverrideConfiguration() {
156 return mResolvedOverrideConfiguration;
Andrii Kulian1779e612016-10-12 21:58:25 -0700157 }
158
159 /**
160 * Update override configuration and recalculate full config.
Evan Roskydfe3da72018-10-26 17:21:06 -0700161 * @see #mRequestedOverrideConfiguration
Andrii Kulian1779e612016-10-12 21:58:25 -0700162 * @see #mFullConfiguration
163 */
Evan Roskydfe3da72018-10-26 17:21:06 -0700164 public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
Adrian Roos4921ccf2017-09-28 16:54:06 +0200165 // Pre-compute this here, so we don't need to go through the entire Configuration when
166 // writing to proto (which has significant cost if we write a lot of empty configurations).
167 mHasOverrideConfiguration = !Configuration.EMPTY.equals(overrideConfiguration);
Evan Roskydfe3da72018-10-26 17:21:06 -0700168 mRequestedOverrideConfiguration.setTo(overrideConfiguration);
Andrii Kulian1779e612016-10-12 21:58:25 -0700169 // Update full configuration of this container and all its children.
170 final ConfigurationContainer parent = getParent();
171 onConfigurationChanged(parent != null ? parent.getConfiguration() : Configuration.EMPTY);
Andrii Kulian1779e612016-10-12 21:58:25 -0700172 }
173
174 /**
175 * Get merged override configuration from the top of the hierarchy down to this particular
176 * instance. This should be reported to client as override config.
177 */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700178 public Configuration getMergedOverrideConfiguration() {
Andrii Kulian1779e612016-10-12 21:58:25 -0700179 return mMergedOverrideConfiguration;
180 }
181
182 /**
183 * Update merged override configuration based on corresponding parent's config and notify all
184 * its children. If there is no parent, merged override configuration will set equal to current
185 * override config.
186 * @see #mMergedOverrideConfiguration
187 */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700188 void onMergedOverrideConfigurationChanged() {
Andrii Kulian1779e612016-10-12 21:58:25 -0700189 final ConfigurationContainer parent = getParent();
190 if (parent != null) {
191 mMergedOverrideConfiguration.setTo(parent.getMergedOverrideConfiguration());
Evan Roskydfe3da72018-10-26 17:21:06 -0700192 mMergedOverrideConfiguration.updateFrom(mResolvedOverrideConfiguration);
Andrii Kulian1779e612016-10-12 21:58:25 -0700193 } else {
Evan Roskydfe3da72018-10-26 17:21:06 -0700194 mMergedOverrideConfiguration.setTo(mResolvedOverrideConfiguration);
Andrii Kulian1779e612016-10-12 21:58:25 -0700195 }
196 for (int i = getChildCount() - 1; i >= 0; --i) {
197 final ConfigurationContainer child = getChildAt(i);
198 child.onMergedOverrideConfigurationChanged();
199 }
200 }
201
Bryce Leef3c6a472017-11-14 14:53:06 -0800202 /**
Evan Roskydfe3da72018-10-26 17:21:06 -0700203 * Indicates whether this container has not requested any bounds different from its parent. In
204 * this case, it will inherit the bounds of the first ancestor which specifies a bounds subject
205 * to policy constraints.
206 *
207 * @return {@code true} if no explicit bounds have been requested at this container level.
Bryce Leef3c6a472017-11-14 14:53:06 -0800208 * {@code false} otherwise.
209 */
210 public boolean matchParentBounds() {
Evan Roskydfe3da72018-10-26 17:21:06 -0700211 return getRequestedOverrideBounds().isEmpty();
Bryce Leef3c6a472017-11-14 14:53:06 -0800212 }
213
214 /**
Evan Roskydfe3da72018-10-26 17:21:06 -0700215 * Returns whether the bounds specified are considered the same as the existing requested
216 * override bounds. This is either when the two bounds are equal or the requested override
217 * bounds are empty and the specified bounds is null.
Bryce Leef3c6a472017-11-14 14:53:06 -0800218 *
219 * @return {@code true} if the bounds are equivalent, {@code false} otherwise
220 */
Evan Roskydfe3da72018-10-26 17:21:06 -0700221 public boolean equivalentRequestedOverrideBounds(Rect bounds) {
222 return equivalentBounds(getRequestedOverrideBounds(), bounds);
Bryce Leef3c6a472017-11-14 14:53:06 -0800223 }
224
225 /**
226 * Returns whether the two bounds are equal to each other or are a combination of null or empty.
227 */
228 public static boolean equivalentBounds(Rect bounds, Rect other) {
229 return bounds == other
230 || (bounds != null && (bounds.equals(other) || (bounds.isEmpty() && other == null)))
231 || (other != null && other.isEmpty() && bounds == null);
232 }
233
234 /**
235 * Returns the effective bounds of this container, inheriting the first non-empty bounds set in
236 * its ancestral hierarchy, including itself.
237 * @return
238 */
239 public Rect getBounds() {
240 mReturnBounds.set(getConfiguration().windowConfiguration.getBounds());
241 return mReturnBounds;
242 }
243
244 public void getBounds(Rect outBounds) {
245 outBounds.set(getBounds());
246 }
247
248 /**
Adrian Roos7af9d972018-11-30 15:26:27 +0100249 * Sets {@code out} to the top-left corner of the bounds as returned by {@link #getBounds()}.
250 */
251 public void getPosition(Point out) {
252 Rect bounds = getBounds();
253 out.set(bounds.left, bounds.top);
254 }
255
256 /**
Evan Roskydfe3da72018-10-26 17:21:06 -0700257 * Returns the bounds requested on this container. These may not be the actual bounds the
258 * container ends up with due to policy constraints. The {@link Rect} handed back is
Bryce Leef3c6a472017-11-14 14:53:06 -0800259 * shared for all calls to this method and should not be modified.
260 */
Evan Roskydfe3da72018-10-26 17:21:06 -0700261 public Rect getRequestedOverrideBounds() {
262 mReturnBounds.set(getRequestedOverrideConfiguration().windowConfiguration.getBounds());
Bryce Leef3c6a472017-11-14 14:53:06 -0800263
264 return mReturnBounds;
265 }
266
267 /**
Evan Roskydfe3da72018-10-26 17:21:06 -0700268 * Returns {@code true} if the {@link WindowConfiguration} in the requested override
Bryce Leed92ae482018-01-22 13:56:23 -0800269 * {@link Configuration} specifies bounds.
270 */
271 public boolean hasOverrideBounds() {
Evan Roskydfe3da72018-10-26 17:21:06 -0700272 return !getRequestedOverrideBounds().isEmpty();
Bryce Leed92ae482018-01-22 13:56:23 -0800273 }
274
275 /**
Bryce Leef3c6a472017-11-14 14:53:06 -0800276 * Sets the passed in {@link Rect} to the current bounds.
Evan Roskydfe3da72018-10-26 17:21:06 -0700277 * @see {@link #getRequestedOverrideBounds()}.
Bryce Leef3c6a472017-11-14 14:53:06 -0800278 */
Evan Roskydfe3da72018-10-26 17:21:06 -0700279 public void getRequestedOverrideBounds(Rect outBounds) {
280 outBounds.set(getRequestedOverrideBounds());
Bryce Leef3c6a472017-11-14 14:53:06 -0800281 }
282
283 /**
284 * Sets the bounds at the current hierarchy level, overriding any bounds set on an ancestor.
Evan Roskydfe3da72018-10-26 17:21:06 -0700285 * This value will be reported when {@link #getBounds()} and
286 * {@link #getRequestedOverrideBounds()}. If
Bryce Leef3c6a472017-11-14 14:53:06 -0800287 * an empty {@link Rect} or null is specified, this container will be considered to match its
288 * parent bounds {@see #matchParentBounds} and will inherit bounds from its parent.
289 * @param bounds The bounds defining the container size.
290 * @return a bitmask representing the types of changes made to the bounds.
291 */
292 public int setBounds(Rect bounds) {
Evan Roskydfe3da72018-10-26 17:21:06 -0700293 int boundsChange = diffRequestedOverrideBounds(bounds);
Bryce Leef3c6a472017-11-14 14:53:06 -0800294
295 if (boundsChange == BOUNDS_CHANGE_NONE) {
296 return boundsChange;
297 }
298
299
Evan Roskydfe3da72018-10-26 17:21:06 -0700300 mTmpConfig.setTo(getRequestedOverrideConfiguration());
Bryce Leef3c6a472017-11-14 14:53:06 -0800301 mTmpConfig.windowConfiguration.setBounds(bounds);
Evan Roskydfe3da72018-10-26 17:21:06 -0700302 onRequestedOverrideConfigurationChanged(mTmpConfig);
Bryce Leef3c6a472017-11-14 14:53:06 -0800303
304 return boundsChange;
305 }
306
307 public int setBounds(int left, int top, int right, int bottom) {
308 mTmpRect.set(left, top, right, bottom);
309 return setBounds(mTmpRect);
310 }
311
Evan Roskydfe3da72018-10-26 17:21:06 -0700312 int diffRequestedOverrideBounds(Rect bounds) {
313 if (equivalentRequestedOverrideBounds(bounds)) {
Bryce Leef3c6a472017-11-14 14:53:06 -0800314 return BOUNDS_CHANGE_NONE;
315 }
316
317 int boundsChange = BOUNDS_CHANGE_NONE;
318
Evan Roskydfe3da72018-10-26 17:21:06 -0700319 final Rect existingBounds = getRequestedOverrideBounds();
Bryce Leef3c6a472017-11-14 14:53:06 -0800320
321 if (bounds == null || existingBounds.left != bounds.left
322 || existingBounds.top != bounds.top) {
323 boundsChange |= BOUNDS_CHANGE_POSITION;
324 }
325
326 if (bounds == null || existingBounds.width() != bounds.width()
327 || existingBounds.height() != bounds.height()) {
328 boundsChange |= BOUNDS_CHANGE_SIZE;
329 }
330
331 return boundsChange;
332 }
333
Nataniel Borges023ecb52019-01-16 14:15:43 -0800334 boolean hasOverrideConfiguration() {
335 return mHasOverrideConfiguration;
336 }
337
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700338 public WindowConfiguration getWindowConfiguration() {
339 return mFullConfiguration.windowConfiguration;
340 }
341
342 /** Returns the windowing mode the configuration container is currently in. */
343 public int getWindowingMode() {
344 return mFullConfiguration.windowConfiguration.getWindowingMode();
345 }
346
Evan Roskydfe3da72018-10-26 17:21:06 -0700347 /** Returns the windowing mode override that is requested by this container. */
348 public int getRequestedOverrideWindowingMode() {
349 return mRequestedOverrideConfiguration.windowConfiguration.getWindowingMode();
Evan Rosky10475742018-09-05 19:02:48 -0700350 }
351
Evan Roskydfe3da72018-10-26 17:21:06 -0700352 /** Sets the requested windowing mode override for the configuration container. */
Wale Ogunwaleeea34ee92017-08-31 20:07:45 -0700353 public void setWindowingMode(/*@WindowConfiguration.WindowingMode*/ int windowingMode) {
Evan Roskydfe3da72018-10-26 17:21:06 -0700354 mTmpConfig.setTo(getRequestedOverrideConfiguration());
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700355 mTmpConfig.windowConfiguration.setWindowingMode(windowingMode);
Evan Roskydfe3da72018-10-26 17:21:06 -0700356 onRequestedOverrideConfigurationChanged(mTmpConfig);
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700357 }
358
Kazuki Takise148d00a2018-05-31 15:32:19 +0900359 /** Sets the always on top flag for this configuration container.
360 * When you call this function, make sure that the following functions are called as well to
361 * keep proper z-order.
362 * - {@Link DisplayContent#positionStackAt(POSITION_TOP, TaskStack)};
363 * - {@Link ActivityDisplay#positionChildAtTop(ActivityStack)};
364 * */
365 public void setAlwaysOnTop(boolean alwaysOnTop) {
Evan Roskydfe3da72018-10-26 17:21:06 -0700366 mTmpConfig.setTo(getRequestedOverrideConfiguration());
Kazuki Takise148d00a2018-05-31 15:32:19 +0900367 mTmpConfig.windowConfiguration.setAlwaysOnTop(alwaysOnTop);
Evan Roskydfe3da72018-10-26 17:21:06 -0700368 onRequestedOverrideConfigurationChanged(mTmpConfig);
Kazuki Takise148d00a2018-05-31 15:32:19 +0900369 }
370
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800371 /** Sets the windowing mode for the configuration container. */
372 void setDisplayWindowingMode(int windowingMode) {
Evan Roskydfe3da72018-10-26 17:21:06 -0700373 mTmpConfig.setTo(getRequestedOverrideConfiguration());
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800374 mTmpConfig.windowConfiguration.setDisplayWindowingMode(windowingMode);
Evan Roskydfe3da72018-10-26 17:21:06 -0700375 onRequestedOverrideConfigurationChanged(mTmpConfig);
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800376 }
377
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700378 /**
379 * Returns true if this container is currently in multi-window mode. I.e. sharing the screen
380 * with another activity.
381 */
382 public boolean inMultiWindowMode() {
383 /*@WindowConfiguration.WindowingMode*/ int windowingMode =
384 mFullConfiguration.windowConfiguration.getWindowingMode();
385 return windowingMode != WINDOWING_MODE_FULLSCREEN
386 && windowingMode != WINDOWING_MODE_UNDEFINED;
387 }
388
Wale Ogunwale926aade2017-08-29 11:24:37 -0700389 /** Returns true if this container is currently in split-screen windowing mode. */
390 public boolean inSplitScreenWindowingMode() {
Wale Ogunwale5acab1c2017-09-08 07:45:08 -0700391 /*@WindowConfiguration.WindowingMode*/ int windowingMode =
Wale Ogunwale926aade2017-08-29 11:24:37 -0700392 mFullConfiguration.windowConfiguration.getWindowingMode();
393
394 return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
395 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
396 }
397
398 /** Returns true if this container is currently in split-screen secondary windowing mode. */
399 public boolean inSplitScreenSecondaryWindowingMode() {
Wale Ogunwale5acab1c2017-09-08 07:45:08 -0700400 /*@WindowConfiguration.WindowingMode*/ int windowingMode =
Wale Ogunwale926aade2017-08-29 11:24:37 -0700401 mFullConfiguration.windowConfiguration.getWindowingMode();
402
403 return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
404 }
405
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700406 public boolean inSplitScreenPrimaryWindowingMode() {
407 return mFullConfiguration.windowConfiguration.getWindowingMode()
408 == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
409 }
410
Wale Ogunwale926aade2017-08-29 11:24:37 -0700411 /**
412 * Returns true if this container can be put in either
413 * {@link WindowConfiguration#WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} or
414 * {@link WindowConfiguration##WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} windowing modes based on
415 * its current state.
416 */
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700417 public boolean supportsSplitScreenWindowingMode() {
Wale Ogunwale926aade2017-08-29 11:24:37 -0700418 return mFullConfiguration.windowConfiguration.supportSplitScreenWindowingMode();
419 }
420
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700421 public boolean inPinnedWindowingMode() {
422 return mFullConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_PINNED;
423 }
424
425 public boolean inFreeformWindowingMode() {
426 return mFullConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_FREEFORM;
427 }
428
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700429 /** Returns the activity type associated with the the configuration container. */
Wale Ogunwaleeea34ee92017-08-31 20:07:45 -0700430 /*@WindowConfiguration.ActivityType*/
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700431 public int getActivityType() {
432 return mFullConfiguration.windowConfiguration.getActivityType();
433 }
434
435 /** Sets the activity type to associate with the configuration container. */
Wale Ogunwaleeea34ee92017-08-31 20:07:45 -0700436 public void setActivityType(/*@WindowConfiguration.ActivityType*/ int activityType) {
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700437 int currentActivityType = getActivityType();
438 if (currentActivityType == activityType) {
439 return;
440 }
441 if (currentActivityType != ACTIVITY_TYPE_UNDEFINED) {
442 throw new IllegalStateException("Can't change activity type once set: " + this
443 + " activityType=" + activityTypeToString(activityType));
444 }
Evan Roskydfe3da72018-10-26 17:21:06 -0700445 mTmpConfig.setTo(getRequestedOverrideConfiguration());
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700446 mTmpConfig.windowConfiguration.setActivityType(activityType);
Evan Roskydfe3da72018-10-26 17:21:06 -0700447 onRequestedOverrideConfigurationChanged(mTmpConfig);
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700448 }
449
450 public boolean isActivityTypeHome() {
451 return getActivityType() == ACTIVITY_TYPE_HOME;
452 }
453
454 public boolean isActivityTypeRecents() {
455 return getActivityType() == ACTIVITY_TYPE_RECENTS;
456 }
457
458 public boolean isActivityTypeAssistant() {
459 return getActivityType() == ACTIVITY_TYPE_ASSISTANT;
460 }
461
462 public boolean isActivityTypeStandard() {
463 return getActivityType() == ACTIVITY_TYPE_STANDARD;
464 }
465
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700466 public boolean isActivityTypeStandardOrUndefined() {
467 /*@WindowConfiguration.ActivityType*/ final int activityType = getActivityType();
468 return activityType == ACTIVITY_TYPE_STANDARD || activityType == ACTIVITY_TYPE_UNDEFINED;
469 }
470
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700471 public boolean hasCompatibleActivityType(ConfigurationContainer other) {
Wale Ogunwaleeea34ee92017-08-31 20:07:45 -0700472 /*@WindowConfiguration.ActivityType*/ int thisType = getActivityType();
473 /*@WindowConfiguration.ActivityType*/ int otherType = other.getActivityType();
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700474
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700475 if (thisType == otherType) {
476 return true;
477 }
478 if (thisType == ACTIVITY_TYPE_ASSISTANT) {
479 // Assistant activities are only compatible with themselves...
480 return false;
481 }
482 // Otherwise we are compatible if us or other is not currently defined.
483 return thisType == ACTIVITY_TYPE_UNDEFINED || otherType == ACTIVITY_TYPE_UNDEFINED;
Wale Ogunwale687b4272017-07-27 02:56:23 -0700484 }
485
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700486 /**
487 * Returns true if this container is compatible with the input windowing mode and activity type.
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700488 * The container is compatible:
489 * - If {@param activityType} and {@param windowingMode} match this container activity type and
490 * windowing mode.
491 * - If {@param activityType} is {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} or
492 * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} and this containers activity type is also
493 * standard or undefined and its windowing mode matches {@param windowingMode}.
494 * - If {@param activityType} isn't {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} or
495 * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} or this containers activity type isn't
496 * also standard or undefined and its activity type matches {@param activityType} regardless of
497 * if {@param windowingMode} matches the containers windowing mode.
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700498 */
499 public boolean isCompatible(int windowingMode, int activityType) {
500 final int thisActivityType = getActivityType();
501 final int thisWindowingMode = getWindowingMode();
502 final boolean sameActivityType = thisActivityType == activityType;
503 final boolean sameWindowingMode = thisWindowingMode == windowingMode;
504
505 if (sameActivityType && sameWindowingMode) {
506 return true;
507 }
508
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700509 if ((activityType != ACTIVITY_TYPE_UNDEFINED && activityType != ACTIVITY_TYPE_STANDARD)
510 || !isActivityTypeStandardOrUndefined()) {
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700511 // Only activity type need to match for non-standard activity types that are defined.
512 return sameActivityType;
513 }
514
515 // Otherwise we are compatible if the windowing mode is the same.
516 return sameWindowingMode;
517 }
518
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700519 public void registerConfigurationChangeListener(ConfigurationContainerListener listener) {
520 if (mChangeListeners.contains(listener)) {
521 return;
522 }
523 mChangeListeners.add(listener);
Evan Roskydfe3da72018-10-26 17:21:06 -0700524 listener.onRequestedOverrideConfigurationChanged(mResolvedOverrideConfiguration);
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700525 }
526
527 public void unregisterConfigurationChangeListener(ConfigurationContainerListener listener) {
528 mChangeListeners.remove(listener);
529 }
530
Yunfan Chenb29cbfd2019-01-24 17:30:33 +0900531 @VisibleForTesting
532 boolean containsListener(ConfigurationContainerListener listener) {
533 return mChangeListeners.contains(listener);
534 }
535
Andrii Kulian1779e612016-10-12 21:58:25 -0700536 /**
537 * Must be called when new parent for the container was set.
538 */
Riddle Hsu3a4bb612019-01-31 00:02:22 +0800539 void onParentChanged() {
Andrii Kulian1779e612016-10-12 21:58:25 -0700540 final ConfigurationContainer parent = getParent();
Andrii Kulianb94292e2016-10-19 13:30:58 -0700541 // Removing parent usually means that we've detached this entity to destroy it or to attach
542 // to another parent. In both cases we don't need to update the configuration now.
543 if (parent != null) {
544 // Update full configuration of this container and all its children.
545 onConfigurationChanged(parent.mFullConfiguration);
546 // Update merged override configuration of this container and all its children.
547 onMergedOverrideConfigurationChanged();
548 }
Andrii Kulian1779e612016-10-12 21:58:25 -0700549 }
550
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700551 /**
552 * Write to a protocol buffer output stream. Protocol buffer message definition is at
Yi Jin6c6e9ca2018-03-20 16:53:35 -0700553 * {@link com.android.server.wm.ConfigurationContainerProto}.
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700554 *
Adrian Roos4921ccf2017-09-28 16:54:06 +0200555 * @param proto Stream to write the ConfigurationContainer object to.
556 * @param fieldId Field Id of the ConfigurationContainer as defined in the parent
557 * message.
Nataniel Borges023ecb52019-01-16 14:15:43 -0800558 * @param logLevel Determines the amount of data to be written to the Protobuf.
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700559 * @hide
560 */
561 @CallSuper
Nataniel Borges023ecb52019-01-16 14:15:43 -0800562 protected void writeToProto(ProtoOutputStream proto, long fieldId,
563 @WindowTraceLogLevel int logLevel) {
564 // Critical log level logs only visible elements to mitigate performance overheard
565 if (logLevel != WindowTraceLogLevel.ALL && !mHasOverrideConfiguration) {
566 return;
Adrian Roos4921ccf2017-09-28 16:54:06 +0200567 }
Nataniel Borges023ecb52019-01-16 14:15:43 -0800568
569 final long token = proto.start(fieldId);
570 mRequestedOverrideConfiguration.writeToProto(proto, OVERRIDE_CONFIGURATION,
lumark137cc512019-02-18 15:00:47 +0800571 logLevel == WindowTraceLogLevel.CRITICAL);
Nataniel Borges023ecb52019-01-16 14:15:43 -0800572 if (logLevel == WindowTraceLogLevel.ALL) {
573 mFullConfiguration.writeToProto(proto, FULL_CONFIGURATION, false /* critical */);
574 mMergedOverrideConfiguration.writeToProto(proto, MERGED_OVERRIDE_CONFIGURATION,
575 false /* critical */);
Adrian Roos4921ccf2017-09-28 16:54:06 +0200576 }
577 proto.end(token);
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700578 }
579
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700580 /**
581 * Dumps the names of this container children in the input print writer indenting each
582 * level with the input prefix.
583 */
584 public void dumpChildrenNames(PrintWriter pw, String prefix) {
585 final String childPrefix = prefix + " ";
586 pw.println(getName()
587 + " type=" + activityTypeToString(getActivityType())
Evan Rosky10475742018-09-05 19:02:48 -0700588 + " mode=" + windowingModeToString(getWindowingMode())
Evan Roskydfe3da72018-10-26 17:21:06 -0700589 + " override-mode=" + windowingModeToString(getRequestedOverrideWindowingMode()));
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700590 for (int i = getChildCount() - 1; i >= 0; --i) {
591 final E cc = getChildAt(i);
592 pw.print(childPrefix + "#" + i + " ");
593 cc.dumpChildrenNames(pw, childPrefix);
594 }
595 }
596
597 String getName() {
598 return toString();
599 }
600
Kazuki Takise148d00a2018-05-31 15:32:19 +0900601 public boolean isAlwaysOnTop() {
Robert Carrb1579c82017-09-05 14:54:47 -0700602 return mFullConfiguration.windowConfiguration.isAlwaysOnTop();
603 }
604
Andrii Kulian1779e612016-10-12 21:58:25 -0700605 abstract protected int getChildCount();
606
607 abstract protected E getChildAt(int index);
608
609 abstract protected ConfigurationContainer getParent();
610}