blob: 7df057c86d5aca9a36fc2a5bcfab960e50ba7772 [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;
Yi Jin6c6e9ca2018-03-20 16:53:35 -070032import static com.android.server.wm.ConfigurationContainerProto.FULL_CONFIGURATION;
33import static com.android.server.wm.ConfigurationContainerProto.MERGED_OVERRIDE_CONFIGURATION;
34import static com.android.server.wm.ConfigurationContainerProto.OVERRIDE_CONFIGURATION;
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -070035
Wale Ogunwale0d5609b2017-09-13 05:55:07 -070036import android.annotation.CallSuper;
Wale Ogunwale687b4272017-07-27 02:56:23 -070037import android.app.WindowConfiguration;
Andrii Kulian1779e612016-10-12 21:58:25 -070038import android.content.res.Configuration;
Bryce Leef3c6a472017-11-14 14:53:06 -080039import android.graphics.Rect;
Wale Ogunwale0d5609b2017-09-13 05:55:07 -070040import android.util.proto.ProtoOutputStream;
Andrii Kulian1779e612016-10-12 21:58:25 -070041
Wale Ogunwaleab5de372017-10-18 06:46:31 -070042import java.io.PrintWriter;
Wale Ogunwale034a8ec2017-09-02 17:14:40 -070043import java.util.ArrayList;
44
Andrii Kulian1779e612016-10-12 21:58:25 -070045/**
46 * Contains common logic for classes that have override configurations and are organized in a
47 * hierarchy.
48 */
Wale Ogunwale98d62312017-07-12 09:24:56 -070049public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
Bryce Leef3c6a472017-11-14 14:53:06 -080050 /**
51 * {@link #Rect} returned from {@link #getOverrideBounds()} to prevent original value from being
52 * set directly.
53 */
54 private Rect mReturnBounds = new Rect();
Andrii Kulian1779e612016-10-12 21:58:25 -070055
56 /** Contains override configuration settings applied to this configuration container. */
57 private Configuration mOverrideConfiguration = new Configuration();
58
Adrian Roos4921ccf2017-09-28 16:54:06 +020059 /** True if mOverrideConfiguration is not empty */
60 private boolean mHasOverrideConfiguration;
61
Andrii Kulian1779e612016-10-12 21:58:25 -070062 /**
63 * Contains full configuration applied to this configuration container. Corresponds to full
64 * parent's config with applied {@link #mOverrideConfiguration}.
65 */
66 private Configuration mFullConfiguration = new Configuration();
67
68 /**
69 * Contains merged override configuration settings from the top of the hierarchy down to this
70 * particular instance. It is different from {@link #mFullConfiguration} because it starts from
71 * topmost container's override config instead of global config.
72 */
73 private Configuration mMergedOverrideConfiguration = new Configuration();
74
Wale Ogunwale034a8ec2017-09-02 17:14:40 -070075 private ArrayList<ConfigurationContainerListener> mChangeListeners = new ArrayList<>();
76
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -070077 // TODO: Can't have ag/2592611 soon enough!
78 private final Configuration mTmpConfig = new Configuration();
79
Bryce Leef3c6a472017-11-14 14:53:06 -080080 // Used for setting bounds
81 private final Rect mTmpRect = new Rect();
82
83 static final int BOUNDS_CHANGE_NONE = 0;
84 // Return value from {@link setBounds} indicating the position of the override bounds changed.
85 static final int BOUNDS_CHANGE_POSITION = 1;
86 // Return value from {@link setBounds} indicating the size of the override bounds changed.
87 static final int BOUNDS_CHANGE_SIZE = 1 << 1;
88
89
Andrii Kulian1779e612016-10-12 21:58:25 -070090 /**
91 * Returns full configuration applied to this configuration container.
92 * This method should be used for getting settings applied in each particular level of the
93 * hierarchy.
94 */
Wale Ogunwale98d62312017-07-12 09:24:56 -070095 public Configuration getConfiguration() {
Andrii Kulian1779e612016-10-12 21:58:25 -070096 return mFullConfiguration;
97 }
98
99 /**
100 * Notify that parent config changed and we need to update full configuration.
101 * @see #mFullConfiguration
102 */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700103 public void onConfigurationChanged(Configuration newParentConfig) {
Andrii Kulian1779e612016-10-12 21:58:25 -0700104 mFullConfiguration.setTo(newParentConfig);
105 mFullConfiguration.updateFrom(mOverrideConfiguration);
106 for (int i = getChildCount() - 1; i >= 0; --i) {
107 final ConfigurationContainer child = getChildAt(i);
108 child.onConfigurationChanged(mFullConfiguration);
109 }
110 }
111
112 /** Returns override configuration applied to this configuration container. */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700113 public Configuration getOverrideConfiguration() {
Andrii Kulian1779e612016-10-12 21:58:25 -0700114 return mOverrideConfiguration;
115 }
116
117 /**
118 * Update override configuration and recalculate full config.
119 * @see #mOverrideConfiguration
120 * @see #mFullConfiguration
121 */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700122 public void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
Adrian Roos4921ccf2017-09-28 16:54:06 +0200123 // Pre-compute this here, so we don't need to go through the entire Configuration when
124 // writing to proto (which has significant cost if we write a lot of empty configurations).
125 mHasOverrideConfiguration = !Configuration.EMPTY.equals(overrideConfiguration);
Andrii Kulian1779e612016-10-12 21:58:25 -0700126 mOverrideConfiguration.setTo(overrideConfiguration);
127 // Update full configuration of this container and all its children.
128 final ConfigurationContainer parent = getParent();
129 onConfigurationChanged(parent != null ? parent.getConfiguration() : Configuration.EMPTY);
130 // Update merged override config of this container and all its children.
131 onMergedOverrideConfigurationChanged();
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700132
Garfield Tan20c34562018-04-20 16:19:03 -0700133 // Use the updated override configuration to notify listeners.
134 mTmpConfig.setTo(mOverrideConfiguration);
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700135 // Inform listeners of the change.
136 for (int i = mChangeListeners.size() - 1; i >=0; --i) {
Garfield Tan20c34562018-04-20 16:19:03 -0700137 mChangeListeners.get(i).onOverrideConfigurationChanged(mTmpConfig);
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700138 }
Andrii Kulian1779e612016-10-12 21:58:25 -0700139 }
140
141 /**
142 * Get merged override configuration from the top of the hierarchy down to this particular
143 * instance. This should be reported to client as override config.
144 */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700145 public Configuration getMergedOverrideConfiguration() {
Andrii Kulian1779e612016-10-12 21:58:25 -0700146 return mMergedOverrideConfiguration;
147 }
148
149 /**
150 * Update merged override configuration based on corresponding parent's config and notify all
151 * its children. If there is no parent, merged override configuration will set equal to current
152 * override config.
153 * @see #mMergedOverrideConfiguration
154 */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700155 void onMergedOverrideConfigurationChanged() {
Andrii Kulian1779e612016-10-12 21:58:25 -0700156 final ConfigurationContainer parent = getParent();
157 if (parent != null) {
158 mMergedOverrideConfiguration.setTo(parent.getMergedOverrideConfiguration());
159 mMergedOverrideConfiguration.updateFrom(mOverrideConfiguration);
160 } else {
161 mMergedOverrideConfiguration.setTo(mOverrideConfiguration);
162 }
163 for (int i = getChildCount() - 1; i >= 0; --i) {
164 final ConfigurationContainer child = getChildAt(i);
165 child.onMergedOverrideConfigurationChanged();
166 }
167 }
168
Bryce Leef3c6a472017-11-14 14:53:06 -0800169 /**
170 * Indicates whether this container has not specified any bounds different from its parent. In
171 * this case, it will inherit the bounds of the first ancestor which specifies a bounds.
172 * @return {@code true} if no explicit bounds have been set at this container level.
173 * {@code false} otherwise.
174 */
175 public boolean matchParentBounds() {
176 return getOverrideBounds().isEmpty();
177 }
178
179 /**
180 * Returns whether the bounds specified is considered the same as the existing override bounds.
181 * This is either when the two bounds are equal or the override bounds is empty and the
182 * specified bounds is null.
183 *
184 * @return {@code true} if the bounds are equivalent, {@code false} otherwise
185 */
186 public boolean equivalentOverrideBounds(Rect bounds) {
187 return equivalentBounds(getOverrideBounds(), bounds);
188 }
189
190 /**
191 * Returns whether the two bounds are equal to each other or are a combination of null or empty.
192 */
193 public static boolean equivalentBounds(Rect bounds, Rect other) {
194 return bounds == other
195 || (bounds != null && (bounds.equals(other) || (bounds.isEmpty() && other == null)))
196 || (other != null && other.isEmpty() && bounds == null);
197 }
198
199 /**
200 * Returns the effective bounds of this container, inheriting the first non-empty bounds set in
201 * its ancestral hierarchy, including itself.
202 * @return
203 */
204 public Rect getBounds() {
205 mReturnBounds.set(getConfiguration().windowConfiguration.getBounds());
206 return mReturnBounds;
207 }
208
209 public void getBounds(Rect outBounds) {
210 outBounds.set(getBounds());
211 }
212
213 /**
214 * Returns the current bounds explicitly set on this container. The {@link Rect} handed back is
215 * shared for all calls to this method and should not be modified.
216 */
217 public Rect getOverrideBounds() {
218 mReturnBounds.set(getOverrideConfiguration().windowConfiguration.getBounds());
219
220 return mReturnBounds;
221 }
222
223 /**
Bryce Leed92ae482018-01-22 13:56:23 -0800224 * Returns {@code true} if the {@link WindowConfiguration} in the override
225 * {@link Configuration} specifies bounds.
226 */
227 public boolean hasOverrideBounds() {
228 return !getOverrideBounds().isEmpty();
229 }
230
231 /**
Bryce Leef3c6a472017-11-14 14:53:06 -0800232 * Sets the passed in {@link Rect} to the current bounds.
233 * @see {@link #getOverrideBounds()}.
234 */
235 public void getOverrideBounds(Rect outBounds) {
236 outBounds.set(getOverrideBounds());
237 }
238
239 /**
240 * Sets the bounds at the current hierarchy level, overriding any bounds set on an ancestor.
241 * This value will be reported when {@link #getBounds()} and {@link #getOverrideBounds()}. If
242 * an empty {@link Rect} or null is specified, this container will be considered to match its
243 * parent bounds {@see #matchParentBounds} and will inherit bounds from its parent.
244 * @param bounds The bounds defining the container size.
245 * @return a bitmask representing the types of changes made to the bounds.
246 */
247 public int setBounds(Rect bounds) {
248 int boundsChange = diffOverrideBounds(bounds);
249
250 if (boundsChange == BOUNDS_CHANGE_NONE) {
251 return boundsChange;
252 }
253
254
255 mTmpConfig.setTo(getOverrideConfiguration());
256 mTmpConfig.windowConfiguration.setBounds(bounds);
257 onOverrideConfigurationChanged(mTmpConfig);
258
259 return boundsChange;
260 }
261
262 public int setBounds(int left, int top, int right, int bottom) {
263 mTmpRect.set(left, top, right, bottom);
264 return setBounds(mTmpRect);
265 }
266
267 int diffOverrideBounds(Rect bounds) {
268 if (equivalentOverrideBounds(bounds)) {
269 return BOUNDS_CHANGE_NONE;
270 }
271
272 int boundsChange = BOUNDS_CHANGE_NONE;
273
274 final Rect existingBounds = getOverrideBounds();
275
276 if (bounds == null || existingBounds.left != bounds.left
277 || existingBounds.top != bounds.top) {
278 boundsChange |= BOUNDS_CHANGE_POSITION;
279 }
280
281 if (bounds == null || existingBounds.width() != bounds.width()
282 || existingBounds.height() != bounds.height()) {
283 boundsChange |= BOUNDS_CHANGE_SIZE;
284 }
285
286 return boundsChange;
287 }
288
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700289 public WindowConfiguration getWindowConfiguration() {
290 return mFullConfiguration.windowConfiguration;
291 }
292
293 /** Returns the windowing mode the configuration container is currently in. */
294 public int getWindowingMode() {
295 return mFullConfiguration.windowConfiguration.getWindowingMode();
296 }
297
Wale Ogunwale687b4272017-07-27 02:56:23 -0700298 /** Sets the windowing mode for the configuration container. */
Wale Ogunwaleeea34ee92017-08-31 20:07:45 -0700299 public void setWindowingMode(/*@WindowConfiguration.WindowingMode*/ int windowingMode) {
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700300 mTmpConfig.setTo(getOverrideConfiguration());
301 mTmpConfig.windowConfiguration.setWindowingMode(windowingMode);
302 onOverrideConfigurationChanged(mTmpConfig);
303 }
304
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700305 /**
306 * Returns true if this container is currently in multi-window mode. I.e. sharing the screen
307 * with another activity.
308 */
309 public boolean inMultiWindowMode() {
310 /*@WindowConfiguration.WindowingMode*/ int windowingMode =
311 mFullConfiguration.windowConfiguration.getWindowingMode();
312 return windowingMode != WINDOWING_MODE_FULLSCREEN
313 && windowingMode != WINDOWING_MODE_UNDEFINED;
314 }
315
Wale Ogunwale926aade2017-08-29 11:24:37 -0700316 /** Returns true if this container is currently in split-screen windowing mode. */
317 public boolean inSplitScreenWindowingMode() {
Wale Ogunwale5acab1c2017-09-08 07:45:08 -0700318 /*@WindowConfiguration.WindowingMode*/ int windowingMode =
Wale Ogunwale926aade2017-08-29 11:24:37 -0700319 mFullConfiguration.windowConfiguration.getWindowingMode();
320
321 return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
322 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
323 }
324
325 /** Returns true if this container is currently in split-screen secondary windowing mode. */
326 public boolean inSplitScreenSecondaryWindowingMode() {
Wale Ogunwale5acab1c2017-09-08 07:45:08 -0700327 /*@WindowConfiguration.WindowingMode*/ int windowingMode =
Wale Ogunwale926aade2017-08-29 11:24:37 -0700328 mFullConfiguration.windowConfiguration.getWindowingMode();
329
330 return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
331 }
332
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700333 public boolean inSplitScreenPrimaryWindowingMode() {
334 return mFullConfiguration.windowConfiguration.getWindowingMode()
335 == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
336 }
337
Wale Ogunwale926aade2017-08-29 11:24:37 -0700338 /**
339 * Returns true if this container can be put in either
340 * {@link WindowConfiguration#WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} or
341 * {@link WindowConfiguration##WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} windowing modes based on
342 * its current state.
343 */
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700344 public boolean supportsSplitScreenWindowingMode() {
Wale Ogunwale926aade2017-08-29 11:24:37 -0700345 return mFullConfiguration.windowConfiguration.supportSplitScreenWindowingMode();
346 }
347
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700348 public boolean inPinnedWindowingMode() {
349 return mFullConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_PINNED;
350 }
351
352 public boolean inFreeformWindowingMode() {
353 return mFullConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_FREEFORM;
354 }
355
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700356 /** Returns the activity type associated with the the configuration container. */
Wale Ogunwaleeea34ee92017-08-31 20:07:45 -0700357 /*@WindowConfiguration.ActivityType*/
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700358 public int getActivityType() {
359 return mFullConfiguration.windowConfiguration.getActivityType();
360 }
361
362 /** Sets the activity type to associate with the configuration container. */
Wale Ogunwaleeea34ee92017-08-31 20:07:45 -0700363 public void setActivityType(/*@WindowConfiguration.ActivityType*/ int activityType) {
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700364 int currentActivityType = getActivityType();
365 if (currentActivityType == activityType) {
366 return;
367 }
368 if (currentActivityType != ACTIVITY_TYPE_UNDEFINED) {
369 throw new IllegalStateException("Can't change activity type once set: " + this
370 + " activityType=" + activityTypeToString(activityType));
371 }
372 mTmpConfig.setTo(getOverrideConfiguration());
373 mTmpConfig.windowConfiguration.setActivityType(activityType);
374 onOverrideConfigurationChanged(mTmpConfig);
375 }
376
377 public boolean isActivityTypeHome() {
378 return getActivityType() == ACTIVITY_TYPE_HOME;
379 }
380
381 public boolean isActivityTypeRecents() {
382 return getActivityType() == ACTIVITY_TYPE_RECENTS;
383 }
384
385 public boolean isActivityTypeAssistant() {
386 return getActivityType() == ACTIVITY_TYPE_ASSISTANT;
387 }
388
389 public boolean isActivityTypeStandard() {
390 return getActivityType() == ACTIVITY_TYPE_STANDARD;
391 }
392
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700393 public boolean isActivityTypeStandardOrUndefined() {
394 /*@WindowConfiguration.ActivityType*/ final int activityType = getActivityType();
395 return activityType == ACTIVITY_TYPE_STANDARD || activityType == ACTIVITY_TYPE_UNDEFINED;
396 }
397
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700398 public boolean hasCompatibleActivityType(ConfigurationContainer other) {
Wale Ogunwaleeea34ee92017-08-31 20:07:45 -0700399 /*@WindowConfiguration.ActivityType*/ int thisType = getActivityType();
400 /*@WindowConfiguration.ActivityType*/ int otherType = other.getActivityType();
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700401
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700402 if (thisType == otherType) {
403 return true;
404 }
405 if (thisType == ACTIVITY_TYPE_ASSISTANT) {
406 // Assistant activities are only compatible with themselves...
407 return false;
408 }
409 // Otherwise we are compatible if us or other is not currently defined.
410 return thisType == ACTIVITY_TYPE_UNDEFINED || otherType == ACTIVITY_TYPE_UNDEFINED;
Wale Ogunwale687b4272017-07-27 02:56:23 -0700411 }
412
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700413 /**
414 * Returns true if this container is compatible with the input windowing mode and activity type.
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700415 * The container is compatible:
416 * - If {@param activityType} and {@param windowingMode} match this container activity type and
417 * windowing mode.
418 * - If {@param activityType} is {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} or
419 * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} and this containers activity type is also
420 * standard or undefined and its windowing mode matches {@param windowingMode}.
421 * - If {@param activityType} isn't {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} or
422 * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} or this containers activity type isn't
423 * also standard or undefined and its activity type matches {@param activityType} regardless of
424 * if {@param windowingMode} matches the containers windowing mode.
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700425 */
426 public boolean isCompatible(int windowingMode, int activityType) {
427 final int thisActivityType = getActivityType();
428 final int thisWindowingMode = getWindowingMode();
429 final boolean sameActivityType = thisActivityType == activityType;
430 final boolean sameWindowingMode = thisWindowingMode == windowingMode;
431
432 if (sameActivityType && sameWindowingMode) {
433 return true;
434 }
435
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700436 if ((activityType != ACTIVITY_TYPE_UNDEFINED && activityType != ACTIVITY_TYPE_STANDARD)
437 || !isActivityTypeStandardOrUndefined()) {
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700438 // Only activity type need to match for non-standard activity types that are defined.
439 return sameActivityType;
440 }
441
442 // Otherwise we are compatible if the windowing mode is the same.
443 return sameWindowingMode;
444 }
445
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700446 public void registerConfigurationChangeListener(ConfigurationContainerListener listener) {
447 if (mChangeListeners.contains(listener)) {
448 return;
449 }
450 mChangeListeners.add(listener);
451 listener.onOverrideConfigurationChanged(mOverrideConfiguration);
452 }
453
454 public void unregisterConfigurationChangeListener(ConfigurationContainerListener listener) {
455 mChangeListeners.remove(listener);
456 }
457
Andrii Kulian1779e612016-10-12 21:58:25 -0700458 /**
459 * Must be called when new parent for the container was set.
460 */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700461 protected void onParentChanged() {
Andrii Kulian1779e612016-10-12 21:58:25 -0700462 final ConfigurationContainer parent = getParent();
Andrii Kulianb94292e2016-10-19 13:30:58 -0700463 // Removing parent usually means that we've detached this entity to destroy it or to attach
464 // to another parent. In both cases we don't need to update the configuration now.
465 if (parent != null) {
466 // Update full configuration of this container and all its children.
467 onConfigurationChanged(parent.mFullConfiguration);
468 // Update merged override configuration of this container and all its children.
469 onMergedOverrideConfigurationChanged();
470 }
Andrii Kulian1779e612016-10-12 21:58:25 -0700471 }
472
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700473 /**
474 * Write to a protocol buffer output stream. Protocol buffer message definition is at
Yi Jin6c6e9ca2018-03-20 16:53:35 -0700475 * {@link com.android.server.wm.ConfigurationContainerProto}.
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700476 *
Adrian Roos4921ccf2017-09-28 16:54:06 +0200477 * @param proto Stream to write the ConfigurationContainer object to.
478 * @param fieldId Field Id of the ConfigurationContainer as defined in the parent
479 * message.
480 * @param trim If true, reduce amount of data written.
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700481 * @hide
482 */
483 @CallSuper
Adrian Roos4921ccf2017-09-28 16:54:06 +0200484 public void writeToProto(ProtoOutputStream proto, long fieldId, boolean trim) {
485 final long token = proto.start(fieldId);
486 if (!trim || mHasOverrideConfiguration) {
487 mOverrideConfiguration.writeToProto(proto, OVERRIDE_CONFIGURATION);
488 }
489 if (!trim) {
490 mFullConfiguration.writeToProto(proto, FULL_CONFIGURATION);
491 mMergedOverrideConfiguration.writeToProto(proto, MERGED_OVERRIDE_CONFIGURATION);
492 }
493 proto.end(token);
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700494 }
495
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700496 /**
497 * Dumps the names of this container children in the input print writer indenting each
498 * level with the input prefix.
499 */
500 public void dumpChildrenNames(PrintWriter pw, String prefix) {
501 final String childPrefix = prefix + " ";
502 pw.println(getName()
503 + " type=" + activityTypeToString(getActivityType())
504 + " mode=" + windowingModeToString(getWindowingMode()));
505 for (int i = getChildCount() - 1; i >= 0; --i) {
506 final E cc = getChildAt(i);
507 pw.print(childPrefix + "#" + i + " ");
508 cc.dumpChildrenNames(pw, childPrefix);
509 }
510 }
511
512 String getName() {
513 return toString();
514 }
515
Robert Carrb1579c82017-09-05 14:54:47 -0700516 boolean isAlwaysOnTop() {
517 return mFullConfiguration.windowConfiguration.isAlwaysOnTop();
518 }
519
Andrii Kulian1779e612016-10-12 21:58:25 -0700520 abstract protected int getChildCount();
521
522 abstract protected E getChildAt(int index);
523
524 abstract protected ConfigurationContainer getParent();
525}