blob: bd0ea3d06853e97c08fab4175dea0737b7dce101 [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
84 /**
85 * Contains merged override configuration settings from the top of the hierarchy down to this
86 * particular instance. It is different from {@link #mFullConfiguration} because it starts from
87 * topmost container's override config instead of global config.
88 */
89 private Configuration mMergedOverrideConfiguration = new Configuration();
90
Wale Ogunwale034a8ec2017-09-02 17:14:40 -070091 private ArrayList<ConfigurationContainerListener> mChangeListeners = new ArrayList<>();
92
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -070093 // TODO: Can't have ag/2592611 soon enough!
Wale Ogunwaleda8b8272018-11-29 19:37:37 -080094 private final Configuration mRequestsTmpConfig = new Configuration();
95 private final Configuration mResolvedTmpConfig = new Configuration();
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -070096
Bryce Leef3c6a472017-11-14 14:53:06 -080097 // Used for setting bounds
98 private final Rect mTmpRect = new Rect();
99
100 static final int BOUNDS_CHANGE_NONE = 0;
101 // Return value from {@link setBounds} indicating the position of the override bounds changed.
102 static final int BOUNDS_CHANGE_POSITION = 1;
103 // Return value from {@link setBounds} indicating the size of the override bounds changed.
104 static final int BOUNDS_CHANGE_SIZE = 1 << 1;
105
Evan Roskyddedfd42019-10-04 13:38:38 -0700106 /**
107 * Used as a unique, cross-process identifier for this Container. It also serves a minimal
108 * interface to other processes.
109 */
110 RemoteToken mRemoteToken = null;
Bryce Leef3c6a472017-11-14 14:53:06 -0800111
Andrii Kulian1779e612016-10-12 21:58:25 -0700112 /**
113 * Returns full configuration applied to this configuration container.
114 * This method should be used for getting settings applied in each particular level of the
115 * hierarchy.
116 */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700117 public Configuration getConfiguration() {
Andrii Kulian1779e612016-10-12 21:58:25 -0700118 return mFullConfiguration;
119 }
120
121 /**
122 * Notify that parent config changed and we need to update full configuration.
123 * @see #mFullConfiguration
124 */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700125 public void onConfigurationChanged(Configuration newParentConfig) {
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800126 onConfigurationChanged(newParentConfig, true /*forwardToChildren*/);
127 }
128
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200129 // TODO(root-unify): Consolidate with onConfigurationChanged() method above once unification is
130 // done. This is only currently need during the process of unification where we don't want
131 // configuration forwarded to a child from both parents.
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800132 public void onConfigurationChanged(Configuration newParentConfig, boolean forwardToChildren) {
133 mResolvedTmpConfig.setTo(mResolvedOverrideConfiguration);
Evan Roskydfe3da72018-10-26 17:21:06 -0700134 resolveOverrideConfiguration(newParentConfig);
Andrii Kulian1779e612016-10-12 21:58:25 -0700135 mFullConfiguration.setTo(newParentConfig);
Riddle Hsu7f704b52019-12-10 23:10:45 +0800136 mFullConfiguration.updateFrom(mResolvedOverrideConfiguration);
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800137 if (!mResolvedTmpConfig.equals(mResolvedOverrideConfiguration)) {
Evan Roskydfe3da72018-10-26 17:21:06 -0700138 onMergedOverrideConfigurationChanged();
139 // This depends on the assumption that change-listeners don't do
140 // their own override resolution. This way, dependent hierarchies
141 // can stay properly synced-up with a primary hierarchy's constraints.
142 // Since the hierarchies will be merged, this whole thing will go away
143 // before the assumption will be broken.
144 // Inform listeners of the change.
145 for (int i = mChangeListeners.size() - 1; i >= 0; --i) {
146 mChangeListeners.get(i).onRequestedOverrideConfigurationChanged(
147 mResolvedOverrideConfiguration);
148 }
149 }
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800150 if (forwardToChildren) {
151 for (int i = getChildCount() - 1; i >= 0; --i) {
152 final ConfigurationContainer child = getChildAt(i);
153 child.onConfigurationChanged(mFullConfiguration);
154 }
Andrii Kulian1779e612016-10-12 21:58:25 -0700155 }
156 }
157
Evan Roskydfe3da72018-10-26 17:21:06 -0700158 /**
159 * Resolves the current requested override configuration into
160 * {@link #mResolvedOverrideConfiguration}
161 *
162 * @param newParentConfig The new parent configuration to resolve overrides against.
163 */
164 void resolveOverrideConfiguration(Configuration newParentConfig) {
165 mResolvedOverrideConfiguration.setTo(mRequestedOverrideConfiguration);
166 }
167
168 /** Returns requested override configuration applied to this configuration container. */
169 public Configuration getRequestedOverrideConfiguration() {
170 return mRequestedOverrideConfiguration;
171 }
172
173 /** Returns the resolved override configuration. */
174 Configuration getResolvedOverrideConfiguration() {
175 return mResolvedOverrideConfiguration;
Andrii Kulian1779e612016-10-12 21:58:25 -0700176 }
177
178 /**
179 * Update override configuration and recalculate full config.
Evan Roskydfe3da72018-10-26 17:21:06 -0700180 * @see #mRequestedOverrideConfiguration
Andrii Kulian1779e612016-10-12 21:58:25 -0700181 * @see #mFullConfiguration
182 */
Evan Roskydfe3da72018-10-26 17:21:06 -0700183 public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
Adrian Roos4921ccf2017-09-28 16:54:06 +0200184 // Pre-compute this here, so we don't need to go through the entire Configuration when
185 // writing to proto (which has significant cost if we write a lot of empty configurations).
186 mHasOverrideConfiguration = !Configuration.EMPTY.equals(overrideConfiguration);
Evan Roskydfe3da72018-10-26 17:21:06 -0700187 mRequestedOverrideConfiguration.setTo(overrideConfiguration);
Andrii Kulian1779e612016-10-12 21:58:25 -0700188 // Update full configuration of this container and all its children.
189 final ConfigurationContainer parent = getParent();
190 onConfigurationChanged(parent != null ? parent.getConfiguration() : Configuration.EMPTY);
Andrii Kulian1779e612016-10-12 21:58:25 -0700191 }
192
193 /**
194 * Get merged override configuration from the top of the hierarchy down to this particular
195 * instance. This should be reported to client as override config.
196 */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700197 public Configuration getMergedOverrideConfiguration() {
Andrii Kulian1779e612016-10-12 21:58:25 -0700198 return mMergedOverrideConfiguration;
199 }
200
201 /**
202 * Update merged override configuration based on corresponding parent's config and notify all
203 * its children. If there is no parent, merged override configuration will set equal to current
204 * override config.
205 * @see #mMergedOverrideConfiguration
206 */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700207 void onMergedOverrideConfigurationChanged() {
Andrii Kulian1779e612016-10-12 21:58:25 -0700208 final ConfigurationContainer parent = getParent();
209 if (parent != null) {
210 mMergedOverrideConfiguration.setTo(parent.getMergedOverrideConfiguration());
Evan Roskydfe3da72018-10-26 17:21:06 -0700211 mMergedOverrideConfiguration.updateFrom(mResolvedOverrideConfiguration);
Andrii Kulian1779e612016-10-12 21:58:25 -0700212 } else {
Evan Roskydfe3da72018-10-26 17:21:06 -0700213 mMergedOverrideConfiguration.setTo(mResolvedOverrideConfiguration);
Andrii Kulian1779e612016-10-12 21:58:25 -0700214 }
215 for (int i = getChildCount() - 1; i >= 0; --i) {
216 final ConfigurationContainer child = getChildAt(i);
217 child.onMergedOverrideConfigurationChanged();
218 }
219 }
220
Bryce Leef3c6a472017-11-14 14:53:06 -0800221 /**
Evan Roskydfe3da72018-10-26 17:21:06 -0700222 * Indicates whether this container has not requested any bounds different from its parent. In
223 * this case, it will inherit the bounds of the first ancestor which specifies a bounds subject
224 * to policy constraints.
225 *
226 * @return {@code true} if no explicit bounds have been requested at this container level.
Bryce Leef3c6a472017-11-14 14:53:06 -0800227 * {@code false} otherwise.
228 */
229 public boolean matchParentBounds() {
Evan Roskydfe3da72018-10-26 17:21:06 -0700230 return getRequestedOverrideBounds().isEmpty();
Bryce Leef3c6a472017-11-14 14:53:06 -0800231 }
232
233 /**
Evan Roskydfe3da72018-10-26 17:21:06 -0700234 * Returns whether the bounds specified are considered the same as the existing requested
235 * override bounds. This is either when the two bounds are equal or the requested override
236 * bounds are empty and the specified bounds is null.
Bryce Leef3c6a472017-11-14 14:53:06 -0800237 *
238 * @return {@code true} if the bounds are equivalent, {@code false} otherwise
239 */
Evan Roskydfe3da72018-10-26 17:21:06 -0700240 public boolean equivalentRequestedOverrideBounds(Rect bounds) {
241 return equivalentBounds(getRequestedOverrideBounds(), bounds);
Bryce Leef3c6a472017-11-14 14:53:06 -0800242 }
243
244 /**
245 * Returns whether the two bounds are equal to each other or are a combination of null or empty.
246 */
247 public static boolean equivalentBounds(Rect bounds, Rect other) {
248 return bounds == other
249 || (bounds != null && (bounds.equals(other) || (bounds.isEmpty() && other == null)))
250 || (other != null && other.isEmpty() && bounds == null);
251 }
252
253 /**
254 * Returns the effective bounds of this container, inheriting the first non-empty bounds set in
255 * its ancestral hierarchy, including itself.
256 * @return
257 */
258 public Rect getBounds() {
259 mReturnBounds.set(getConfiguration().windowConfiguration.getBounds());
260 return mReturnBounds;
261 }
262
263 public void getBounds(Rect outBounds) {
264 outBounds.set(getBounds());
265 }
266
267 /**
Adrian Roos7af9d972018-11-30 15:26:27 +0100268 * Sets {@code out} to the top-left corner of the bounds as returned by {@link #getBounds()}.
269 */
270 public void getPosition(Point out) {
271 Rect bounds = getBounds();
272 out.set(bounds.left, bounds.top);
273 }
274
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800275 Rect getResolvedOverrideBounds() {
276 mReturnBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
277 return mReturnBounds;
278 }
279
Adrian Roos7af9d972018-11-30 15:26:27 +0100280 /**
Evan Roskydfe3da72018-10-26 17:21:06 -0700281 * Returns the bounds requested on this container. These may not be the actual bounds the
282 * container ends up with due to policy constraints. The {@link Rect} handed back is
Bryce Leef3c6a472017-11-14 14:53:06 -0800283 * shared for all calls to this method and should not be modified.
284 */
Evan Roskydfe3da72018-10-26 17:21:06 -0700285 public Rect getRequestedOverrideBounds() {
286 mReturnBounds.set(getRequestedOverrideConfiguration().windowConfiguration.getBounds());
Bryce Leef3c6a472017-11-14 14:53:06 -0800287
288 return mReturnBounds;
289 }
290
291 /**
Evan Roskydfe3da72018-10-26 17:21:06 -0700292 * Returns {@code true} if the {@link WindowConfiguration} in the requested override
Bryce Leed92ae482018-01-22 13:56:23 -0800293 * {@link Configuration} specifies bounds.
294 */
295 public boolean hasOverrideBounds() {
Evan Roskydfe3da72018-10-26 17:21:06 -0700296 return !getRequestedOverrideBounds().isEmpty();
Bryce Leed92ae482018-01-22 13:56:23 -0800297 }
298
299 /**
Bryce Leef3c6a472017-11-14 14:53:06 -0800300 * Sets the passed in {@link Rect} to the current bounds.
Evan Roskydfe3da72018-10-26 17:21:06 -0700301 * @see {@link #getRequestedOverrideBounds()}.
Bryce Leef3c6a472017-11-14 14:53:06 -0800302 */
Evan Roskydfe3da72018-10-26 17:21:06 -0700303 public void getRequestedOverrideBounds(Rect outBounds) {
304 outBounds.set(getRequestedOverrideBounds());
Bryce Leef3c6a472017-11-14 14:53:06 -0800305 }
306
307 /**
308 * Sets the bounds at the current hierarchy level, overriding any bounds set on an ancestor.
Evan Roskydfe3da72018-10-26 17:21:06 -0700309 * This value will be reported when {@link #getBounds()} and
310 * {@link #getRequestedOverrideBounds()}. If
Bryce Leef3c6a472017-11-14 14:53:06 -0800311 * an empty {@link Rect} or null is specified, this container will be considered to match its
312 * parent bounds {@see #matchParentBounds} and will inherit bounds from its parent.
313 * @param bounds The bounds defining the container size.
314 * @return a bitmask representing the types of changes made to the bounds.
315 */
316 public int setBounds(Rect bounds) {
Evan Roskydfe3da72018-10-26 17:21:06 -0700317 int boundsChange = diffRequestedOverrideBounds(bounds);
Bryce Leef3c6a472017-11-14 14:53:06 -0800318
319 if (boundsChange == BOUNDS_CHANGE_NONE) {
320 return boundsChange;
321 }
322
323
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800324 mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
325 mRequestsTmpConfig.windowConfiguration.setBounds(bounds);
326 onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
Bryce Leef3c6a472017-11-14 14:53:06 -0800327
328 return boundsChange;
329 }
330
331 public int setBounds(int left, int top, int right, int bottom) {
332 mTmpRect.set(left, top, right, bottom);
333 return setBounds(mTmpRect);
334 }
335
Evan Roskydfe3da72018-10-26 17:21:06 -0700336 int diffRequestedOverrideBounds(Rect bounds) {
337 if (equivalentRequestedOverrideBounds(bounds)) {
Bryce Leef3c6a472017-11-14 14:53:06 -0800338 return BOUNDS_CHANGE_NONE;
339 }
340
341 int boundsChange = BOUNDS_CHANGE_NONE;
342
Evan Roskydfe3da72018-10-26 17:21:06 -0700343 final Rect existingBounds = getRequestedOverrideBounds();
Bryce Leef3c6a472017-11-14 14:53:06 -0800344
345 if (bounds == null || existingBounds.left != bounds.left
346 || existingBounds.top != bounds.top) {
347 boundsChange |= BOUNDS_CHANGE_POSITION;
348 }
349
350 if (bounds == null || existingBounds.width() != bounds.width()
351 || existingBounds.height() != bounds.height()) {
352 boundsChange |= BOUNDS_CHANGE_SIZE;
353 }
354
355 return boundsChange;
356 }
357
Nataniel Borges023ecb52019-01-16 14:15:43 -0800358 boolean hasOverrideConfiguration() {
359 return mHasOverrideConfiguration;
360 }
361
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700362 public WindowConfiguration getWindowConfiguration() {
363 return mFullConfiguration.windowConfiguration;
364 }
365
366 /** Returns the windowing mode the configuration container is currently in. */
367 public int getWindowingMode() {
368 return mFullConfiguration.windowConfiguration.getWindowingMode();
369 }
370
Evan Roskydfe3da72018-10-26 17:21:06 -0700371 /** Returns the windowing mode override that is requested by this container. */
372 public int getRequestedOverrideWindowingMode() {
373 return mRequestedOverrideConfiguration.windowConfiguration.getWindowingMode();
Evan Rosky10475742018-09-05 19:02:48 -0700374 }
375
Evan Roskydfe3da72018-10-26 17:21:06 -0700376 /** Sets the requested windowing mode override for the configuration container. */
Wale Ogunwaleeea34ee92017-08-31 20:07:45 -0700377 public void setWindowingMode(/*@WindowConfiguration.WindowingMode*/ int windowingMode) {
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800378 mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
379 mRequestsTmpConfig.windowConfiguration.setWindowingMode(windowingMode);
380 onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700381 }
382
Kazuki Takise148d00a2018-05-31 15:32:19 +0900383 /** Sets the always on top flag for this configuration container.
384 * When you call this function, make sure that the following functions are called as well to
385 * keep proper z-order.
386 * - {@Link DisplayContent#positionStackAt(POSITION_TOP, TaskStack)};
387 * - {@Link ActivityDisplay#positionChildAtTop(ActivityStack)};
388 * */
389 public void setAlwaysOnTop(boolean alwaysOnTop) {
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800390 mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
391 mRequestsTmpConfig.windowConfiguration.setAlwaysOnTop(alwaysOnTop);
392 onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
Kazuki Takise148d00a2018-05-31 15:32:19 +0900393 }
394
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800395 /** Sets the windowing mode for the configuration container. */
396 void setDisplayWindowingMode(int windowingMode) {
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800397 mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
398 mRequestsTmpConfig.windowConfiguration.setDisplayWindowingMode(windowingMode);
399 onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800400 }
401
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700402 /**
403 * Returns true if this container is currently in multi-window mode. I.e. sharing the screen
404 * with another activity.
405 */
406 public boolean inMultiWindowMode() {
407 /*@WindowConfiguration.WindowingMode*/ int windowingMode =
408 mFullConfiguration.windowConfiguration.getWindowingMode();
409 return windowingMode != WINDOWING_MODE_FULLSCREEN
410 && windowingMode != WINDOWING_MODE_UNDEFINED;
411 }
412
Wale Ogunwale926aade2017-08-29 11:24:37 -0700413 /** Returns true if this container is currently in split-screen windowing mode. */
414 public boolean inSplitScreenWindowingMode() {
Wale Ogunwale5acab1c2017-09-08 07:45:08 -0700415 /*@WindowConfiguration.WindowingMode*/ int windowingMode =
Wale Ogunwale926aade2017-08-29 11:24:37 -0700416 mFullConfiguration.windowConfiguration.getWindowingMode();
417
418 return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
419 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
420 }
421
422 /** Returns true if this container is currently in split-screen secondary windowing mode. */
423 public boolean inSplitScreenSecondaryWindowingMode() {
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_SECONDARY;
428 }
429
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700430 public boolean inSplitScreenPrimaryWindowingMode() {
431 return mFullConfiguration.windowConfiguration.getWindowingMode()
432 == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
433 }
434
Wale Ogunwale926aade2017-08-29 11:24:37 -0700435 /**
436 * Returns true if this container can be put in either
437 * {@link WindowConfiguration#WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} or
438 * {@link WindowConfiguration##WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} windowing modes based on
439 * its current state.
440 */
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700441 public boolean supportsSplitScreenWindowingMode() {
Wale Ogunwale926aade2017-08-29 11:24:37 -0700442 return mFullConfiguration.windowConfiguration.supportSplitScreenWindowingMode();
443 }
444
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700445 public boolean inPinnedWindowingMode() {
446 return mFullConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_PINNED;
447 }
448
449 public boolean inFreeformWindowingMode() {
450 return mFullConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_FREEFORM;
451 }
452
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700453 /** Returns the activity type associated with the the configuration container. */
Wale Ogunwaleeea34ee92017-08-31 20:07:45 -0700454 /*@WindowConfiguration.ActivityType*/
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700455 public int getActivityType() {
456 return mFullConfiguration.windowConfiguration.getActivityType();
457 }
458
459 /** Sets the activity type to associate with the configuration container. */
Wale Ogunwaleeea34ee92017-08-31 20:07:45 -0700460 public void setActivityType(/*@WindowConfiguration.ActivityType*/ int activityType) {
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700461 int currentActivityType = getActivityType();
462 if (currentActivityType == activityType) {
463 return;
464 }
465 if (currentActivityType != ACTIVITY_TYPE_UNDEFINED) {
466 throw new IllegalStateException("Can't change activity type once set: " + this
467 + " activityType=" + activityTypeToString(activityType));
468 }
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800469 mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
470 mRequestsTmpConfig.windowConfiguration.setActivityType(activityType);
471 onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700472 }
473
474 public boolean isActivityTypeHome() {
475 return getActivityType() == ACTIVITY_TYPE_HOME;
476 }
477
478 public boolean isActivityTypeRecents() {
479 return getActivityType() == ACTIVITY_TYPE_RECENTS;
480 }
481
482 public boolean isActivityTypeAssistant() {
483 return getActivityType() == ACTIVITY_TYPE_ASSISTANT;
484 }
485
486 public boolean isActivityTypeStandard() {
487 return getActivityType() == ACTIVITY_TYPE_STANDARD;
488 }
489
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700490 public boolean isActivityTypeStandardOrUndefined() {
491 /*@WindowConfiguration.ActivityType*/ final int activityType = getActivityType();
492 return activityType == ACTIVITY_TYPE_STANDARD || activityType == ACTIVITY_TYPE_UNDEFINED;
493 }
494
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700495 public boolean hasCompatibleActivityType(ConfigurationContainer other) {
Wale Ogunwaleeea34ee92017-08-31 20:07:45 -0700496 /*@WindowConfiguration.ActivityType*/ int thisType = getActivityType();
497 /*@WindowConfiguration.ActivityType*/ int otherType = other.getActivityType();
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700498
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700499 if (thisType == otherType) {
500 return true;
501 }
502 if (thisType == ACTIVITY_TYPE_ASSISTANT) {
503 // Assistant activities are only compatible with themselves...
504 return false;
505 }
506 // Otherwise we are compatible if us or other is not currently defined.
507 return thisType == ACTIVITY_TYPE_UNDEFINED || otherType == ACTIVITY_TYPE_UNDEFINED;
Wale Ogunwale687b4272017-07-27 02:56:23 -0700508 }
509
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700510 /**
511 * Returns true if this container is compatible with the input windowing mode and activity type.
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700512 * The container is compatible:
513 * - If {@param activityType} and {@param windowingMode} match this container activity type and
514 * windowing mode.
515 * - If {@param activityType} is {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} or
516 * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} and this containers activity type is also
517 * standard or undefined and its windowing mode matches {@param windowingMode}.
518 * - If {@param activityType} isn't {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} or
519 * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} or this containers activity type isn't
520 * also standard or undefined and its activity type matches {@param activityType} regardless of
521 * if {@param windowingMode} matches the containers windowing mode.
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700522 */
523 public boolean isCompatible(int windowingMode, int activityType) {
524 final int thisActivityType = getActivityType();
525 final int thisWindowingMode = getWindowingMode();
526 final boolean sameActivityType = thisActivityType == activityType;
527 final boolean sameWindowingMode = thisWindowingMode == windowingMode;
528
529 if (sameActivityType && sameWindowingMode) {
530 return true;
531 }
532
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700533 if ((activityType != ACTIVITY_TYPE_UNDEFINED && activityType != ACTIVITY_TYPE_STANDARD)
534 || !isActivityTypeStandardOrUndefined()) {
Wale Ogunwaleb62139d2017-09-20 15:37:35 -0700535 // Only activity type need to match for non-standard activity types that are defined.
536 return sameActivityType;
537 }
538
539 // Otherwise we are compatible if the windowing mode is the same.
540 return sameWindowingMode;
541 }
542
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200543 void registerConfigurationChangeListener(ConfigurationContainerListener listener) {
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700544 if (mChangeListeners.contains(listener)) {
545 return;
546 }
547 mChangeListeners.add(listener);
Evan Roskydfe3da72018-10-26 17:21:06 -0700548 listener.onRequestedOverrideConfigurationChanged(mResolvedOverrideConfiguration);
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700549 }
550
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200551 void unregisterConfigurationChangeListener(ConfigurationContainerListener listener) {
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700552 mChangeListeners.remove(listener);
553 }
554
Yunfan Chenb29cbfd2019-01-24 17:30:33 +0900555 @VisibleForTesting
556 boolean containsListener(ConfigurationContainerListener listener) {
557 return mChangeListeners.contains(listener);
558 }
559
Andrii Kulian1779e612016-10-12 21:58:25 -0700560 /**
561 * Must be called when new parent for the container was set.
562 */
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200563 void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
Andrii Kulianb94292e2016-10-19 13:30:58 -0700564 // Removing parent usually means that we've detached this entity to destroy it or to attach
565 // to another parent. In both cases we don't need to update the configuration now.
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200566 if (newParent != null) {
Andrii Kulianb94292e2016-10-19 13:30:58 -0700567 // Update full configuration of this container and all its children.
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200568 onConfigurationChanged(newParent.mFullConfiguration);
Andrii Kulianb94292e2016-10-19 13:30:58 -0700569 // Update merged override configuration of this container and all its children.
570 onMergedOverrideConfigurationChanged();
571 }
Andrii Kulian1779e612016-10-12 21:58:25 -0700572 }
573
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700574 /**
575 * Write to a protocol buffer output stream. Protocol buffer message definition is at
Yi Jin6c6e9ca2018-03-20 16:53:35 -0700576 * {@link com.android.server.wm.ConfigurationContainerProto}.
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700577 *
Adrian Roos4921ccf2017-09-28 16:54:06 +0200578 * @param proto Stream to write the ConfigurationContainer object to.
579 * @param fieldId Field Id of the ConfigurationContainer as defined in the parent
580 * message.
Nataniel Borges023ecb52019-01-16 14:15:43 -0800581 * @param logLevel Determines the amount of data to be written to the Protobuf.
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700582 * @hide
583 */
584 @CallSuper
Jeffrey Huangcb782852019-12-05 11:28:11 -0800585 protected void dumpDebug(ProtoOutputStream proto, long fieldId,
Nataniel Borges023ecb52019-01-16 14:15:43 -0800586 @WindowTraceLogLevel int logLevel) {
587 // Critical log level logs only visible elements to mitigate performance overheard
588 if (logLevel != WindowTraceLogLevel.ALL && !mHasOverrideConfiguration) {
589 return;
Adrian Roos4921ccf2017-09-28 16:54:06 +0200590 }
Nataniel Borges023ecb52019-01-16 14:15:43 -0800591
592 final long token = proto.start(fieldId);
Jeffrey Huangcb782852019-12-05 11:28:11 -0800593 mRequestedOverrideConfiguration.dumpDebug(proto, OVERRIDE_CONFIGURATION,
lumark137cc512019-02-18 15:00:47 +0800594 logLevel == WindowTraceLogLevel.CRITICAL);
Nataniel Borges023ecb52019-01-16 14:15:43 -0800595 if (logLevel == WindowTraceLogLevel.ALL) {
Jeffrey Huangcb782852019-12-05 11:28:11 -0800596 mFullConfiguration.dumpDebug(proto, FULL_CONFIGURATION, false /* critical */);
597 mMergedOverrideConfiguration.dumpDebug(proto, MERGED_OVERRIDE_CONFIGURATION,
Nataniel Borges023ecb52019-01-16 14:15:43 -0800598 false /* critical */);
Adrian Roos4921ccf2017-09-28 16:54:06 +0200599 }
600 proto.end(token);
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700601 }
602
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700603 /**
604 * Dumps the names of this container children in the input print writer indenting each
605 * level with the input prefix.
606 */
607 public void dumpChildrenNames(PrintWriter pw, String prefix) {
608 final String childPrefix = prefix + " ";
609 pw.println(getName()
610 + " type=" + activityTypeToString(getActivityType())
Evan Rosky10475742018-09-05 19:02:48 -0700611 + " mode=" + windowingModeToString(getWindowingMode())
Evan Roskydfe3da72018-10-26 17:21:06 -0700612 + " override-mode=" + windowingModeToString(getRequestedOverrideWindowingMode()));
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700613 for (int i = getChildCount() - 1; i >= 0; --i) {
614 final E cc = getChildAt(i);
615 pw.print(childPrefix + "#" + i + " ");
616 cc.dumpChildrenNames(pw, childPrefix);
617 }
618 }
619
620 String getName() {
621 return toString();
622 }
623
Kazuki Takise148d00a2018-05-31 15:32:19 +0900624 public boolean isAlwaysOnTop() {
Robert Carrb1579c82017-09-05 14:54:47 -0700625 return mFullConfiguration.windowConfiguration.isAlwaysOnTop();
626 }
627
Wale Ogunwale1a06f152019-10-11 11:26:30 +0200628 boolean hasChild() {
629 return getChildCount() > 0;
630 }
631
Andrii Kulian1779e612016-10-12 21:58:25 -0700632 abstract protected int getChildCount();
633
634 abstract protected E getChildAt(int index);
635
636 abstract protected ConfigurationContainer getParent();
Evan Roskyddedfd42019-10-04 13:38:38 -0700637
638 // TODO: Consider moving to WindowContainer once hierarchies and Task/Stack are merged.
639 static class RemoteToken extends IWindowContainer.Stub {
640 final WeakReference<ConfigurationContainer> mWeakRef;
641
642 RemoteToken(ConfigurationContainer container) {
643 mWeakRef = new WeakReference<>(container);
644 }
645
646 ConfigurationContainer getContainer() {
647 return mWeakRef.get();
648 }
649
650 static RemoteToken fromBinder(IBinder binder) {
651 return (RemoteToken) binder;
652 }
653
654 @Override
655 public SurfaceControl getLeash() {
656 throw new RuntimeException("Not implemented");
657 }
658
659 @Override
660 public String toString() {
661 StringBuilder sb = new StringBuilder(128);
662 sb.append("RemoteToken{");
663 sb.append(Integer.toHexString(System.identityHashCode(this)));
664 sb.append(' ');
665 sb.append(mWeakRef.get());
666 sb.append('}');
667 return sb.toString();
668 }
669 }
Andrii Kulian1779e612016-10-12 21:58:25 -0700670}