1 /*
2  * Copyright (C) 2016 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.am;
18 
19 import android.content.res.Configuration;
20 
21 /**
22  * Contains common logic for classes that have override configurations and are organized in a
23  * hierarchy.
24  */
25 // TODO(b/36505427): Move to wm package and have WindowContainer use this instead of having its own
26 // implementation for merging configuration.
27 abstract class ConfigurationContainer<E extends ConfigurationContainer> {
28 
29     /** Contains override configuration settings applied to this configuration container. */
30     private Configuration mOverrideConfiguration = new Configuration();
31 
32     /**
33      * Contains full configuration applied to this configuration container. Corresponds to full
34      * parent's config with applied {@link #mOverrideConfiguration}.
35      */
36     private Configuration mFullConfiguration = new Configuration();
37 
38     /**
39      * Contains merged override configuration settings from the top of the hierarchy down to this
40      * particular instance. It is different from {@link #mFullConfiguration} because it starts from
41      * topmost container's override config instead of global config.
42      */
43     private Configuration mMergedOverrideConfiguration = new Configuration();
44 
45     /**
46      * Returns full configuration applied to this configuration container.
47      * This method should be used for getting settings applied in each particular level of the
48      * hierarchy.
49      */
getConfiguration()50     Configuration getConfiguration() {
51         return mFullConfiguration;
52     }
53 
54     /**
55      * Notify that parent config changed and we need to update full configuration.
56      * @see #mFullConfiguration
57      */
onConfigurationChanged(Configuration newParentConfig)58     void onConfigurationChanged(Configuration newParentConfig) {
59         mFullConfiguration.setTo(newParentConfig);
60         mFullConfiguration.updateFrom(mOverrideConfiguration);
61         for (int i = getChildCount() - 1; i >= 0; --i) {
62             final ConfigurationContainer child = getChildAt(i);
63             child.onConfigurationChanged(mFullConfiguration);
64         }
65     }
66 
67     /** Returns override configuration applied to this configuration container. */
getOverrideConfiguration()68     Configuration getOverrideConfiguration() {
69         return mOverrideConfiguration;
70     }
71 
72     /**
73      * Update override configuration and recalculate full config.
74      * @see #mOverrideConfiguration
75      * @see #mFullConfiguration
76      */
onOverrideConfigurationChanged(Configuration overrideConfiguration)77     void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
78         mOverrideConfiguration.setTo(overrideConfiguration);
79         // Update full configuration of this container and all its children.
80         final ConfigurationContainer parent = getParent();
81         onConfigurationChanged(parent != null ? parent.getConfiguration() : Configuration.EMPTY);
82         // Update merged override config of this container and all its children.
83         onMergedOverrideConfigurationChanged();
84     }
85 
86     /**
87      * Get merged override configuration from the top of the hierarchy down to this particular
88      * instance. This should be reported to client as override config.
89      */
getMergedOverrideConfiguration()90     Configuration getMergedOverrideConfiguration() {
91         return mMergedOverrideConfiguration;
92     }
93 
94     /**
95      * Update merged override configuration based on corresponding parent's config and notify all
96      * its children. If there is no parent, merged override configuration will set equal to current
97      * override config.
98      * @see #mMergedOverrideConfiguration
99      */
onMergedOverrideConfigurationChanged()100     private void onMergedOverrideConfigurationChanged() {
101         final ConfigurationContainer parent = getParent();
102         if (parent != null) {
103             mMergedOverrideConfiguration.setTo(parent.getMergedOverrideConfiguration());
104             mMergedOverrideConfiguration.updateFrom(mOverrideConfiguration);
105         } else {
106             mMergedOverrideConfiguration.setTo(mOverrideConfiguration);
107         }
108         for (int i = getChildCount() - 1; i >= 0; --i) {
109             final ConfigurationContainer child = getChildAt(i);
110             child.onMergedOverrideConfigurationChanged();
111         }
112     }
113 
114     /**
115      * Must be called when new parent for the container was set.
116      */
onParentChanged()117     void onParentChanged() {
118         final ConfigurationContainer parent = getParent();
119         // Removing parent usually means that we've detached this entity to destroy it or to attach
120         // to another parent. In both cases we don't need to update the configuration now.
121         if (parent != null) {
122             // Update full configuration of this container and all its children.
123             onConfigurationChanged(parent.mFullConfiguration);
124             // Update merged override configuration of this container and all its children.
125             onMergedOverrideConfigurationChanged();
126         }
127     }
128 
getChildCount()129     abstract protected int getChildCount();
130 
getChildAt(int index)131     abstract protected E getChildAt(int index);
132 
getParent()133     abstract protected ConfigurationContainer getParent();
134 }
135