• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.server.wm;
18 
19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
23 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
24 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
25 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
26 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
27 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
28 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
29 import static android.app.WindowConfiguration.activityTypeToString;
30 import static android.app.WindowConfiguration.windowingModeToString;
31 
32 import static com.android.server.wm.ConfigurationContainerProto.FULL_CONFIGURATION;
33 import static com.android.server.wm.ConfigurationContainerProto.MERGED_OVERRIDE_CONFIGURATION;
34 import static com.android.server.wm.ConfigurationContainerProto.OVERRIDE_CONFIGURATION;
35 
36 import android.annotation.CallSuper;
37 import android.app.WindowConfiguration;
38 import android.content.res.Configuration;
39 import android.graphics.Point;
40 import android.graphics.Rect;
41 import android.util.proto.ProtoOutputStream;
42 
43 import com.android.internal.annotations.VisibleForTesting;
44 
45 import java.io.PrintWriter;
46 import java.util.ArrayList;
47 
48 /**
49  * Contains common logic for classes that have override configurations and are organized in a
50  * hierarchy.
51  */
52 public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
53     /**
54      * {@link #Rect} returned from {@link #getRequestedOverrideBounds()} to prevent original value
55      * from being set directly.
56      */
57     private Rect mReturnBounds = new Rect();
58 
59     /**
60      * Contains requested override configuration settings applied to this configuration container.
61      */
62     private Configuration mRequestedOverrideConfiguration = new Configuration();
63 
64     /**
65      * Contains the requested override configuration with parent and policy constraints applied.
66      * This is the set of overrides that gets applied to the full and merged configurations.
67      */
68     private Configuration mResolvedOverrideConfiguration = new Configuration();
69 
70     /** True if mRequestedOverrideConfiguration is not empty */
71     private boolean mHasOverrideConfiguration;
72 
73     /**
74      * Contains full configuration applied to this configuration container. Corresponds to full
75      * parent's config with applied {@link #mResolvedOverrideConfiguration}.
76      */
77     private Configuration mFullConfiguration = new Configuration();
78 
79     /**
80      * Contains merged override configuration settings from the top of the hierarchy down to this
81      * particular instance. It is different from {@link #mFullConfiguration} because it starts from
82      * topmost container's override config instead of global config.
83      */
84     private Configuration mMergedOverrideConfiguration = new Configuration();
85 
86     private ArrayList<ConfigurationContainerListener> mChangeListeners = new ArrayList<>();
87 
88     // TODO: Can't have ag/2592611 soon enough!
89     private final Configuration mRequestsTmpConfig = new Configuration();
90     private final Configuration mResolvedTmpConfig = new Configuration();
91 
92     // Used for setting bounds
93     private final Rect mTmpRect = new Rect();
94 
95     static final int BOUNDS_CHANGE_NONE = 0;
96 
97     /**
98      * Return value from {@link #setBounds(Rect)} indicating the position of the override bounds
99      * changed.
100      */
101     static final int BOUNDS_CHANGE_POSITION = 1;
102 
103     /**
104      * Return value from {@link #setBounds(Rect)} indicating the size of the override bounds
105      * changed.
106      */
107     static final int BOUNDS_CHANGE_SIZE = 1 << 1;
108 
109     /**
110      * Returns full configuration applied to this configuration container.
111      * This method should be used for getting settings applied in each particular level of the
112      * hierarchy.
113      */
getConfiguration()114     public Configuration getConfiguration() {
115         return mFullConfiguration;
116     }
117 
118     /**
119      * Notify that parent config changed and we need to update full configuration.
120      * @see #mFullConfiguration
121      */
onConfigurationChanged(Configuration newParentConfig)122     public void onConfigurationChanged(Configuration newParentConfig) {
123         mResolvedTmpConfig.setTo(mResolvedOverrideConfiguration);
124         resolveOverrideConfiguration(newParentConfig);
125         mFullConfiguration.setTo(newParentConfig);
126         mFullConfiguration.updateFrom(mResolvedOverrideConfiguration);
127         onMergedOverrideConfigurationChanged();
128         if (!mResolvedTmpConfig.equals(mResolvedOverrideConfiguration)) {
129             // This depends on the assumption that change-listeners don't do
130             // their own override resolution. This way, dependent hierarchies
131             // can stay properly synced-up with a primary hierarchy's constraints.
132             // Since the hierarchies will be merged, this whole thing will go away
133             // before the assumption will be broken.
134             // Inform listeners of the change.
135             for (int i = mChangeListeners.size() - 1; i >= 0; --i) {
136                 mChangeListeners.get(i).onRequestedOverrideConfigurationChanged(
137                         mResolvedOverrideConfiguration);
138             }
139         }
140         for (int i = mChangeListeners.size() - 1; i >= 0; --i) {
141             mChangeListeners.get(i).onMergedOverrideConfigurationChanged(
142                     mMergedOverrideConfiguration);
143         }
144         for (int i = getChildCount() - 1; i >= 0; --i) {
145             dispatchConfigurationToChild(getChildAt(i), mFullConfiguration);
146         }
147     }
148 
149     /**
150      * Dispatches the configuration to child when {@link #onConfigurationChanged(Configuration)} is
151      * called. This allows the derived classes to override how to dispatch the configuration.
152      */
dispatchConfigurationToChild(E child, Configuration config)153     void dispatchConfigurationToChild(E child, Configuration config) {
154         child.onConfigurationChanged(config);
155     }
156 
157     /**
158      * Resolves the current requested override configuration into
159      * {@link #mResolvedOverrideConfiguration}
160      *
161      * @param newParentConfig The new parent configuration to resolve overrides against.
162      */
resolveOverrideConfiguration(Configuration newParentConfig)163     void resolveOverrideConfiguration(Configuration newParentConfig) {
164         mResolvedOverrideConfiguration.setTo(mRequestedOverrideConfiguration);
165     }
166 
167     /** Returns {@code true} if requested override override configuration is not empty. */
hasRequestedOverrideConfiguration()168     boolean hasRequestedOverrideConfiguration() {
169         return mHasOverrideConfiguration;
170     }
171 
172     /** Returns requested override configuration applied to this configuration container. */
getRequestedOverrideConfiguration()173     public Configuration getRequestedOverrideConfiguration() {
174         return mRequestedOverrideConfiguration;
175     }
176 
177     /** Returns the resolved override configuration. */
getResolvedOverrideConfiguration()178     Configuration getResolvedOverrideConfiguration() {
179         return mResolvedOverrideConfiguration;
180     }
181 
182     /**
183      * Update override configuration and recalculate full config.
184      * @see #mRequestedOverrideConfiguration
185      * @see #mFullConfiguration
186      */
onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration)187     public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
188         // Pre-compute this here, so we don't need to go through the entire Configuration when
189         // writing to proto (which has significant cost if we write a lot of empty configurations).
190         mHasOverrideConfiguration = !Configuration.EMPTY.equals(overrideConfiguration);
191         mRequestedOverrideConfiguration.setTo(overrideConfiguration);
192         final Rect newBounds = mRequestedOverrideConfiguration.windowConfiguration.getBounds();
193         if (mHasOverrideConfiguration && providesMaxBounds()
194                 && diffRequestedOverrideMaxBounds(newBounds) != BOUNDS_CHANGE_NONE) {
195             mRequestedOverrideConfiguration.windowConfiguration.setMaxBounds(newBounds);
196         }
197         // Update full configuration of this container and all its children.
198         final ConfigurationContainer parent = getParent();
199         onConfigurationChanged(parent != null ? parent.getConfiguration() : Configuration.EMPTY);
200     }
201 
202     /**
203      * Get merged override configuration from the top of the hierarchy down to this particular
204      * instance. This should be reported to client as override config.
205      */
getMergedOverrideConfiguration()206     public Configuration getMergedOverrideConfiguration() {
207         return mMergedOverrideConfiguration;
208     }
209 
210     /**
211      * Update merged override configuration based on corresponding parent's config and notify all
212      * its children. If there is no parent, merged override configuration will set equal to current
213      * override config.
214      * @see #mMergedOverrideConfiguration
215      */
onMergedOverrideConfigurationChanged()216     void onMergedOverrideConfigurationChanged() {
217         final ConfigurationContainer parent = getParent();
218         if (parent != null) {
219             mMergedOverrideConfiguration.setTo(parent.getMergedOverrideConfiguration());
220             mMergedOverrideConfiguration.updateFrom(mResolvedOverrideConfiguration);
221         } else {
222             mMergedOverrideConfiguration.setTo(mResolvedOverrideConfiguration);
223         }
224         for (int i = getChildCount() - 1; i >= 0; --i) {
225             final ConfigurationContainer child = getChildAt(i);
226             child.onMergedOverrideConfigurationChanged();
227         }
228     }
229 
230     /**
231      * Indicates whether this container chooses not to override any bounds from its parent, either
232      * because it doesn't request to override them or the request is dropped during configuration
233      * resolution. In this case, it will inherit the bounds of the first ancestor which specifies a
234      * bounds subject to policy constraints.
235      *
236      * @return {@code true} if this container level uses bounds from parent level. {@code false}
237      *         otherwise.
238      */
matchParentBounds()239     public boolean matchParentBounds() {
240         return getResolvedOverrideBounds().isEmpty();
241     }
242 
243     /**
244      * Returns whether the bounds specified are considered the same as the existing requested
245      * override bounds. This is either when the two bounds are equal or the requested override
246      * bounds are empty and the specified bounds is null.
247      *
248      * @return {@code true} if the bounds are equivalent, {@code false} otherwise
249      */
equivalentRequestedOverrideBounds(Rect bounds)250     public boolean equivalentRequestedOverrideBounds(Rect bounds) {
251         return equivalentBounds(getRequestedOverrideBounds(),  bounds);
252     }
253 
254     /** Similar to {@link #equivalentRequestedOverrideBounds(Rect)}, but compares max bounds. */
equivalentRequestedOverrideMaxBounds(Rect bounds)255     public boolean equivalentRequestedOverrideMaxBounds(Rect bounds) {
256         return equivalentBounds(getRequestedOverrideMaxBounds(),  bounds);
257     }
258 
259     /**
260      * Returns whether the two bounds are equal to each other or are a combination of null or empty.
261      */
equivalentBounds(Rect bounds, Rect other)262     public static boolean equivalentBounds(Rect bounds, Rect other) {
263         return bounds == other
264                 || (bounds != null && (bounds.equals(other) || (bounds.isEmpty() && other == null)))
265                 || (other != null && other.isEmpty() && bounds == null);
266     }
267 
268     /**
269      * Returns the effective bounds of this container, inheriting the first non-empty bounds set in
270      * its ancestral hierarchy, including itself.
271      */
getBounds()272     public Rect getBounds() {
273         mReturnBounds.set(getConfiguration().windowConfiguration.getBounds());
274         return mReturnBounds;
275     }
276 
getBounds(Rect outBounds)277     public void getBounds(Rect outBounds) {
278         outBounds.set(getBounds());
279     }
280 
281     /** Similar to {@link #getBounds()}, but reports the max bounds. */
getMaxBounds()282     public Rect getMaxBounds() {
283         mReturnBounds.set(getConfiguration().windowConfiguration.getMaxBounds());
284         return mReturnBounds;
285     }
286 
287     /**
288      * Sets {@code out} to the top-left corner of the bounds as returned by {@link #getBounds()}.
289      */
getPosition(Point out)290     public void getPosition(Point out) {
291         Rect bounds = getBounds();
292         out.set(bounds.left, bounds.top);
293     }
294 
getResolvedOverrideBounds()295     Rect getResolvedOverrideBounds() {
296         mReturnBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
297         return mReturnBounds;
298     }
299 
300     /**
301      * Returns the bounds requested on this container. These may not be the actual bounds the
302      * container ends up with due to policy constraints. The {@link Rect} handed back is
303      * shared for all calls to this method and should not be modified.
304      */
getRequestedOverrideBounds()305     public Rect getRequestedOverrideBounds() {
306         mReturnBounds.set(getRequestedOverrideConfiguration().windowConfiguration.getBounds());
307 
308         return mReturnBounds;
309     }
310 
311     /** Similar to {@link #getRequestedOverrideBounds()}, but returns the max bounds. */
getRequestedOverrideMaxBounds()312     public Rect getRequestedOverrideMaxBounds() {
313         mReturnBounds.set(getRequestedOverrideConfiguration().windowConfiguration.getMaxBounds());
314 
315         return mReturnBounds;
316     }
317 
318     /**
319      * Returns {@code true} if the {@link WindowConfiguration} in the requested override
320      * {@link Configuration} specifies bounds.
321      */
hasOverrideBounds()322     public boolean hasOverrideBounds() {
323         return !getRequestedOverrideBounds().isEmpty();
324     }
325 
326     /**
327      * Sets the passed in {@link Rect} to the current bounds.
328      * @see #getRequestedOverrideBounds()
329      */
getRequestedOverrideBounds(Rect outBounds)330     public void getRequestedOverrideBounds(Rect outBounds) {
331         outBounds.set(getRequestedOverrideBounds());
332     }
333 
334     /**
335      * Sets the bounds at the current hierarchy level, overriding any bounds set on an ancestor.
336      * This value will be reported when {@link #getBounds()} and
337      * {@link #getRequestedOverrideBounds()}. If
338      * an empty {@link Rect} or null is specified, this container will be considered to match its
339      * parent bounds {@see #matchParentBounds} and will inherit bounds from its parent.
340      *
341      * @param bounds The bounds defining the container size.
342      *
343      * @return a bitmask representing the types of changes made to the bounds.
344      */
setBounds(Rect bounds)345     public int setBounds(Rect bounds) {
346         int boundsChange = diffRequestedOverrideBounds(bounds);
347         final boolean overrideMaxBounds = providesMaxBounds()
348                 && diffRequestedOverrideMaxBounds(bounds) != BOUNDS_CHANGE_NONE;
349 
350         if (boundsChange == BOUNDS_CHANGE_NONE && !overrideMaxBounds) {
351             return boundsChange;
352         }
353 
354         mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
355         mRequestsTmpConfig.windowConfiguration.setBounds(bounds);
356         onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
357 
358         return boundsChange;
359     }
360 
setBounds(int left, int top, int right, int bottom)361     public int setBounds(int left, int top, int right, int bottom) {
362         mTmpRect.set(left, top, right, bottom);
363         return setBounds(mTmpRect);
364     }
365 
366     /**
367      * Returns {@code true} if this {@link ConfigurationContainer} provides the maximum bounds to
368      * its child {@link ConfigurationContainer}s. Returns {@code false}, otherwise.
369      * <p>
370      * The maximum bounds is how large a window can be expanded.
371      * </p>
372      */
providesMaxBounds()373     protected boolean providesMaxBounds() {
374         return false;
375     }
376 
diffRequestedOverrideMaxBounds(Rect bounds)377     int diffRequestedOverrideMaxBounds(Rect bounds) {
378         if (equivalentRequestedOverrideMaxBounds(bounds)) {
379             return BOUNDS_CHANGE_NONE;
380         }
381 
382         int boundsChange = BOUNDS_CHANGE_NONE;
383 
384         final Rect existingBounds = getRequestedOverrideMaxBounds();
385 
386         if (bounds == null || existingBounds.left != bounds.left
387                 || existingBounds.top != bounds.top) {
388             boundsChange |= BOUNDS_CHANGE_POSITION;
389         }
390 
391         if (bounds == null || existingBounds.width() != bounds.width()
392                 || existingBounds.height() != bounds.height()) {
393             boundsChange |= BOUNDS_CHANGE_SIZE;
394         }
395 
396         return boundsChange;
397     }
398 
diffRequestedOverrideBounds(Rect bounds)399     int diffRequestedOverrideBounds(Rect bounds) {
400         if (equivalentRequestedOverrideBounds(bounds)) {
401             return BOUNDS_CHANGE_NONE;
402         }
403 
404         int boundsChange = BOUNDS_CHANGE_NONE;
405 
406         final Rect existingBounds = getRequestedOverrideBounds();
407 
408         if (bounds == null || existingBounds.left != bounds.left
409                 || existingBounds.top != bounds.top) {
410             boundsChange |= BOUNDS_CHANGE_POSITION;
411         }
412 
413         if (bounds == null || existingBounds.width() != bounds.width()
414                 || existingBounds.height() != bounds.height()) {
415             boundsChange |= BOUNDS_CHANGE_SIZE;
416         }
417 
418         return boundsChange;
419     }
420 
getWindowConfiguration()421     public WindowConfiguration getWindowConfiguration() {
422         return mFullConfiguration.windowConfiguration;
423     }
424 
425     /** Returns the windowing mode the configuration container is currently in. */
getWindowingMode()426     public int getWindowingMode() {
427         return mFullConfiguration.windowConfiguration.getWindowingMode();
428     }
429 
430     /** Returns the windowing mode override that is requested by this container. */
getRequestedOverrideWindowingMode()431     public int getRequestedOverrideWindowingMode() {
432         return mRequestedOverrideConfiguration.windowConfiguration.getWindowingMode();
433     }
434 
435     /** Sets the requested windowing mode override for the configuration container. */
setWindowingMode( int windowingMode)436     public void setWindowingMode(/*@WindowConfiguration.WindowingMode*/ int windowingMode) {
437         mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
438         mRequestsTmpConfig.windowConfiguration.setWindowingMode(windowingMode);
439         onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
440     }
441 
442     /** Sets the always on top flag for this configuration container.
443      *  When you call this function, make sure that the following functions are called as well to
444      *  keep proper z-order.
445      *  - {@link TaskDisplayArea#positionChildAt(int POSITION_TOP, Task, boolean)};
446      * */
setAlwaysOnTop(boolean alwaysOnTop)447     public void setAlwaysOnTop(boolean alwaysOnTop) {
448         mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
449         mRequestsTmpConfig.windowConfiguration.setAlwaysOnTop(alwaysOnTop);
450         onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
451     }
452 
453     /** Sets the windowing mode for the configuration container. */
setDisplayWindowingMode(int windowingMode)454     void setDisplayWindowingMode(int windowingMode) {
455         mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
456         mRequestsTmpConfig.windowConfiguration.setDisplayWindowingMode(windowingMode);
457         onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
458     }
459 
460     /**
461      * Returns true if this container is currently in multi-window mode. I.e. sharing the screen
462      * with another activity.
463      */
inMultiWindowMode()464     public boolean inMultiWindowMode() {
465         /*@WindowConfiguration.WindowingMode*/ int windowingMode =
466                 mFullConfiguration.windowConfiguration.getWindowingMode();
467         return WindowConfiguration.inMultiWindowMode(windowingMode);
468     }
469 
470     /** Returns true if this container is currently in split-screen windowing mode. */
inSplitScreenWindowingMode()471     public boolean inSplitScreenWindowingMode() {
472         /*@WindowConfiguration.WindowingMode*/ int windowingMode =
473                 mFullConfiguration.windowConfiguration.getWindowingMode();
474 
475         return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
476                 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
477     }
478 
479     /** Returns true if this container is currently in split-screen secondary windowing mode. */
inSplitScreenSecondaryWindowingMode()480     public boolean inSplitScreenSecondaryWindowingMode() {
481         /*@WindowConfiguration.WindowingMode*/ int windowingMode =
482                 mFullConfiguration.windowConfiguration.getWindowingMode();
483 
484         return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
485     }
486 
inSplitScreenPrimaryWindowingMode()487     public boolean inSplitScreenPrimaryWindowingMode() {
488         return mFullConfiguration.windowConfiguration.getWindowingMode()
489                 == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
490     }
491 
492     /**
493      * Returns true if this container can be put in either
494      * {@link WindowConfiguration#WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} or
495      * {@link WindowConfiguration##WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} windowing modes based on
496      * its current state.
497      */
supportsSplitScreenWindowingMode()498     public boolean supportsSplitScreenWindowingMode() {
499         return mFullConfiguration.windowConfiguration.supportSplitScreenWindowingMode();
500     }
501 
inPinnedWindowingMode()502     public boolean inPinnedWindowingMode() {
503         return mFullConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_PINNED;
504     }
505 
inFreeformWindowingMode()506     public boolean inFreeformWindowingMode() {
507         return mFullConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_FREEFORM;
508     }
509 
510     /** Returns the activity type associated with the the configuration container. */
511     /*@WindowConfiguration.ActivityType*/
getActivityType()512     public int getActivityType() {
513         return mFullConfiguration.windowConfiguration.getActivityType();
514     }
515 
516     /** Sets the activity type to associate with the configuration container. */
setActivityType( int activityType)517     public void setActivityType(/*@WindowConfiguration.ActivityType*/ int activityType) {
518         int currentActivityType = getActivityType();
519         if (currentActivityType == activityType) {
520             return;
521         }
522         if (currentActivityType != ACTIVITY_TYPE_UNDEFINED) {
523             throw new IllegalStateException("Can't change activity type once set: " + this
524                     + " activityType=" + activityTypeToString(activityType));
525         }
526         mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
527         mRequestsTmpConfig.windowConfiguration.setActivityType(activityType);
528         onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
529     }
530 
isActivityTypeHome()531     public boolean isActivityTypeHome() {
532         return getActivityType() == ACTIVITY_TYPE_HOME;
533     }
534 
isActivityTypeRecents()535     public boolean isActivityTypeRecents() {
536         return getActivityType() == ACTIVITY_TYPE_RECENTS;
537     }
538 
isActivityTypeAssistant()539     public boolean isActivityTypeAssistant() {
540         return getActivityType() == ACTIVITY_TYPE_ASSISTANT;
541     }
542 
543     /**
544      * Overrides the night mode applied to this ConfigurationContainer.
545      * @return true if the nightMode has been changed.
546      */
setOverrideNightMode(int nightMode)547     public boolean setOverrideNightMode(int nightMode) {
548         final int currentUiMode = mRequestedOverrideConfiguration.uiMode;
549         final int currentNightMode = currentUiMode & Configuration.UI_MODE_NIGHT_MASK;
550         final int validNightMode = nightMode & Configuration.UI_MODE_NIGHT_MASK;
551         if (currentNightMode == validNightMode) {
552             return false;
553         }
554         mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
555         mRequestsTmpConfig.uiMode = validNightMode
556                 | (currentUiMode & ~Configuration.UI_MODE_NIGHT_MASK);
557         onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
558         return true;
559     }
560 
isActivityTypeDream()561     public boolean isActivityTypeDream() {
562         return getActivityType() == ACTIVITY_TYPE_DREAM;
563     }
564 
isActivityTypeStandard()565     public boolean isActivityTypeStandard() {
566         return getActivityType() == ACTIVITY_TYPE_STANDARD;
567     }
568 
isActivityTypeStandardOrUndefined()569     public boolean isActivityTypeStandardOrUndefined() {
570         /*@WindowConfiguration.ActivityType*/ final int activityType = getActivityType();
571         return activityType == ACTIVITY_TYPE_STANDARD || activityType == ACTIVITY_TYPE_UNDEFINED;
572     }
573 
isCompatibleActivityType(int currentType, int otherType)574     public static boolean isCompatibleActivityType(int currentType, int otherType) {
575         if (currentType == otherType) {
576             return true;
577         }
578         if (currentType == ACTIVITY_TYPE_ASSISTANT) {
579             // Assistant activities are only compatible with themselves...
580             return false;
581         }
582         // Otherwise we are compatible if us or other is not currently defined.
583         return currentType == ACTIVITY_TYPE_UNDEFINED || otherType == ACTIVITY_TYPE_UNDEFINED;
584     }
585 
586     /**
587      * Returns true if this container is compatible with the input windowing mode and activity type.
588      * The container is compatible:
589      * - If {@param activityType} and {@param windowingMode} match this container activity type and
590      * windowing mode.
591      * - If {@param activityType} is {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} or
592      * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} and this containers activity type is also
593      * standard or undefined and its windowing mode matches {@param windowingMode}.
594      * - If {@param activityType} isn't {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} or
595      * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} or this containers activity type isn't
596      * also standard or undefined and its activity type matches {@param activityType} regardless of
597      * if {@param windowingMode} matches the containers windowing mode.
598      */
isCompatible(int windowingMode, int activityType)599     public boolean isCompatible(int windowingMode, int activityType) {
600         final int thisActivityType = getActivityType();
601         final int thisWindowingMode = getWindowingMode();
602         final boolean sameActivityType = thisActivityType == activityType;
603         final boolean sameWindowingMode = thisWindowingMode == windowingMode;
604 
605         if (sameActivityType && sameWindowingMode) {
606             return true;
607         }
608 
609         if ((activityType != ACTIVITY_TYPE_UNDEFINED && activityType != ACTIVITY_TYPE_STANDARD)
610                 || !isActivityTypeStandardOrUndefined()) {
611             // Only activity type need to match for non-standard activity types that are defined.
612             return sameActivityType;
613         }
614 
615         // Otherwise we are compatible if the windowing mode is the same.
616         return sameWindowingMode;
617     }
618 
registerConfigurationChangeListener(ConfigurationContainerListener listener)619     void registerConfigurationChangeListener(ConfigurationContainerListener listener) {
620         if (mChangeListeners.contains(listener)) {
621             return;
622         }
623         mChangeListeners.add(listener);
624         listener.onRequestedOverrideConfigurationChanged(mResolvedOverrideConfiguration);
625         listener.onMergedOverrideConfigurationChanged(mMergedOverrideConfiguration);
626     }
627 
unregisterConfigurationChangeListener(ConfigurationContainerListener listener)628     void unregisterConfigurationChangeListener(ConfigurationContainerListener listener) {
629         mChangeListeners.remove(listener);
630     }
631 
632     @VisibleForTesting
containsListener(ConfigurationContainerListener listener)633     boolean containsListener(ConfigurationContainerListener listener) {
634         return mChangeListeners.contains(listener);
635     }
636 
637     /**
638      * Must be called when new parent for the container was set.
639      */
onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent)640     void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
641         // Removing parent usually means that we've detached this entity to destroy it or to attach
642         // to another parent. In both cases we don't need to update the configuration now.
643         if (newParent != null) {
644             // Update full configuration of this container and all its children.
645             onConfigurationChanged(newParent.mFullConfiguration);
646             // Update merged override configuration of this container and all its children.
647             onMergedOverrideConfigurationChanged();
648         }
649     }
650 
651     /**
652      * Write to a protocol buffer output stream. Protocol buffer message definition is at
653      * {@link com.android.server.wm.ConfigurationContainerProto}.
654      *
655      * @param proto    Stream to write the ConfigurationContainer object to.
656      * @param fieldId  Field Id of the ConfigurationContainer as defined in the parent
657      *                 message.
658      * @param logLevel Determines the amount of data to be written to the Protobuf.
659      * @hide
660      */
661     @CallSuper
dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel)662     protected void dumpDebug(ProtoOutputStream proto, long fieldId,
663             @WindowTraceLogLevel int logLevel) {
664         // Critical log level logs only visible elements to mitigate performance overheard
665         if (logLevel != WindowTraceLogLevel.ALL && !mHasOverrideConfiguration) {
666             return;
667         }
668 
669         final long token = proto.start(fieldId);
670         mRequestedOverrideConfiguration.dumpDebug(proto, OVERRIDE_CONFIGURATION,
671                 logLevel == WindowTraceLogLevel.CRITICAL);
672         if (logLevel == WindowTraceLogLevel.ALL) {
673             mFullConfiguration.dumpDebug(proto, FULL_CONFIGURATION, false /* critical */);
674             mMergedOverrideConfiguration.dumpDebug(proto, MERGED_OVERRIDE_CONFIGURATION,
675                     false /* critical */);
676         }
677         proto.end(token);
678     }
679 
680     /**
681      * Dumps the names of this container children in the input print writer indenting each
682      * level with the input prefix.
683      */
dumpChildrenNames(PrintWriter pw, String prefix)684     public void dumpChildrenNames(PrintWriter pw, String prefix) {
685         final String childPrefix = prefix + " ";
686         pw.println(getName()
687                 + " type=" + activityTypeToString(getActivityType())
688                 + " mode=" + windowingModeToString(getWindowingMode())
689                 + " override-mode=" + windowingModeToString(getRequestedOverrideWindowingMode())
690                 + " requested-bounds=" + getRequestedOverrideBounds().toShortString()
691                 + " bounds=" + getBounds().toShortString());
692         for (int i = getChildCount() - 1; i >= 0; --i) {
693             final E cc = getChildAt(i);
694             pw.print(childPrefix + "#" + i + " ");
695             cc.dumpChildrenNames(pw, childPrefix);
696         }
697     }
698 
getName()699     String getName() {
700         return toString();
701     }
702 
isAlwaysOnTop()703     public boolean isAlwaysOnTop() {
704         return mFullConfiguration.windowConfiguration.isAlwaysOnTop();
705     }
706 
hasChild()707     boolean hasChild() {
708         return getChildCount() > 0;
709     }
710 
getChildCount()711     abstract protected int getChildCount();
712 
getChildAt(int index)713     abstract protected E getChildAt(int index);
714 
getParent()715     abstract protected ConfigurationContainer getParent();
716 
717 }
718