blob: affc8b9283fbc593e8d9e49c28e154e7ae2c577e [file] [log] [blame]
Wale Ogunwale822e5122017-07-26 06:02:24 -07001/*
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
17package android.app;
18
Wale Ogunwale6cbbc9a2017-09-06 19:01:03 -070019import static android.app.ActivityThread.isSystem;
Wale Ogunwale0d5609b2017-09-13 05:55:07 -070020import static android.app.WindowConfigurationProto.ACTIVITY_TYPE;
21import static android.app.WindowConfigurationProto.APP_BOUNDS;
Adrian Roos5f8b52c2018-11-28 16:31:55 +010022import static android.app.WindowConfigurationProto.BOUNDS;
Wale Ogunwale0d5609b2017-09-13 05:55:07 -070023import static android.app.WindowConfigurationProto.WINDOWING_MODE;
Evan Roskye747c3e2018-10-30 20:06:41 -070024import static android.view.Surface.rotationToString;
Wale Ogunwale6cbbc9a2017-09-06 19:01:03 -070025
Wale Ogunwale822e5122017-07-26 06:02:24 -070026import android.annotation.IntDef;
27import android.annotation.NonNull;
Steven Timotiuse597ca12017-09-05 15:46:29 -070028import android.annotation.TestApi;
Wale Ogunwale822e5122017-07-26 06:02:24 -070029import android.content.res.Configuration;
30import android.graphics.Rect;
31import android.os.Parcel;
32import android.os.Parcelable;
Michael Wachenschwanzc8c26362018-09-07 14:59:25 -070033import android.util.proto.ProtoInputStream;
Wale Ogunwale0d5609b2017-09-13 05:55:07 -070034import android.util.proto.ProtoOutputStream;
Michael Wachenschwanzc8c26362018-09-07 14:59:25 -070035import android.util.proto.WireTypeMismatchException;
Wale Ogunwale822e5122017-07-26 06:02:24 -070036import android.view.DisplayInfo;
37
Michael Wachenschwanzc8c26362018-09-07 14:59:25 -070038import java.io.IOException;
39
Wale Ogunwale822e5122017-07-26 06:02:24 -070040/**
41 * Class that contains windowing configuration/state for other objects that contain windows directly
42 * or indirectly. E.g. Activities, Task, Displays, ...
43 * The test class is {@link com.android.server.wm.WindowConfigurationTests} which must be kept
44 * up-to-date and ran anytime changes are made to this class.
45 * @hide
46 */
Steven Timotiuse597ca12017-09-05 15:46:29 -070047@TestApi
Wale Ogunwale822e5122017-07-26 06:02:24 -070048public class WindowConfiguration implements Parcelable, Comparable<WindowConfiguration> {
Bryce Leef3c6a472017-11-14 14:53:06 -080049 /**
50 * bounds that can differ from app bounds, which may include things such as insets.
51 *
52 * TODO: Investigate combining with {@link mAppBounds}. Can the latter be a product of the
53 * former?
54 */
55 private Rect mBounds = new Rect();
Wale Ogunwale822e5122017-07-26 06:02:24 -070056
57 /**
58 * {@link android.graphics.Rect} defining app bounds. The dimensions override usages of
59 * {@link DisplayInfo#appHeight} and {@link DisplayInfo#appWidth} and mirrors these values at
60 * the display level. Lower levels can override these values to provide custom bounds to enforce
61 * features such as a max aspect ratio.
62 */
63 private Rect mAppBounds;
64
Evan Roskye747c3e2018-10-30 20:06:41 -070065 /**
66 * The current rotation of this window container relative to the default
67 * orientation of the display it is on (regardless of how deep in the hierarchy
68 * it is). It is used by the configuration hierarchy to apply rotation-dependent
69 * policy during bounds calculation.
70 */
71 private int mRotation = ROTATION_UNDEFINED;
72
73 /** Rotation is not defined, use the parent containers rotation. */
74 public static final int ROTATION_UNDEFINED = -1;
75
Wale Ogunwale687b4272017-07-27 02:56:23 -070076 /** The current windowing mode of the configuration. */
77 private @WindowingMode int mWindowingMode;
78
Yunfan Chen7daa6ac2018-11-29 18:16:44 -080079 /** The display windowing mode of the configuration */
80 private @WindowingMode int mDisplayWindowingMode;
81
Wale Ogunwale0d5609b2017-09-13 05:55:07 -070082 /** Windowing mode is currently not defined. */
Wale Ogunwale687b4272017-07-27 02:56:23 -070083 public static final int WINDOWING_MODE_UNDEFINED = 0;
Wale Ogunwale0d5609b2017-09-13 05:55:07 -070084 /** Occupies the full area of the screen or the parent container. */
Wale Ogunwale687b4272017-07-27 02:56:23 -070085 public static final int WINDOWING_MODE_FULLSCREEN = 1;
Wale Ogunwale0d5609b2017-09-13 05:55:07 -070086 /** Always on-top (always visible). of other siblings in its parent container. */
Wale Ogunwale687b4272017-07-27 02:56:23 -070087 public static final int WINDOWING_MODE_PINNED = 2;
Wale Ogunwale0d5609b2017-09-13 05:55:07 -070088 /** The primary container driving the screen to be in split-screen mode. */
Wale Ogunwale926aade2017-08-29 11:24:37 -070089 public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3;
90 /**
91 * The containers adjacent to the {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} container in
92 * split-screen mode.
Wale Ogunwale0568aed2017-09-08 13:29:37 -070093 * NOTE: Containers launched with the windowing mode with APIs like
94 * {@link ActivityOptions#setLaunchWindowingMode(int)} will be launched in
95 * {@link #WINDOWING_MODE_FULLSCREEN} if the display isn't currently in split-screen windowing
96 * mode
97 * @see #WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY
Wale Ogunwale926aade2017-08-29 11:24:37 -070098 */
99 public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4;
Wale Ogunwale0568aed2017-09-08 13:29:37 -0700100 /**
101 * Alias for {@link #WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} that makes it clear that the usage
102 * points for APIs like {@link ActivityOptions#setLaunchWindowingMode(int)} that the container
103 * will launch into fullscreen or split-screen secondary depending on if the device is currently
104 * in fullscreen mode or split-screen mode.
105 */
106 public static final int WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY =
107 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700108 /** Can be freely resized within its parent container. */
Wale Ogunwale926aade2017-08-29 11:24:37 -0700109 public static final int WINDOWING_MODE_FREEFORM = 5;
Wale Ogunwale687b4272017-07-27 02:56:23 -0700110
Steven Timotiuse597ca12017-09-05 15:46:29 -0700111 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700112 @IntDef(prefix = { "WINDOWING_MODE_" }, value = {
Wale Ogunwale687b4272017-07-27 02:56:23 -0700113 WINDOWING_MODE_UNDEFINED,
114 WINDOWING_MODE_FULLSCREEN,
115 WINDOWING_MODE_PINNED,
Wale Ogunwale926aade2017-08-29 11:24:37 -0700116 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
117 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
Wale Ogunwale0568aed2017-09-08 13:29:37 -0700118 WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY,
Wale Ogunwale687b4272017-07-27 02:56:23 -0700119 WINDOWING_MODE_FREEFORM,
120 })
Wale Ogunwale687b4272017-07-27 02:56:23 -0700121 public @interface WindowingMode {}
Wale Ogunwale822e5122017-07-26 06:02:24 -0700122
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700123 /** The current activity type of the configuration. */
124 private @ActivityType int mActivityType;
125
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700126 /** Activity type is currently not defined. */
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700127 public static final int ACTIVITY_TYPE_UNDEFINED = 0;
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700128 /** Standard activity type. Nothing special about the activity... */
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700129 public static final int ACTIVITY_TYPE_STANDARD = 1;
130 /** Home/Launcher activity type. */
131 public static final int ACTIVITY_TYPE_HOME = 2;
Winson Chung3f0e59a2017-10-25 10:19:05 -0700132 /** Recents/Overview activity type. There is only one activity with this type in the system. */
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700133 public static final int ACTIVITY_TYPE_RECENTS = 3;
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700134 /** Assistant activity type. */
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700135 public static final int ACTIVITY_TYPE_ASSISTANT = 4;
136
Steven Timotiuse597ca12017-09-05 15:46:29 -0700137 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700138 @IntDef(prefix = { "ACTIVITY_TYPE_" }, value = {
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700139 ACTIVITY_TYPE_UNDEFINED,
140 ACTIVITY_TYPE_STANDARD,
141 ACTIVITY_TYPE_HOME,
142 ACTIVITY_TYPE_RECENTS,
143 ACTIVITY_TYPE_ASSISTANT,
144 })
145 public @interface ActivityType {}
146
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900147 /** The current always on top status of the configuration. */
148 private @AlwaysOnTop int mAlwaysOnTop;
149
150 /** Always on top is currently not defined. */
151 private static final int ALWAYS_ON_TOP_UNDEFINED = 0;
152 /** Always on top is currently on for this configuration. */
153 private static final int ALWAYS_ON_TOP_ON = 1;
154 /** Always on top is currently off for this configuration. */
155 private static final int ALWAYS_ON_TOP_OFF = 2;
156
157 /** @hide */
158 @IntDef(prefix = { "ALWAYS_ON_TOP_" }, value = {
159 ALWAYS_ON_TOP_UNDEFINED,
160 ALWAYS_ON_TOP_ON,
161 ALWAYS_ON_TOP_OFF,
162 })
163 private @interface AlwaysOnTop {}
164
Bryce Leef3c6a472017-11-14 14:53:06 -0800165 /** Bit that indicates that the {@link #mBounds} changed.
166 * @hide */
167 public static final int WINDOW_CONFIG_BOUNDS = 1 << 0;
Steven Timotiuse597ca12017-09-05 15:46:29 -0700168 /** Bit that indicates that the {@link #mAppBounds} changed.
169 * @hide */
Bryce Leef3c6a472017-11-14 14:53:06 -0800170 public static final int WINDOW_CONFIG_APP_BOUNDS = 1 << 1;
Steven Timotiuse597ca12017-09-05 15:46:29 -0700171 /** Bit that indicates that the {@link #mWindowingMode} changed.
172 * @hide */
Bryce Leef3c6a472017-11-14 14:53:06 -0800173 public static final int WINDOW_CONFIG_WINDOWING_MODE = 1 << 2;
Steven Timotiuse597ca12017-09-05 15:46:29 -0700174 /** Bit that indicates that the {@link #mActivityType} changed.
175 * @hide */
Bryce Leef3c6a472017-11-14 14:53:06 -0800176 public static final int WINDOW_CONFIG_ACTIVITY_TYPE = 1 << 3;
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900177 /** Bit that indicates that the {@link #mAlwaysOnTop} changed.
Kazuki Takise148d00a2018-05-31 15:32:19 +0900178 * @hide */
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900179 public static final int WINDOW_CONFIG_ALWAYS_ON_TOP = 1 << 4;
Evan Roskye747c3e2018-10-30 20:06:41 -0700180 /** Bit that indicates that the {@link #mRotation} changed.
181 * @hide */
182 public static final int WINDOW_CONFIG_ROTATION = 1 << 5;
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800183 /** Bit that indicates that the {@link #mDisplayWindowingMode} changed.
184 * @hide */
185 public static final int WINDOW_CONFIG_DISPLAY_WINDOWING_MODE = 1 << 6;
186
Steven Timotiuse597ca12017-09-05 15:46:29 -0700187 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700188 @IntDef(flag = true, prefix = { "WINDOW_CONFIG_" }, value = {
189 WINDOW_CONFIG_BOUNDS,
190 WINDOW_CONFIG_APP_BOUNDS,
191 WINDOW_CONFIG_WINDOWING_MODE,
Kazuki Takise148d00a2018-05-31 15:32:19 +0900192 WINDOW_CONFIG_ACTIVITY_TYPE,
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900193 WINDOW_CONFIG_ALWAYS_ON_TOP,
Evan Roskye747c3e2018-10-30 20:06:41 -0700194 WINDOW_CONFIG_ROTATION,
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800195 WINDOW_CONFIG_DISPLAY_WINDOWING_MODE,
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700196 })
Wale Ogunwale687b4272017-07-27 02:56:23 -0700197 public @interface WindowConfig {}
Wale Ogunwale822e5122017-07-26 06:02:24 -0700198
Robert Carr32bcb102018-01-29 15:03:23 -0800199 /** @hide */
200 public static final int PINNED_WINDOWING_MODE_ELEVATION_IN_DIP = 5;
201
Wale Ogunwale822e5122017-07-26 06:02:24 -0700202 public WindowConfiguration() {
203 unset();
204 }
205
Steven Timotiuse597ca12017-09-05 15:46:29 -0700206 /** @hide */
Wale Ogunwale822e5122017-07-26 06:02:24 -0700207 public WindowConfiguration(WindowConfiguration configuration) {
208 setTo(configuration);
209 }
210
211 private WindowConfiguration(Parcel in) {
212 readFromParcel(in);
213 }
214
215 @Override
216 public void writeToParcel(Parcel dest, int flags) {
Bryce Leef3c6a472017-11-14 14:53:06 -0800217 dest.writeParcelable(mBounds, flags);
Wale Ogunwale822e5122017-07-26 06:02:24 -0700218 dest.writeParcelable(mAppBounds, flags);
Wale Ogunwale687b4272017-07-27 02:56:23 -0700219 dest.writeInt(mWindowingMode);
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700220 dest.writeInt(mActivityType);
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900221 dest.writeInt(mAlwaysOnTop);
Evan Roskye747c3e2018-10-30 20:06:41 -0700222 dest.writeInt(mRotation);
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800223 dest.writeInt(mDisplayWindowingMode);
Wale Ogunwale822e5122017-07-26 06:02:24 -0700224 }
225
226 private void readFromParcel(Parcel source) {
Bryce Leef3c6a472017-11-14 14:53:06 -0800227 mBounds = source.readParcelable(Rect.class.getClassLoader());
Wale Ogunwale822e5122017-07-26 06:02:24 -0700228 mAppBounds = source.readParcelable(Rect.class.getClassLoader());
Wale Ogunwale687b4272017-07-27 02:56:23 -0700229 mWindowingMode = source.readInt();
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700230 mActivityType = source.readInt();
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900231 mAlwaysOnTop = source.readInt();
Evan Roskye747c3e2018-10-30 20:06:41 -0700232 mRotation = source.readInt();
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800233 mDisplayWindowingMode = source.readInt();
Wale Ogunwale822e5122017-07-26 06:02:24 -0700234 }
235
236 @Override
237 public int describeContents() {
238 return 0;
239 }
240
Steven Timotiuse597ca12017-09-05 15:46:29 -0700241 /** @hide */
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700242 public static final @android.annotation.NonNull Creator<WindowConfiguration> CREATOR = new Creator<WindowConfiguration>() {
Wale Ogunwale822e5122017-07-26 06:02:24 -0700243 @Override
244 public WindowConfiguration createFromParcel(Parcel in) {
245 return new WindowConfiguration(in);
246 }
247
248 @Override
249 public WindowConfiguration[] newArray(int size) {
250 return new WindowConfiguration[size];
251 }
252 };
253
254 /**
Bryce Leef3c6a472017-11-14 14:53:06 -0800255 * Sets the bounds to the provided {@link Rect}.
256 * @param rect the new bounds value.
257 */
258 public void setBounds(Rect rect) {
259 if (rect == null) {
260 mBounds.setEmpty();
261 return;
262 }
263
264 mBounds.set(rect);
265 }
266
267 /**
Wale Ogunwale822e5122017-07-26 06:02:24 -0700268 * Set {@link #mAppBounds} to the input Rect.
269 * @param rect The rect value to set {@link #mAppBounds} to.
270 * @see #getAppBounds()
271 */
272 public void setAppBounds(Rect rect) {
273 if (rect == null) {
274 mAppBounds = null;
275 return;
276 }
277
278 setAppBounds(rect.left, rect.top, rect.right, rect.bottom);
279 }
280
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900281
Kazuki Takise148d00a2018-05-31 15:32:19 +0900282
283 /**
284 * Sets whether this window should be always on top.
285 * @param alwaysOnTop {@code true} to set window always on top, otherwise {@code false}
286 * @hide
287 */
288 public void setAlwaysOnTop(boolean alwaysOnTop) {
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900289 mAlwaysOnTop = alwaysOnTop ? ALWAYS_ON_TOP_ON : ALWAYS_ON_TOP_OFF;
290 }
291
292 private void setAlwaysOnTop(@AlwaysOnTop int alwaysOnTop) {
293 mAlwaysOnTop = alwaysOnTop;
Kazuki Takise148d00a2018-05-31 15:32:19 +0900294 }
295
Wale Ogunwale822e5122017-07-26 06:02:24 -0700296 /**
297 * @see #setAppBounds(Rect)
298 * @see #getAppBounds()
Steven Timotiuse597ca12017-09-05 15:46:29 -0700299 * @hide
Wale Ogunwale822e5122017-07-26 06:02:24 -0700300 */
301 public void setAppBounds(int left, int top, int right, int bottom) {
302 if (mAppBounds == null) {
303 mAppBounds = new Rect();
304 }
305
306 mAppBounds.set(left, top, right, bottom);
307 }
308
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700309 /** @see #setAppBounds(Rect) */
Wale Ogunwale822e5122017-07-26 06:02:24 -0700310 public Rect getAppBounds() {
311 return mAppBounds;
312 }
313
Bryce Leef3c6a472017-11-14 14:53:06 -0800314 /** @see #setBounds(Rect) */
315 public Rect getBounds() {
316 return mBounds;
317 }
318
Evan Roskye747c3e2018-10-30 20:06:41 -0700319 public int getRotation() {
320 return mRotation;
321 }
322
323 public void setRotation(int rotation) {
324 mRotation = rotation;
325 }
326
Wale Ogunwale687b4272017-07-27 02:56:23 -0700327 public void setWindowingMode(@WindowingMode int windowingMode) {
328 mWindowingMode = windowingMode;
329 }
330
331 @WindowingMode
332 public int getWindowingMode() {
333 return mWindowingMode;
334 }
335
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800336 /** @hide */
337 public void setDisplayWindowingMode(@WindowingMode int windowingMode) {
338 mDisplayWindowingMode = windowingMode;
339 }
340
341
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700342 public void setActivityType(@ActivityType int activityType) {
343 if (mActivityType == activityType) {
344 return;
345 }
Wale Ogunwale6cbbc9a2017-09-06 19:01:03 -0700346
347 // Error check within system server that we are not changing activity type which can be
348 // dangerous. It is okay for things to change in the application process as it doesn't
349 // affect how other things is the system is managed.
350 if (isSystem()
351 && mActivityType != ACTIVITY_TYPE_UNDEFINED
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700352 && activityType != ACTIVITY_TYPE_UNDEFINED) {
353 throw new IllegalStateException("Can't change activity type once set: " + this
354 + " activityType=" + activityTypeToString(activityType));
355 }
356 mActivityType = activityType;
357 }
358
359 @ActivityType
360 public int getActivityType() {
361 return mActivityType;
362 }
363
Wale Ogunwale822e5122017-07-26 06:02:24 -0700364 public void setTo(WindowConfiguration other) {
Bryce Leef3c6a472017-11-14 14:53:06 -0800365 setBounds(other.mBounds);
Wale Ogunwale822e5122017-07-26 06:02:24 -0700366 setAppBounds(other.mAppBounds);
Wale Ogunwale687b4272017-07-27 02:56:23 -0700367 setWindowingMode(other.mWindowingMode);
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700368 setActivityType(other.mActivityType);
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900369 setAlwaysOnTop(other.mAlwaysOnTop);
Evan Roskye747c3e2018-10-30 20:06:41 -0700370 setRotation(other.mRotation);
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800371 setDisplayWindowingMode(other.mDisplayWindowingMode);
Wale Ogunwale822e5122017-07-26 06:02:24 -0700372 }
373
Steven Timotiuse597ca12017-09-05 15:46:29 -0700374 /** Set this object to completely undefined.
375 * @hide */
Wale Ogunwale822e5122017-07-26 06:02:24 -0700376 public void unset() {
377 setToDefaults();
378 }
379
Steven Timotiuse597ca12017-09-05 15:46:29 -0700380 /** @hide */
Wale Ogunwale822e5122017-07-26 06:02:24 -0700381 public void setToDefaults() {
382 setAppBounds(null);
Bryce Leef3c6a472017-11-14 14:53:06 -0800383 setBounds(null);
Wale Ogunwale687b4272017-07-27 02:56:23 -0700384 setWindowingMode(WINDOWING_MODE_UNDEFINED);
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700385 setActivityType(ACTIVITY_TYPE_UNDEFINED);
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900386 setAlwaysOnTop(ALWAYS_ON_TOP_UNDEFINED);
Evan Roskye747c3e2018-10-30 20:06:41 -0700387 setRotation(ROTATION_UNDEFINED);
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800388 setDisplayWindowingMode(WINDOWING_MODE_UNDEFINED);
Wale Ogunwale822e5122017-07-26 06:02:24 -0700389 }
390
391 /**
392 * Copies the fields from delta into this Configuration object, keeping
393 * track of which ones have changed. Any undefined fields in {@code delta}
394 * are ignored and not copied in to the current Configuration.
395 *
396 * @return a bit mask of the changed fields, as per {@link #diff}
Steven Timotiuse597ca12017-09-05 15:46:29 -0700397 * @hide
Wale Ogunwale822e5122017-07-26 06:02:24 -0700398 */
399 public @WindowConfig int updateFrom(@NonNull WindowConfiguration delta) {
400 int changed = 0;
Bryce Leef3c6a472017-11-14 14:53:06 -0800401 // Only allow override if bounds is not empty
402 if (!delta.mBounds.isEmpty() && !delta.mBounds.equals(mBounds)) {
403 changed |= WINDOW_CONFIG_BOUNDS;
404 setBounds(delta.mBounds);
405 }
Wale Ogunwale822e5122017-07-26 06:02:24 -0700406 if (delta.mAppBounds != null && !delta.mAppBounds.equals(mAppBounds)) {
407 changed |= WINDOW_CONFIG_APP_BOUNDS;
408 setAppBounds(delta.mAppBounds);
409 }
Wale Ogunwale687b4272017-07-27 02:56:23 -0700410 if (delta.mWindowingMode != WINDOWING_MODE_UNDEFINED
411 && mWindowingMode != delta.mWindowingMode) {
412 changed |= WINDOW_CONFIG_WINDOWING_MODE;
413 setWindowingMode(delta.mWindowingMode);
414 }
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700415 if (delta.mActivityType != ACTIVITY_TYPE_UNDEFINED
416 && mActivityType != delta.mActivityType) {
417 changed |= WINDOW_CONFIG_ACTIVITY_TYPE;
418 setActivityType(delta.mActivityType);
419 }
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900420 if (delta.mAlwaysOnTop != ALWAYS_ON_TOP_UNDEFINED
421 && mAlwaysOnTop != delta.mAlwaysOnTop) {
422 changed |= WINDOW_CONFIG_ALWAYS_ON_TOP;
423 setAlwaysOnTop(delta.mAlwaysOnTop);
424 }
Evan Roskye747c3e2018-10-30 20:06:41 -0700425 if (delta.mRotation != ROTATION_UNDEFINED && delta.mRotation != mRotation) {
426 changed |= WINDOW_CONFIG_ROTATION;
427 setRotation(delta.mRotation);
428 }
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800429 if (delta.mDisplayWindowingMode != WINDOWING_MODE_UNDEFINED
430 && mDisplayWindowingMode != delta.mDisplayWindowingMode) {
431 changed |= WINDOW_CONFIG_DISPLAY_WINDOWING_MODE;
432 setDisplayWindowingMode(delta.mDisplayWindowingMode);
433 }
Wale Ogunwale822e5122017-07-26 06:02:24 -0700434 return changed;
435 }
436
437 /**
438 * Return a bit mask of the differences between this Configuration object and the given one.
439 * Does not change the values of either. Any undefined fields in <var>other</var> are ignored.
440 * @param other The configuration to diff against.
441 * @param compareUndefined If undefined values should be compared.
442 * @return Returns a bit mask indicating which configuration
443 * values has changed, containing any combination of {@link WindowConfig} flags.
444 *
445 * @see Configuration#diff(Configuration)
Steven Timotiuse597ca12017-09-05 15:46:29 -0700446 * @hide
Wale Ogunwale822e5122017-07-26 06:02:24 -0700447 */
448 public @WindowConfig long diff(WindowConfiguration other, boolean compareUndefined) {
449 long changes = 0;
450
Bryce Leef3c6a472017-11-14 14:53:06 -0800451 if (!mBounds.equals(other.mBounds)) {
452 changes |= WINDOW_CONFIG_BOUNDS;
453 }
454
Wale Ogunwale822e5122017-07-26 06:02:24 -0700455 // Make sure that one of the values is not null and that they are not equal.
456 if ((compareUndefined || other.mAppBounds != null)
457 && mAppBounds != other.mAppBounds
458 && (mAppBounds == null || !mAppBounds.equals(other.mAppBounds))) {
459 changes |= WINDOW_CONFIG_APP_BOUNDS;
460 }
461
Wale Ogunwale687b4272017-07-27 02:56:23 -0700462 if ((compareUndefined || other.mWindowingMode != WINDOWING_MODE_UNDEFINED)
463 && mWindowingMode != other.mWindowingMode) {
464 changes |= WINDOW_CONFIG_WINDOWING_MODE;
465 }
466
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700467 if ((compareUndefined || other.mActivityType != ACTIVITY_TYPE_UNDEFINED)
468 && mActivityType != other.mActivityType) {
469 changes |= WINDOW_CONFIG_ACTIVITY_TYPE;
470 }
471
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900472 if ((compareUndefined || other.mAlwaysOnTop != ALWAYS_ON_TOP_UNDEFINED)
473 && mAlwaysOnTop != other.mAlwaysOnTop) {
474 changes |= WINDOW_CONFIG_ALWAYS_ON_TOP;
475 }
476
Evan Roskye747c3e2018-10-30 20:06:41 -0700477 if ((compareUndefined || other.mRotation != ROTATION_UNDEFINED)
478 && mRotation != other.mRotation) {
479 changes |= WINDOW_CONFIG_ROTATION;
480 }
481
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800482 if ((compareUndefined || other.mDisplayWindowingMode != WINDOWING_MODE_UNDEFINED)
483 && mDisplayWindowingMode != other.mDisplayWindowingMode) {
484 changes |= WINDOW_CONFIG_DISPLAY_WINDOWING_MODE;
485 }
486
Wale Ogunwale822e5122017-07-26 06:02:24 -0700487 return changes;
488 }
489
490 @Override
491 public int compareTo(WindowConfiguration that) {
492 int n = 0;
493 if (mAppBounds == null && that.mAppBounds != null) {
494 return 1;
495 } else if (mAppBounds != null && that.mAppBounds == null) {
496 return -1;
497 } else if (mAppBounds != null && that.mAppBounds != null) {
498 n = mAppBounds.left - that.mAppBounds.left;
499 if (n != 0) return n;
500 n = mAppBounds.top - that.mAppBounds.top;
501 if (n != 0) return n;
502 n = mAppBounds.right - that.mAppBounds.right;
503 if (n != 0) return n;
504 n = mAppBounds.bottom - that.mAppBounds.bottom;
505 if (n != 0) return n;
506 }
Bryce Leef3c6a472017-11-14 14:53:06 -0800507
508 n = mBounds.left - that.mBounds.left;
509 if (n != 0) return n;
510 n = mBounds.top - that.mBounds.top;
511 if (n != 0) return n;
512 n = mBounds.right - that.mBounds.right;
513 if (n != 0) return n;
514 n = mBounds.bottom - that.mBounds.bottom;
515 if (n != 0) return n;
516
Wale Ogunwale687b4272017-07-27 02:56:23 -0700517 n = mWindowingMode - that.mWindowingMode;
518 if (n != 0) return n;
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700519 n = mActivityType - that.mActivityType;
520 if (n != 0) return n;
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900521 n = mAlwaysOnTop - that.mAlwaysOnTop;
Kazuki Takise148d00a2018-05-31 15:32:19 +0900522 if (n != 0) return n;
Evan Roskye747c3e2018-10-30 20:06:41 -0700523 n = mRotation - that.mRotation;
524 if (n != 0) return n;
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800525 n = mDisplayWindowingMode - that.mDisplayWindowingMode;
526 if (n != 0) return n;
Kazuki Takise148d00a2018-05-31 15:32:19 +0900527
Wale Ogunwale822e5122017-07-26 06:02:24 -0700528 // if (n != 0) return n;
529 return n;
530 }
531
Steven Timotiuse597ca12017-09-05 15:46:29 -0700532 /** @hide */
Wale Ogunwale822e5122017-07-26 06:02:24 -0700533 @Override
534 public boolean equals(Object that) {
535 if (that == null) return false;
536 if (that == this) return true;
537 if (!(that instanceof WindowConfiguration)) {
538 return false;
539 }
540 return this.compareTo((WindowConfiguration) that) == 0;
541 }
542
Steven Timotiuse597ca12017-09-05 15:46:29 -0700543 /** @hide */
Wale Ogunwale822e5122017-07-26 06:02:24 -0700544 @Override
545 public int hashCode() {
546 int result = 0;
547 if (mAppBounds != null) {
548 result = 31 * result + mAppBounds.hashCode();
549 }
Bryce Leef3c6a472017-11-14 14:53:06 -0800550 result = 31 * result + mBounds.hashCode();
551
Wale Ogunwale687b4272017-07-27 02:56:23 -0700552 result = 31 * result + mWindowingMode;
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700553 result = 31 * result + mActivityType;
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900554 result = 31 * result + mAlwaysOnTop;
Evan Roskye747c3e2018-10-30 20:06:41 -0700555 result = 31 * result + mRotation;
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800556 result = 31 * result + mDisplayWindowingMode;
Wale Ogunwale822e5122017-07-26 06:02:24 -0700557 return result;
558 }
559
Steven Timotiuse597ca12017-09-05 15:46:29 -0700560 /** @hide */
Wale Ogunwale822e5122017-07-26 06:02:24 -0700561 @Override
562 public String toString() {
Bryce Leef3c6a472017-11-14 14:53:06 -0800563 return "{ mBounds=" + mBounds
564 + " mAppBounds=" + mAppBounds
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700565 + " mWindowingMode=" + windowingModeToString(mWindowingMode)
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800566 + " mDisplayWindowingMode=" + windowingModeToString(mDisplayWindowingMode)
Kazuki Takise148d00a2018-05-31 15:32:19 +0900567 + " mActivityType=" + activityTypeToString(mActivityType)
Kazuki Takisef85197b2018-06-18 18:18:36 +0900568 + " mAlwaysOnTop=" + alwaysOnTopToString(mAlwaysOnTop)
Evan Roskye747c3e2018-10-30 20:06:41 -0700569 + " mRotation=" + (mRotation == ROTATION_UNDEFINED
570 ? "undefined" : rotationToString(mRotation))
Kazuki Takise148d00a2018-05-31 15:32:19 +0900571 + "}";
Wale Ogunwale687b4272017-07-27 02:56:23 -0700572 }
573
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700574 /**
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700575 * Write to a protocol buffer output stream.
576 * Protocol buffer message definition at {@link android.app.WindowConfigurationProto}
577 *
578 * @param protoOutputStream Stream to write the WindowConfiguration object to.
579 * @param fieldId Field Id of the WindowConfiguration as defined in the parent message
580 * @hide
581 */
582 public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId) {
583 final long token = protoOutputStream.start(fieldId);
584 if (mAppBounds != null) {
585 mAppBounds.writeToProto(protoOutputStream, APP_BOUNDS);
586 }
587 protoOutputStream.write(WINDOWING_MODE, mWindowingMode);
588 protoOutputStream.write(ACTIVITY_TYPE, mActivityType);
Adrian Roos5f8b52c2018-11-28 16:31:55 +0100589 if (mBounds != null) {
590 mBounds.writeToProto(protoOutputStream, BOUNDS);
591 }
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700592 protoOutputStream.end(token);
593 }
594
595 /**
Michael Wachenschwanzc8c26362018-09-07 14:59:25 -0700596 * Read from a protocol buffer input stream.
597 * Protocol buffer message definition at {@link android.app.WindowConfigurationProto}
598 *
599 * @param proto Stream to read the WindowConfiguration object from.
600 * @param fieldId Field Id of the WindowConfiguration as defined in the parent message
601 * @hide
602 */
603 public void readFromProto(ProtoInputStream proto, long fieldId)
604 throws IOException, WireTypeMismatchException {
605 final long token = proto.start(fieldId);
606 try {
607 while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
608 switch (proto.getFieldNumber()) {
609 case (int) APP_BOUNDS:
610 mAppBounds = new Rect();
611 mAppBounds.readFromProto(proto, APP_BOUNDS);
612 break;
Adrian Roos5f8b52c2018-11-28 16:31:55 +0100613 case (int) BOUNDS:
614 mBounds = new Rect();
615 mBounds.readFromProto(proto, BOUNDS);
616 break;
Michael Wachenschwanzc8c26362018-09-07 14:59:25 -0700617 case (int) WINDOWING_MODE:
618 mWindowingMode = proto.readInt(WINDOWING_MODE);
619 break;
620 case (int) ACTIVITY_TYPE:
621 mActivityType = proto.readInt(ACTIVITY_TYPE);
622 break;
623 }
624 }
625 } finally {
626 // Let caller handle any exceptions
627 proto.end(token);
628 }
629 }
630
631 /**
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700632 * Returns true if the activities associated with this window configuration display a shadow
633 * around their border.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700634 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700635 */
636 public boolean hasWindowShadow() {
637 return tasksAreFloating();
638 }
639
640 /**
641 * Returns true if the activities associated with this window configuration display a decor
642 * view.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700643 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700644 */
645 public boolean hasWindowDecorCaption() {
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800646 return mActivityType == ACTIVITY_TYPE_STANDARD && (mWindowingMode == WINDOWING_MODE_FREEFORM
647 || mDisplayWindowingMode == WINDOWING_MODE_FREEFORM);
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700648 }
649
650 /**
651 * Returns true if the tasks associated with this window configuration can be resized
652 * independently of their parent container.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700653 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700654 */
655 public boolean canResizeTask() {
656 return mWindowingMode == WINDOWING_MODE_FREEFORM;
657 }
658
Steven Timotiuse597ca12017-09-05 15:46:29 -0700659 /** Returns true if the task bounds should persist across power cycles.
660 * @hide */
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700661 public boolean persistTaskBounds() {
662 return mWindowingMode == WINDOWING_MODE_FREEFORM;
663 }
664
665 /**
666 * Returns true if the tasks associated with this window configuration are floating.
667 * Floating tasks are laid out differently as they are allowed to extend past the display bounds
668 * without overscan insets.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700669 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700670 */
671 public boolean tasksAreFloating() {
Evan Roskyb0e38882018-04-25 12:48:54 -0700672 return isFloating(mWindowingMode);
673 }
674
675 /**
676 * Returns true if the windowingMode represents a floating window.
677 * @hide
678 */
679 public static boolean isFloating(int windowingMode) {
680 return windowingMode == WINDOWING_MODE_FREEFORM || windowingMode == WINDOWING_MODE_PINNED;
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700681 }
682
683 /**
Evan Rosky1ac84462018-11-13 11:25:30 -0800684 * Returns true if the windowingMode represents a split window.
685 * @hide
686 */
687 public static boolean isSplitScreenWindowingMode(int windowingMode) {
688 return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
689 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
690 }
691
692 /**
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700693 * Returns true if the windows associated with this window configuration can receive input keys.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700694 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700695 */
696 public boolean canReceiveKeys() {
697 return mWindowingMode != WINDOWING_MODE_PINNED;
698 }
699
700 /**
701 * Returns true if the container associated with this window configuration is always-on-top of
702 * its siblings.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700703 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700704 */
705 public boolean isAlwaysOnTop() {
Kazuki Takise048e2662018-06-27 17:05:11 +0900706 return mWindowingMode == WINDOWING_MODE_PINNED
707 || (mWindowingMode == WINDOWING_MODE_FREEFORM && mAlwaysOnTop == ALWAYS_ON_TOP_ON);
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700708 }
709
710 /**
711 * Returns true if any visible windows belonging to apps with this window configuration should
712 * be kept on screen when the app is killed due to something like the low memory killer.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700713 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700714 */
715 public boolean keepVisibleDeadAppWindowOnScreen() {
716 return mWindowingMode != WINDOWING_MODE_PINNED;
717 }
718
719 /**
720 * Returns true if the backdrop on the client side should match the frame of the window.
721 * Returns false, if the backdrop should be fullscreen.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700722 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700723 */
724 public boolean useWindowFrameForBackdrop() {
725 return mWindowingMode == WINDOWING_MODE_FREEFORM || mWindowingMode == WINDOWING_MODE_PINNED;
726 }
727
728 /**
729 * Returns true if this container may be scaled without resizing, and windows within may need
730 * to be configured as such.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700731 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700732 */
733 public boolean windowsAreScaleable() {
734 return mWindowingMode == WINDOWING_MODE_PINNED;
735 }
736
737 /**
738 * Returns true if windows in this container should be given move animations by default.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700739 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700740 */
741 public boolean hasMovementAnimations() {
Jorim Jaggibb6ee9b2017-09-06 23:59:34 +0200742 return mWindowingMode != WINDOWING_MODE_PINNED;
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700743 }
744
Wale Ogunwale926aade2017-08-29 11:24:37 -0700745 /**
746 * Returns true if this container can be put in either
747 * {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} or
748 * {@link #WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} windowing modes based on its current state.
749 * @hide
750 */
751 public boolean supportSplitScreenWindowingMode() {
Wale Ogunwale2b07da82017-11-08 14:52:40 -0800752 return supportSplitScreenWindowingMode(mActivityType);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700753 }
754
755 /** @hide */
Wale Ogunwale2b07da82017-11-08 14:52:40 -0800756 public static boolean supportSplitScreenWindowingMode(int activityType) {
757 return activityType != ACTIVITY_TYPE_ASSISTANT;
Wale Ogunwale926aade2017-08-29 11:24:37 -0700758 }
759
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700760 /** @hide */
761 public static String windowingModeToString(@WindowingMode int windowingMode) {
Wale Ogunwale687b4272017-07-27 02:56:23 -0700762 switch (windowingMode) {
763 case WINDOWING_MODE_UNDEFINED: return "undefined";
764 case WINDOWING_MODE_FULLSCREEN: return "fullscreen";
765 case WINDOWING_MODE_PINNED: return "pinned";
Wale Ogunwale926aade2017-08-29 11:24:37 -0700766 case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return "split-screen-primary";
767 case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: return "split-screen-secondary";
Wale Ogunwale687b4272017-07-27 02:56:23 -0700768 case WINDOWING_MODE_FREEFORM: return "freeform";
769 }
770 return String.valueOf(windowingMode);
Wale Ogunwale822e5122017-07-26 06:02:24 -0700771 }
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700772
Steven Timotiuse597ca12017-09-05 15:46:29 -0700773 /** @hide */
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700774 public static String activityTypeToString(@ActivityType int applicationType) {
775 switch (applicationType) {
776 case ACTIVITY_TYPE_UNDEFINED: return "undefined";
777 case ACTIVITY_TYPE_STANDARD: return "standard";
778 case ACTIVITY_TYPE_HOME: return "home";
779 case ACTIVITY_TYPE_RECENTS: return "recents";
780 case ACTIVITY_TYPE_ASSISTANT: return "assistant";
781 }
782 return String.valueOf(applicationType);
783 }
Kazuki Takisef85197b2018-06-18 18:18:36 +0900784
785 /** @hide */
786 public static String alwaysOnTopToString(@AlwaysOnTop int alwaysOnTop) {
787 switch (alwaysOnTop) {
788 case ALWAYS_ON_TOP_UNDEFINED: return "undefined";
789 case ALWAYS_ON_TOP_ON: return "on";
790 case ALWAYS_ON_TOP_OFF: return "off";
791 }
792 return String.valueOf(alwaysOnTop);
793 }
Wale Ogunwale822e5122017-07-26 06:02:24 -0700794}