blob: bfa72e0eff78225132a18f35f00b4699091e4133 [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;
Evan Roskyddedfd42019-10-04 13:38:38 -070042import android.os.IBinder;
Wale Ogunwale0d5609b2017-09-13 05:55:07 -070043import android.util.proto.ProtoOutputStream;
Evan Roskyddedfd42019-10-04 13:38:38 -070044import android.view.IWindowContainer;
45import android.view.SurfaceControl;
Andrii Kulian1779e612016-10-12 21:58:25 -070046
Yunfan Chenb29cbfd2019-01-24 17:30:33 +090047import com.android.internal.annotations.VisibleForTesting;
48
Wale Ogunwaleab5de372017-10-18 06:46:31 -070049import java.io.PrintWriter;
Evan Roskyddedfd42019-10-04 13:38:38 -070050import java.lang.ref.WeakReference;
Wale Ogunwale034a8ec2017-09-02 17:14:40 -070051import java.util.ArrayList;
52
Andrii Kulian1779e612016-10-12 21:58:25 -070053/**
54 * Contains common logic for classes that have override configurations and are organized in a
55 * hierarchy.
56 */
Wale Ogunwale98d62312017-07-12 09:24:56 -070057public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
Bryce Leef3c6a472017-11-14 14:53:06 -080058 /**
Evan Roskydfe3da72018-10-26 17:21:06 -070059 * {@link #Rect} returned from {@link #getRequestedOverrideBounds()} to prevent original value
60 * from being set directly.
Bryce Leef3c6a472017-11-14 14:53:06 -080061 */
62 private Rect mReturnBounds = new Rect();
Andrii Kulian1779e612016-10-12 21:58:25 -070063
Evan Roskydfe3da72018-10-26 17:21:06 -070064 /**
65 * Contains requested override configuration settings applied to this configuration container.
66 */
67 private Configuration mRequestedOverrideConfiguration = new Configuration();
Andrii Kulian1779e612016-10-12 21:58:25 -070068
Evan Roskydfe3da72018-10-26 17:21:06 -070069 /**
70 * Contains the requested override configuration with parent and policy constraints applied.
71 * This is the set of overrides that gets applied to the full and merged configurations.
72 */
73 private Configuration mResolvedOverrideConfiguration = new Configuration();
74
75 /** True if mRequestedOverrideConfiguration is not empty */
Adrian Roos4921ccf2017-09-28 16:54:06 +020076 private boolean mHasOverrideConfiguration;
77
Andrii Kulian1779e612016-10-12 21:58:25 -070078 /**
79 * Contains full configuration applied to this configuration container. Corresponds to full
Evan Roskydfe3da72018-10-26 17:21:06 -070080 * parent's config with applied {@link #mResolvedOverrideConfiguration}.
Andrii Kulian1779e612016-10-12 21:58:25 -070081 */
82 private Configuration mFullConfiguration = new Configuration();
83
Riddle Hsuaec55442019-03-12 17:25:35 +080084 /** The bit mask of the last override fields of full configuration. */
85 private int mLastOverrideConfigurationChanges;
86
Andrii Kulian1779e612016-10-12 21:58:25 -070087 /**
88 * Contains merged override configuration settings from the top of the hierarchy down to this
89 * particular instance. It is different from {@link #mFullConfiguration} because it starts from
90 * topmost container's override config instead of global config.
91 */
92 private Configuration mMergedOverrideConfiguration = new Configuration();
93
Wale Ogunwale034a8ec2017-09-02 17:14:40 -070094 private ArrayList<ConfigurationContainerListener> mChangeListeners = new ArrayList<>();
95
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -070096 // TODO: Can't have ag/2592611 soon enough!
Wale Ogunwaleda8b8272018-11-29 19:37:37 -080097 private final Configuration mRequestsTmpConfig = new Configuration();
98 private final Configuration mResolvedTmpConfig = new Configuration();
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -070099
Bryce Leef3c6a472017-11-14 14:53:06 -0800100 // Used for setting bounds
101 private final Rect mTmpRect = new Rect();
102
103 static final int BOUNDS_CHANGE_NONE = 0;
104 // Return value from {@link setBounds} indicating the position of the override bounds changed.
105 static final int BOUNDS_CHANGE_POSITION = 1;
106 // Return value from {@link setBounds} indicating the size of the override bounds changed.
107 static final int BOUNDS_CHANGE_SIZE = 1 << 1;
108
Evan Roskyddedfd42019-10-04 13:38:38 -0700109 /**
110 * Used as a unique, cross-process identifier for this Container. It also serves a minimal
111 * interface to other processes.
112 */
113 RemoteToken mRemoteToken = null;
Bryce Leef3c6a472017-11-14 14:53:06 -0800114
Andrii Kulian1779e612016-10-12 21:58:25 -0700115 /**
116 * Returns full configuration applied to this configuration container.
117 * This method should be used for getting settings applied in each particular level of the
118 * hierarchy.
119 */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700120 public Configuration getConfiguration() {
Andrii Kulian1779e612016-10-12 21:58:25 -0700121 return mFullConfiguration;
122 }
123
Riddle Hsuaec55442019-03-12 17:25:35 +0800124 /** Returns the last changes from applying override configuration. */
125 int getLastOverrideConfigurationChanges() {
126 return mLastOverrideConfigurationChanges;
127 }
128
Andrii Kulian1779e612016-10-12 21:58:25 -0700129 /**
130 * Notify that parent config changed and we need to update full configuration.
131 * @see #mFullConfiguration
132 */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700133 public void onConfigurationChanged(Configuration newParentConfig) {
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800134 onConfigurationChanged(newParentConfig, true /*forwardToChildren*/);
135 }
136
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200137 // TODO(root-unify): Consolidate with onConfigurationChanged() method above once unification is
138 // done. This is only currently need during the process of unification where we don't want
139 // configuration forwarded to a child from both parents.
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800140 public void onConfigurationChanged(Configuration newParentConfig, boolean forwardToChildren) {
141 mResolvedTmpConfig.setTo(mResolvedOverrideConfiguration);
Evan Roskydfe3da72018-10-26 17:21:06 -0700142 resolveOverrideConfiguration(newParentConfig);
Andrii Kulian1779e612016-10-12 21:58:25 -0700143 mFullConfiguration.setTo(newParentConfig);
Riddle Hsuaec55442019-03-12 17:25:35 +0800144 mLastOverrideConfigurationChanges =
145 mFullConfiguration.updateFrom(mResolvedOverrideConfiguration);
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800146 if (!mResolvedTmpConfig.equals(mResolvedOverrideConfiguration)) {
Evan Roskydfe3da72018-10-26 17:21:06 -0700147 onMergedOverrideConfigurationChanged();
148 // This depends on the assumption that change-listeners don't do
149 // their own override resolution. This way, dependent hierarchies
150 // can stay properly synced-up with a primary hierarchy's constraints.
151 // Since the hierarchies will be merged, this whole thing will go away
152 // before the assumption will be broken.
153 // Inform listeners of the change.
154 for (int i = mChangeListeners.size() - 1; i >= 0; --i) {
155 mChangeListeners.get(i).onRequestedOverrideConfigurationChanged(
156 mResolvedOverrideConfiguration);
157 }
158 }
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800159 if (forwardToChildren) {
160 for (int i = getChildCount() - 1; i >= 0; --i) {
161 final ConfigurationContainer child = getChildAt(i);
162 child.onConfigurationChanged(mFullConfiguration);
163 }
Andrii Kulian1779e612016-10-12 21:58:25 -0700164 }
165 }
166
Evan Roskydfe3da72018-10-26 17:21:06 -0700167 /**
168 * Resolves the current requested override configuration into
169 * {@link #mResolvedOverrideConfiguration}
170 *
171 * @param newParentConfig The new parent configuration to resolve overrides against.
172 */
173 void resolveOverrideConfiguration(Configuration newParentConfig) {
174 mResolvedOverrideConfiguration.setTo(mRequestedOverrideConfiguration);
175 }
176
177 /** Returns requested override configuration applied to this configuration container. */
178 public Configuration getRequestedOverrideConfiguration() {
179 return mRequestedOverrideConfiguration;
180 }
181
182 /** Returns the resolved override configuration. */
183 Configuration getResolvedOverrideConfiguration() {
184 return mResolvedOverrideConfiguration;
Andrii Kulian1779e612016-10-12 21:58:25 -0700185 }
186
187 /**
188 * Update override configuration and recalculate full config.
Evan Roskydfe3da72018-10-26 17:21:06 -0700189 * @see #mRequestedOverrideConfiguration
Andrii Kulian1779e612016-10-12 21:58:25 -0700190 * @see #mFullConfiguration
191 */
Evan Roskydfe3da72018-10-26 17:21:06 -0700192 public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
Adrian Roos4921ccf2017-09-28 16:54:06 +0200193 // Pre-compute this here, so we don't need to go through the entire Configuration when
194 // writing to proto (which has significant cost if we write a lot of empty configurations).
195 mHasOverrideConfiguration = !Configuration.EMPTY.equals(overrideConfiguration);
Evan Roskydfe3da72018-10-26 17:21:06 -0700196 mRequestedOverrideConfiguration.setTo(overrideConfiguration);
Andrii Kulian1779e612016-10-12 21:58:25 -0700197 // Update full configuration of this container and all its children.
198 final ConfigurationContainer parent = getParent();
199 onConfigurationChanged(parent != null ? parent.getConfiguration() : Configuration.EMPTY);
Andrii Kulian1779e612016-10-12 21:58:25 -0700200 }
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 */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700206 public Configuration getMergedOverrideConfiguration() {
Andrii Kulian1779e612016-10-12 21:58:25 -0700207 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 */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700216 void onMergedOverrideConfigurationChanged() {
Andrii Kulian1779e612016-10-12 21:58:25 -0700217 final ConfigurationContainer parent = getParent();
218 if (parent != null) {
219 mMergedOverrideConfiguration.setTo(parent.getMergedOverrideConfiguration());
Evan Roskydfe3da72018-10-26 17:21:06 -0700220 mMergedOverrideConfiguration.updateFrom(mResolvedOverrideConfiguration);
Andrii Kulian1779e612016-10-12 21:58:25 -0700221 } else {
Evan Roskydfe3da72018-10-26 17:21:06 -0700222 mMergedOverrideConfiguration.setTo(mResolvedOverrideConfiguration);
Andrii Kulian1779e612016-10-12 21:58:25 -0700223 }
224 for (int i = getChildCount() - 1; i >= 0; --i) {
225 final ConfigurationContainer child = getChildAt(i);
226 child.onMergedOverrideConfigurationChanged();
227 }
228 }
229
Bryce Leef3c6a472017-11-14 14:53:06 -0800230 /**
Evan Roskydfe3da72018-10-26 17:21:06 -0700231 * Indicates whether this container has not requested any bounds different from its parent. In
232 * this case, it will inherit the bounds of the first ancestor which specifies a bounds subject
233 * to policy constraints.
234 *
235 * @return {@code true} if no explicit bounds have been requested at this container level.
Bryce Leef3c6a472017-11-14 14:53:06 -0800236 * {@code false} otherwise.
237 */
238 public boolean matchParentBounds() {
Evan Roskydfe3da72018-10-26 17:21:06 -0700239 return getRequestedOverrideBounds().isEmpty();
Bryce Leef3c6a472017-11-14 14:53:06 -0800240 }
241
242 /**
Evan Roskydfe3da72018-10-26 17:21:06 -0700243 * Returns whether the bounds specified are considered the same as the existing requested
244 * override bounds. This is either when the two bounds are equal or the requested override
245 * bounds are empty and the specified bounds is null.
Bryce Leef3c6a472017-11-14 14:53:06 -0800246 *
247 * @return {@code true} if the bounds are equivalent, {@code false} otherwise
248 */
Evan Roskydfe3da72018-10-26 17:21:06 -0700249 public boolean equivalentRequestedOverrideBounds(Rect bounds) {
250 return equivalentBounds(getRequestedOverrideBounds(), bounds);
Bryce Leef3c6a472017-11-14 14:53:06 -0800251 }
252
253 /**
254 * Returns whether the two bounds are equal to each other or are a combination of null or empty.
255 */
256 public static boolean equivalentBounds(Rect bounds, Rect other) {
257 return bounds == other
258 || (bounds != null && (bounds.equals(other) || (bounds.isEmpty() && other == null)))
259 || (other != null && other.isEmpty() && bounds == null);
260 }
261
262 /**
263 * Returns the effective bounds of this container, inheriting the first non-empty bounds set in
264 * its ancestral hierarchy, including itself.
265 * @return
266 */
267 public Rect getBounds() {
268 mReturnBounds.set(getConfiguration().windowConfiguration.getBounds());
269 return mReturnBounds;
270 }
271
272 public void getBounds(Rect outBounds) {
273 outBounds.set(getBounds());
274 }
275
276 /**
Adrian Roos7af9d972018-11-30 15:26:27 +0100277 * Sets {@code out} to the top-left corner of the bounds as returned by {@link #getBounds()}.
278 */
279 public void getPosition(Point out) {
280 Rect bounds = getBounds();
281 out.set(bounds.left, bounds.top);
282 }
283
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800284 Rect getResolvedOverrideBounds() {
285 mReturnBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
286 return mReturnBounds;
287 }
288
Adrian Roos7af9d972018-11-30 15:26:27 +0100289 /**
Evan Roskydfe3da72018-10-26 17:21:06 -0700290 * Returns the bounds requested on this container. These may not be the actual bounds the
291 * container ends up with due to policy constraints. The {@link Rect} handed back is
Bryce Leef3c6a472017-11-14 14:53:06 -0800292 * shared for all calls to this method and should not be modified.
293 */
Evan Roskydfe3da72018-10-26 17:21:06 -0700294 public Rect getRequestedOverrideBounds() {
295 mReturnBounds.set(getRequestedOverrideConfiguration().windowConfiguration.getBounds());
Bryce Leef3c6a472017-11-14 14:53:06 -0800296
297 return mReturnBounds;
298 }
299
300 /**
Evan Roskydfe3da72018-10-26 17:21:06 -0700301 * Returns {@code true} if the {@link WindowConfiguration} in the requested override
Bryce Leed92ae482018-01-22 13:56:23 -0800302 * {@link Configuration} specifies bounds.
303 */
304 public boolean hasOverrideBounds() {
Evan Roskydfe3da72018-10-26 17:21:06 -0700305 return !getRequestedOverrideBounds().isEmpty();
Bryce Leed92ae482018-01-22 13:56:23 -0800306 }
307
308 /**
Bryce Leef3c6a472017-11-14 14:53:06 -0800309 * Sets the passed in {@link Rect} to the current bounds.
Evan Roskydfe3da72018-10-26 17:21:06 -0700310 * @see {@link #getRequestedOverrideBounds()}.
Bryce Leef3c6a472017-11-14 14:53:06 -0800311 */
Evan Roskydfe3da72018-10-26 17:21:06 -0700312 public void getRequestedOverrideBounds(Rect outBounds) {
313 outBounds.set(getRequestedOverrideBounds());
Bryce Leef3c6a472017-11-14 14:53:06 -0800314 }
315
316 /**
317 * Sets the bounds at the current hierarchy level, overriding any bounds set on an ancestor.
Evan Roskydfe3da72018-10-26 17:21:06 -0700318 * This value will be reported when {@link #getBounds()} and
319 * {@link #getRequestedOverrideBounds()}. If
Bryce Leef3c6a472017-11-14 14:53:06 -0800320 * an empty {@link Rect} or null is specified, this container will be considered to match its
321 * parent bounds {@see #matchParentBounds} and will inherit bounds from its parent.
322 * @param bounds The bounds defining the container size.
323 * @return a bitmask representing the types of changes made to the bounds.
324 */
325 public int setBounds(Rect bounds) {
Evan Roskydfe3da72018-10-26 17:21:06 -0700326 int boundsChange = diffRequestedOverrideBounds(bounds);
Bryce Leef3c6a472017-11-14 14:53:06 -0800327
328 if (boundsChange == BOUNDS_CHANGE_NONE) {
329 return boundsChange;
330 }
331
332
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800333 mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
334 mRequestsTmpConfig.windowConfiguration.setBounds(bounds);
335 onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
Bryce Leef3c6a472017-11-14 14:53:06 -0800336
337 return boundsChange;
338 }
339
340 public int setBounds(int left, int top, int right, int bottom) {
341 mTmpRect.set(left, top, right, bottom);
342 return setBounds(mTmpRect);
343 }
344
Evan Roskydfe3da72018-10-26 17:21:06 -0700345 int diffRequestedOverrideBounds(Rect bounds) {
346 if (equivalentRequestedOverrideBounds(bounds)) {
Bryce Leef3c6a472017-11-14 14:53:06 -0800347 return BOUNDS_CHANGE_NONE;
348 }
349
350 int boundsChange = BOUNDS_CHANGE_NONE;
351
Evan Roskydfe3da72018-10-26 17:21:06 -0700352 final Rect existingBounds = getRequestedOverrideBounds();
Bryce Leef3c6a472017-11-14 14:53:06 -0800353
354 if (bounds == null || existingBounds.left != bounds.left
355 || existingBounds.top != bounds.top) {
356 boundsChange |= BOUNDS_CHANGE_POSITION;
357 }
358
359 if (bounds == null || existingBounds.width() != bounds.width()
360 || existingBounds.height() != bounds.height()) {
361 boundsChange |= BOUNDS_CHANGE_SIZE;
362 }
363
364 return boundsChange;
365 }
366
Nataniel Borges023ecb52019-01-16 14:15:43 -0800367 boolean hasOverrideConfiguration() {
368 return mHasOverrideConfiguration;
369 }
370
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700371 public WindowConfiguration getWindowConfiguration() {
372 return mFullConfiguration.windowConfiguration;
373 }
374
375 /** Returns the windowing mode the configuration container is currently in. */
376 public int getWindowingMode() {
377 return mFullConfiguration.windowConfiguration.getWindowingMode();
378 }
379
Evan Roskydfe3da72018-10-26 17:21:06 -0700380 /** Returns the windowing mode override that is requested by this container. */
381 public int getRequestedOverrideWindowingMode() {
382 return mRequestedOverrideConfiguration.windowConfiguration.getWindowingMode();
Evan Rosky10475742018-09-05 19:02:48 -0700383 }
384
Evan Roskydfe3da72018-10-26 17:21:06 -0700385 /** Sets the requested windowing mode override for the configuration container. */
Wale Ogunwaleeea34ee92017-08-31 20:07:45 -0700386 public void setWindowingMode(/*@WindowConfiguration.WindowingMode*/ int windowingMode) {
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800387 mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
388 mRequestsTmpConfig.windowConfiguration.setWindowingMode(windowingMode);
389 onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700390 }
391
Kazuki Takise148d00a2018-05-31 15:32:19 +0900392 /** Sets the always on top flag for this configuration container.
393 * When you call this function, make sure that the following functions are called as well to
394 * keep proper z-order.
395 * - {@Link DisplayContent#positionStackAt(POSITION_TOP, TaskStack)};
396 * - {@Link ActivityDisplay#positionChildAtTop(ActivityStack)};
397 * */
398 public void setAlwaysOnTop(boolean alwaysOnTop) {
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800399 mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
400 mRequestsTmpConfig.windowConfiguration.setAlwaysOnTop(alwaysOnTop);
401 onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
Kazuki Takise148d00a2018-05-31 15:32:19 +0900402 }
403
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800404 /** Sets the windowing mode for the configuration container. */
405 void setDisplayWindowingMode(int windowingMode) {
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800406 mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
407 mRequestsTmpConfig.windowConfiguration.setDisplayWindowingMode(windowingMode);
408 onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800409 }
410
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700411 /**
412 * Returns true if this container is currently in multi-window mode. I.e. sharing the screen
413 * with another activity.
414 */
415 public boolean inMultiWindowMode() {
416 /*@WindowConfiguration.WindowingMode*/ int windowingMode =
417 mFullConfiguration.windowConfiguration.getWindowingMode();
418 return windowingMode != WINDOWING_MODE_FULLSCREEN
419 && windowingMode != WINDOWING_MODE_UNDEFINED;
420 }
421
Wale Ogunwale926aade2017-08-29 11:24:37 -0700422 /** Returns true if this container is currently in split-screen windowing mode. */
423 public boolean inSplitScreenWindowingMode() {
Wale Ogunwale5acab1c2017-09-08 07:45:08 -0700424 /*@WindowConfiguration.WindowingMode*/ int windowingMode =
Wale Ogunwale926aade2017-08-29 11:24:37 -0700425 mFullConfiguration.windowConfiguration.getWindowingMode();
426
427 return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
428 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
429 }
430
431 /** Returns true if this container is currently in split-screen secondary windowing mode. */
432 public boolean inSplitScreenSecondaryWindowingMode() {
Wale Ogunwale5acab1c2017-09-08 07:45:08 -0700433 /*@WindowConfiguration.WindowingMode*/ int windowingMode =
Wale Ogunwale926aade2017-08-29 11:24:37 -0700434 mFullConfiguration.windowConfiguration.getWindowingMode();
435
436 return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
437 }
438
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700439 public boolean inSplitScreenPrimaryWindowingMode() {
440 return mFullConfiguration.windowConfiguration.getWindowingMode()
441 == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
442 }
443
Wale Ogunwale926aade2017-08-29 11:24:37 -0700444 /**
445 * Returns true if this container can be put in either
446 * {@link WindowConfiguration#WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} or
447 * {@link WindowConfiguration##WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} windowing modes based on
448 * its current state.
449 */
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700450 public boolean supportsSplitScreenWindowingMode() {
Wale Ogunwale926aade2017-08-29 11:24:37 -0700451 return mFullConfiguration.windowConfiguration.supportSplitScreenWindowingMode();
452 }
453
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700454 public boolean inPinnedWindowingMode() {
455 return mFullConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_PINNED;
456 }
457
458 public boolean inFreeformWindowingMode() {
459 return mFullConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_FREEFORM;
460 }
461
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700462 /** Returns the activity type associated with the the configuration container. */
Wale Ogunwaleeea34ee92017-08-31 20:07:45 -0700463 /*@WindowConfiguration.ActivityType*/
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700464 public int getActivityType() {
465 return mFullConfiguration.windowConfiguration.getActivityType();
466 }
467
468 /** Sets the activity type to associate with the configuration container. */
Wale Ogunwaleeea34ee92017-08-31 20:07:45 -0700469 public void setActivityType(/*@WindowConfiguration.ActivityType*/ int activityType) {
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700470 int currentActivityType = getActivityType();
471 if (currentActivityType == activityType) {
472 return;
473 }
474 if (currentActivityType != ACTIVITY_TYPE_UNDEFINED) {
475 throw new IllegalStateException("Can't change activity type once set: " + this
476 + " activityType=" + activityTypeToString(activityType));
477 }
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800478 mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
479 mRequestsTmpConfig.windowConfiguration.setActivityType(activityType);
480 onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700481 }
482
483 public boolean isActivityTypeHome() {
484 return getActivityType() == ACTIVITY_TYPE_HOME;
485 }
486
487 public boolean isActivityTypeRecents() {
488 return getActivityType() == ACTIVITY_TYPE_RECENTS;
489 }
490
491 public boolean isActivityTypeAssistant() {
492 return getActivityType() == ACTIVITY_TYPE_ASSISTANT;
493 }
494
495 public boolean isActivityTypeStandard() {
496 return getActivityType() == ACTIVITY_TYPE_STANDARD;
497 }
498
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700499 public boolean isActivityTypeStandardOrUndefined() {
500 /*@WindowConfiguration.ActivityType*/ final int activityType = getActivityType();
501 return activityType == ACTIVITY_TYPE_STANDARD || activityType == ACTIVITY_TYPE_UNDEFINED;
502 }
503
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700504 public boolean hasCompatibleActivityType(ConfigurationContainer other) {
Wale Ogunwaleeea34ee92017-08-31 20:07:45 -0700505 /*@WindowConfiguration.ActivityType*/ int thisType = getActivityType();
506 /*@WindowConfiguration.ActivityType*/ int otherType = other.getActivityType();
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700507
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700508 if (thisType == otherType) {
509 return true;
510 }
511 if (thisType == ACTIVITY_TYPE_ASSISTANT) {
512 // Assistant activities are only compatible with themselves...
513 return false;
514 }
515 // Otherwise we are compatible if us or other is not currently defined.
516 return thisType == ACTIVITY_TYPE_UNDEFINED || otherType == ACTIVITY_TYPE_UNDEFINED;
Wale Ogunwale687b4272017-07-27 02:56:23 -0700517 }
518
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700519 /**
520 * Returns true if this container is compatible with the input windowing mode and activity type.
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700521 * The container is compatible:
522 * - If {@param activityType} and {@param windowingMode} match this container activity type and
523 * windowing mode.
524 * - If {@param activityType} is {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} or
525 * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} and this containers activity type is also
526 * standard or undefined and its windowing mode matches {@param windowingMode}.
527 * - If {@param activityType} isn't {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} or
528 * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} or this containers activity type isn't
529 * also standard or undefined and its activity type matches {@param activityType} regardless of
530 * if {@param windowingMode} matches the containers windowing mode.
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700531 */
532 public boolean isCompatible(int windowingMode, int activityType) {
533 final int thisActivityType = getActivityType();
534 final int thisWindowingMode = getWindowingMode();
535 final boolean sameActivityType = thisActivityType == activityType;
536 final boolean sameWindowingMode = thisWindowingMode == windowingMode;
537
538 if (sameActivityType && sameWindowingMode) {
539 return true;
540 }
541
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700542 if ((activityType != ACTIVITY_TYPE_UNDEFINED && activityType != ACTIVITY_TYPE_STANDARD)
543 || !isActivityTypeStandardOrUndefined()) {
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700544 // Only activity type need to match for non-standard activity types that are defined.
545 return sameActivityType;
546 }
547
548 // Otherwise we are compatible if the windowing mode is the same.
549 return sameWindowingMode;
550 }
551
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200552 void registerConfigurationChangeListener(ConfigurationContainerListener listener) {
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700553 if (mChangeListeners.contains(listener)) {
554 return;
555 }
556 mChangeListeners.add(listener);
Evan Roskydfe3da72018-10-26 17:21:06 -0700557 listener.onRequestedOverrideConfigurationChanged(mResolvedOverrideConfiguration);
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700558 }
559
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200560 void unregisterConfigurationChangeListener(ConfigurationContainerListener listener) {
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700561 mChangeListeners.remove(listener);
562 }
563
Yunfan Chenb29cbfd2019-01-24 17:30:33 +0900564 @VisibleForTesting
565 boolean containsListener(ConfigurationContainerListener listener) {
566 return mChangeListeners.contains(listener);
567 }
568
Andrii Kulian1779e612016-10-12 21:58:25 -0700569 /**
570 * Must be called when new parent for the container was set.
571 */
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200572 void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
Andrii Kulianb94292e2016-10-19 13:30:58 -0700573 // Removing parent usually means that we've detached this entity to destroy it or to attach
574 // to another parent. In both cases we don't need to update the configuration now.
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200575 if (newParent != null) {
Andrii Kulianb94292e2016-10-19 13:30:58 -0700576 // Update full configuration of this container and all its children.
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200577 onConfigurationChanged(newParent.mFullConfiguration);
Andrii Kulianb94292e2016-10-19 13:30:58 -0700578 // Update merged override configuration of this container and all its children.
579 onMergedOverrideConfigurationChanged();
580 }
Andrii Kulian1779e612016-10-12 21:58:25 -0700581 }
582
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700583 /**
584 * Write to a protocol buffer output stream. Protocol buffer message definition is at
Yi Jin6c6e9ca2018-03-20 16:53:35 -0700585 * {@link com.android.server.wm.ConfigurationContainerProto}.
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700586 *
Adrian Roos4921ccf2017-09-28 16:54:06 +0200587 * @param proto Stream to write the ConfigurationContainer object to.
588 * @param fieldId Field Id of the ConfigurationContainer as defined in the parent
589 * message.
Nataniel Borges023ecb52019-01-16 14:15:43 -0800590 * @param logLevel Determines the amount of data to be written to the Protobuf.
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700591 * @hide
592 */
593 @CallSuper
Jeffrey Huangcb782852019-12-05 11:28:11 -0800594 protected void dumpDebug(ProtoOutputStream proto, long fieldId,
Nataniel Borges023ecb52019-01-16 14:15:43 -0800595 @WindowTraceLogLevel int logLevel) {
596 // Critical log level logs only visible elements to mitigate performance overheard
597 if (logLevel != WindowTraceLogLevel.ALL && !mHasOverrideConfiguration) {
598 return;
Adrian Roos4921ccf2017-09-28 16:54:06 +0200599 }
Nataniel Borges023ecb52019-01-16 14:15:43 -0800600
601 final long token = proto.start(fieldId);
Jeffrey Huangcb782852019-12-05 11:28:11 -0800602 mRequestedOverrideConfiguration.dumpDebug(proto, OVERRIDE_CONFIGURATION,
lumark137cc512019-02-18 15:00:47 +0800603 logLevel == WindowTraceLogLevel.CRITICAL);
Nataniel Borges023ecb52019-01-16 14:15:43 -0800604 if (logLevel == WindowTraceLogLevel.ALL) {
Jeffrey Huangcb782852019-12-05 11:28:11 -0800605 mFullConfiguration.dumpDebug(proto, FULL_CONFIGURATION, false /* critical */);
606 mMergedOverrideConfiguration.dumpDebug(proto, MERGED_OVERRIDE_CONFIGURATION,
Nataniel Borges023ecb52019-01-16 14:15:43 -0800607 false /* critical */);
Adrian Roos4921ccf2017-09-28 16:54:06 +0200608 }
609 proto.end(token);
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700610 }
611
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700612 /**
613 * Dumps the names of this container children in the input print writer indenting each
614 * level with the input prefix.
615 */
616 public void dumpChildrenNames(PrintWriter pw, String prefix) {
617 final String childPrefix = prefix + " ";
618 pw.println(getName()
619 + " type=" + activityTypeToString(getActivityType())
Evan Rosky10475742018-09-05 19:02:48 -0700620 + " mode=" + windowingModeToString(getWindowingMode())
Evan Roskydfe3da72018-10-26 17:21:06 -0700621 + " override-mode=" + windowingModeToString(getRequestedOverrideWindowingMode()));
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700622 for (int i = getChildCount() - 1; i >= 0; --i) {
623 final E cc = getChildAt(i);
624 pw.print(childPrefix + "#" + i + " ");
625 cc.dumpChildrenNames(pw, childPrefix);
626 }
627 }
628
629 String getName() {
630 return toString();
631 }
632
Kazuki Takise148d00a2018-05-31 15:32:19 +0900633 public boolean isAlwaysOnTop() {
Robert Carrb1579c82017-09-05 14:54:47 -0700634 return mFullConfiguration.windowConfiguration.isAlwaysOnTop();
635 }
636
Wale Ogunwale1a06f152019-10-11 11:26:30 +0200637 boolean hasChild() {
638 return getChildCount() > 0;
639 }
640
Andrii Kulian1779e612016-10-12 21:58:25 -0700641 abstract protected int getChildCount();
642
643 abstract protected E getChildAt(int index);
644
645 abstract protected ConfigurationContainer getParent();
Evan Roskyddedfd42019-10-04 13:38:38 -0700646
647 // TODO: Consider moving to WindowContainer once hierarchies and Task/Stack are merged.
648 static class RemoteToken extends IWindowContainer.Stub {
649 final WeakReference<ConfigurationContainer> mWeakRef;
650
651 RemoteToken(ConfigurationContainer container) {
652 mWeakRef = new WeakReference<>(container);
653 }
654
655 ConfigurationContainer getContainer() {
656 return mWeakRef.get();
657 }
658
659 static RemoteToken fromBinder(IBinder binder) {
660 return (RemoteToken) binder;
661 }
662
663 @Override
664 public SurfaceControl getLeash() {
665 throw new RuntimeException("Not implemented");
666 }
667
668 @Override
669 public String toString() {
670 StringBuilder sb = new StringBuilder(128);
671 sb.append("RemoteToken{");
672 sb.append(Integer.toHexString(System.identityHashCode(this)));
673 sb.append(' ');
674 sb.append(mWeakRef.get());
675 sb.append('}');
676 return sb.toString();
677 }
678 }
Andrii Kulian1779e612016-10-12 21:58:25 -0700679}