blob: 8cb094f8a6a603b9a99e78a404734dcfc250e864 [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
Artur Satayevf0b7d0b2019-11-04 11:16:45 +000038import dalvik.annotation.compat.UnsupportedAppUsage;
39
Michael Wachenschwanzc8c26362018-09-07 14:59:25 -070040import java.io.IOException;
41
Wale Ogunwale822e5122017-07-26 06:02:24 -070042/**
43 * Class that contains windowing configuration/state for other objects that contain windows directly
44 * or indirectly. E.g. Activities, Task, Displays, ...
45 * The test class is {@link com.android.server.wm.WindowConfigurationTests} which must be kept
46 * up-to-date and ran anytime changes are made to this class.
47 * @hide
48 */
Steven Timotiuse597ca12017-09-05 15:46:29 -070049@TestApi
Wale Ogunwale822e5122017-07-26 06:02:24 -070050public class WindowConfiguration implements Parcelable, Comparable<WindowConfiguration> {
Bryce Leef3c6a472017-11-14 14:53:06 -080051 /**
52 * bounds that can differ from app bounds, which may include things such as insets.
53 *
54 * TODO: Investigate combining with {@link mAppBounds}. Can the latter be a product of the
55 * former?
56 */
57 private Rect mBounds = new Rect();
Wale Ogunwale822e5122017-07-26 06:02:24 -070058
59 /**
60 * {@link android.graphics.Rect} defining app bounds. The dimensions override usages of
61 * {@link DisplayInfo#appHeight} and {@link DisplayInfo#appWidth} and mirrors these values at
62 * the display level. Lower levels can override these values to provide custom bounds to enforce
63 * features such as a max aspect ratio.
64 */
65 private Rect mAppBounds;
66
Evan Roskye747c3e2018-10-30 20:06:41 -070067 /**
68 * The current rotation of this window container relative to the default
69 * orientation of the display it is on (regardless of how deep in the hierarchy
70 * it is). It is used by the configuration hierarchy to apply rotation-dependent
71 * policy during bounds calculation.
72 */
73 private int mRotation = ROTATION_UNDEFINED;
74
75 /** Rotation is not defined, use the parent containers rotation. */
76 public static final int ROTATION_UNDEFINED = -1;
77
Wale Ogunwale687b4272017-07-27 02:56:23 -070078 /** The current windowing mode of the configuration. */
79 private @WindowingMode int mWindowingMode;
80
Yunfan Chen7daa6ac2018-11-29 18:16:44 -080081 /** The display windowing mode of the configuration */
82 private @WindowingMode int mDisplayWindowingMode;
83
Wale Ogunwale0d5609b2017-09-13 05:55:07 -070084 /** Windowing mode is currently not defined. */
Wale Ogunwale687b4272017-07-27 02:56:23 -070085 public static final int WINDOWING_MODE_UNDEFINED = 0;
Wale Ogunwale0d5609b2017-09-13 05:55:07 -070086 /** Occupies the full area of the screen or the parent container. */
Wale Ogunwale687b4272017-07-27 02:56:23 -070087 public static final int WINDOWING_MODE_FULLSCREEN = 1;
Wale Ogunwale0d5609b2017-09-13 05:55:07 -070088 /** Always on-top (always visible). of other siblings in its parent container. */
Wale Ogunwale687b4272017-07-27 02:56:23 -070089 public static final int WINDOWING_MODE_PINNED = 2;
Wale Ogunwale0d5609b2017-09-13 05:55:07 -070090 /** The primary container driving the screen to be in split-screen mode. */
Wale Ogunwale926aade2017-08-29 11:24:37 -070091 public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3;
92 /**
93 * The containers adjacent to the {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} container in
94 * split-screen mode.
Wale Ogunwale0568aed2017-09-08 13:29:37 -070095 * NOTE: Containers launched with the windowing mode with APIs like
96 * {@link ActivityOptions#setLaunchWindowingMode(int)} will be launched in
97 * {@link #WINDOWING_MODE_FULLSCREEN} if the display isn't currently in split-screen windowing
98 * mode
99 * @see #WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY
Wale Ogunwale926aade2017-08-29 11:24:37 -0700100 */
101 public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4;
Wale Ogunwale0568aed2017-09-08 13:29:37 -0700102 /**
103 * Alias for {@link #WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} that makes it clear that the usage
104 * points for APIs like {@link ActivityOptions#setLaunchWindowingMode(int)} that the container
105 * will launch into fullscreen or split-screen secondary depending on if the device is currently
106 * in fullscreen mode or split-screen mode.
107 */
108 public static final int WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY =
109 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700110 /** Can be freely resized within its parent container. */
Wale Ogunwale926aade2017-08-29 11:24:37 -0700111 public static final int WINDOWING_MODE_FREEFORM = 5;
Wale Ogunwale687b4272017-07-27 02:56:23 -0700112
Steven Timotiuse597ca12017-09-05 15:46:29 -0700113 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700114 @IntDef(prefix = { "WINDOWING_MODE_" }, value = {
Wale Ogunwale687b4272017-07-27 02:56:23 -0700115 WINDOWING_MODE_UNDEFINED,
116 WINDOWING_MODE_FULLSCREEN,
117 WINDOWING_MODE_PINNED,
Wale Ogunwale926aade2017-08-29 11:24:37 -0700118 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
119 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
Wale Ogunwale0568aed2017-09-08 13:29:37 -0700120 WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY,
Wale Ogunwale687b4272017-07-27 02:56:23 -0700121 WINDOWING_MODE_FREEFORM,
122 })
Wale Ogunwale687b4272017-07-27 02:56:23 -0700123 public @interface WindowingMode {}
Wale Ogunwale822e5122017-07-26 06:02:24 -0700124
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700125 /** The current activity type of the configuration. */
126 private @ActivityType int mActivityType;
127
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700128 /** Activity type is currently not defined. */
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700129 public static final int ACTIVITY_TYPE_UNDEFINED = 0;
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700130 /** Standard activity type. Nothing special about the activity... */
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700131 public static final int ACTIVITY_TYPE_STANDARD = 1;
132 /** Home/Launcher activity type. */
133 public static final int ACTIVITY_TYPE_HOME = 2;
Winson Chung3f0e59a2017-10-25 10:19:05 -0700134 /** Recents/Overview activity type. There is only one activity with this type in the system. */
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700135 public static final int ACTIVITY_TYPE_RECENTS = 3;
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700136 /** Assistant activity type. */
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700137 public static final int ACTIVITY_TYPE_ASSISTANT = 4;
138
Steven Timotiuse597ca12017-09-05 15:46:29 -0700139 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700140 @IntDef(prefix = { "ACTIVITY_TYPE_" }, value = {
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700141 ACTIVITY_TYPE_UNDEFINED,
142 ACTIVITY_TYPE_STANDARD,
143 ACTIVITY_TYPE_HOME,
144 ACTIVITY_TYPE_RECENTS,
145 ACTIVITY_TYPE_ASSISTANT,
146 })
147 public @interface ActivityType {}
148
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900149 /** The current always on top status of the configuration. */
150 private @AlwaysOnTop int mAlwaysOnTop;
151
152 /** Always on top is currently not defined. */
153 private static final int ALWAYS_ON_TOP_UNDEFINED = 0;
154 /** Always on top is currently on for this configuration. */
155 private static final int ALWAYS_ON_TOP_ON = 1;
156 /** Always on top is currently off for this configuration. */
157 private static final int ALWAYS_ON_TOP_OFF = 2;
158
159 /** @hide */
160 @IntDef(prefix = { "ALWAYS_ON_TOP_" }, value = {
161 ALWAYS_ON_TOP_UNDEFINED,
162 ALWAYS_ON_TOP_ON,
163 ALWAYS_ON_TOP_OFF,
164 })
165 private @interface AlwaysOnTop {}
166
Bryce Leef3c6a472017-11-14 14:53:06 -0800167 /** Bit that indicates that the {@link #mBounds} changed.
168 * @hide */
169 public static final int WINDOW_CONFIG_BOUNDS = 1 << 0;
Steven Timotiuse597ca12017-09-05 15:46:29 -0700170 /** Bit that indicates that the {@link #mAppBounds} changed.
171 * @hide */
Bryce Leef3c6a472017-11-14 14:53:06 -0800172 public static final int WINDOW_CONFIG_APP_BOUNDS = 1 << 1;
Steven Timotiuse597ca12017-09-05 15:46:29 -0700173 /** Bit that indicates that the {@link #mWindowingMode} changed.
174 * @hide */
Bryce Leef3c6a472017-11-14 14:53:06 -0800175 public static final int WINDOW_CONFIG_WINDOWING_MODE = 1 << 2;
Steven Timotiuse597ca12017-09-05 15:46:29 -0700176 /** Bit that indicates that the {@link #mActivityType} changed.
177 * @hide */
Bryce Leef3c6a472017-11-14 14:53:06 -0800178 public static final int WINDOW_CONFIG_ACTIVITY_TYPE = 1 << 3;
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900179 /** Bit that indicates that the {@link #mAlwaysOnTop} changed.
Kazuki Takise148d00a2018-05-31 15:32:19 +0900180 * @hide */
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900181 public static final int WINDOW_CONFIG_ALWAYS_ON_TOP = 1 << 4;
Evan Roskye747c3e2018-10-30 20:06:41 -0700182 /** Bit that indicates that the {@link #mRotation} changed.
183 * @hide */
184 public static final int WINDOW_CONFIG_ROTATION = 1 << 5;
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800185 /** Bit that indicates that the {@link #mDisplayWindowingMode} changed.
186 * @hide */
187 public static final int WINDOW_CONFIG_DISPLAY_WINDOWING_MODE = 1 << 6;
188
Steven Timotiuse597ca12017-09-05 15:46:29 -0700189 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700190 @IntDef(flag = true, prefix = { "WINDOW_CONFIG_" }, value = {
191 WINDOW_CONFIG_BOUNDS,
192 WINDOW_CONFIG_APP_BOUNDS,
193 WINDOW_CONFIG_WINDOWING_MODE,
Kazuki Takise148d00a2018-05-31 15:32:19 +0900194 WINDOW_CONFIG_ACTIVITY_TYPE,
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900195 WINDOW_CONFIG_ALWAYS_ON_TOP,
Evan Roskye747c3e2018-10-30 20:06:41 -0700196 WINDOW_CONFIG_ROTATION,
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800197 WINDOW_CONFIG_DISPLAY_WINDOWING_MODE,
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700198 })
Wale Ogunwale687b4272017-07-27 02:56:23 -0700199 public @interface WindowConfig {}
Wale Ogunwale822e5122017-07-26 06:02:24 -0700200
Robert Carr32bcb102018-01-29 15:03:23 -0800201 /** @hide */
202 public static final int PINNED_WINDOWING_MODE_ELEVATION_IN_DIP = 5;
203
Artur Satayevf0b7d0b2019-11-04 11:16:45 +0000204 @UnsupportedAppUsage
Wale Ogunwale822e5122017-07-26 06:02:24 -0700205 public WindowConfiguration() {
206 unset();
207 }
208
Steven Timotiuse597ca12017-09-05 15:46:29 -0700209 /** @hide */
Wale Ogunwale822e5122017-07-26 06:02:24 -0700210 public WindowConfiguration(WindowConfiguration configuration) {
211 setTo(configuration);
212 }
213
214 private WindowConfiguration(Parcel in) {
215 readFromParcel(in);
216 }
217
218 @Override
219 public void writeToParcel(Parcel dest, int flags) {
Bryce Leef3c6a472017-11-14 14:53:06 -0800220 dest.writeParcelable(mBounds, flags);
Wale Ogunwale822e5122017-07-26 06:02:24 -0700221 dest.writeParcelable(mAppBounds, flags);
Wale Ogunwale687b4272017-07-27 02:56:23 -0700222 dest.writeInt(mWindowingMode);
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700223 dest.writeInt(mActivityType);
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900224 dest.writeInt(mAlwaysOnTop);
Evan Roskye747c3e2018-10-30 20:06:41 -0700225 dest.writeInt(mRotation);
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800226 dest.writeInt(mDisplayWindowingMode);
Wale Ogunwale822e5122017-07-26 06:02:24 -0700227 }
228
229 private void readFromParcel(Parcel source) {
Bryce Leef3c6a472017-11-14 14:53:06 -0800230 mBounds = source.readParcelable(Rect.class.getClassLoader());
Wale Ogunwale822e5122017-07-26 06:02:24 -0700231 mAppBounds = source.readParcelable(Rect.class.getClassLoader());
Wale Ogunwale687b4272017-07-27 02:56:23 -0700232 mWindowingMode = source.readInt();
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700233 mActivityType = source.readInt();
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900234 mAlwaysOnTop = source.readInt();
Evan Roskye747c3e2018-10-30 20:06:41 -0700235 mRotation = source.readInt();
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800236 mDisplayWindowingMode = source.readInt();
Wale Ogunwale822e5122017-07-26 06:02:24 -0700237 }
238
239 @Override
240 public int describeContents() {
241 return 0;
242 }
243
Steven Timotiuse597ca12017-09-05 15:46:29 -0700244 /** @hide */
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700245 public static final @android.annotation.NonNull Creator<WindowConfiguration> CREATOR = new Creator<WindowConfiguration>() {
Wale Ogunwale822e5122017-07-26 06:02:24 -0700246 @Override
247 public WindowConfiguration createFromParcel(Parcel in) {
248 return new WindowConfiguration(in);
249 }
250
251 @Override
252 public WindowConfiguration[] newArray(int size) {
253 return new WindowConfiguration[size];
254 }
255 };
256
257 /**
Bryce Leef3c6a472017-11-14 14:53:06 -0800258 * Sets the bounds to the provided {@link Rect}.
259 * @param rect the new bounds value.
260 */
261 public void setBounds(Rect rect) {
262 if (rect == null) {
263 mBounds.setEmpty();
264 return;
265 }
266
267 mBounds.set(rect);
268 }
269
270 /**
Wale Ogunwale822e5122017-07-26 06:02:24 -0700271 * Set {@link #mAppBounds} to the input Rect.
272 * @param rect The rect value to set {@link #mAppBounds} to.
273 * @see #getAppBounds()
274 */
275 public void setAppBounds(Rect rect) {
276 if (rect == null) {
277 mAppBounds = null;
278 return;
279 }
280
281 setAppBounds(rect.left, rect.top, rect.right, rect.bottom);
282 }
283
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900284
Kazuki Takise148d00a2018-05-31 15:32:19 +0900285
286 /**
287 * Sets whether this window should be always on top.
288 * @param alwaysOnTop {@code true} to set window always on top, otherwise {@code false}
289 * @hide
290 */
291 public void setAlwaysOnTop(boolean alwaysOnTop) {
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900292 mAlwaysOnTop = alwaysOnTop ? ALWAYS_ON_TOP_ON : ALWAYS_ON_TOP_OFF;
293 }
294
295 private void setAlwaysOnTop(@AlwaysOnTop int alwaysOnTop) {
296 mAlwaysOnTop = alwaysOnTop;
Kazuki Takise148d00a2018-05-31 15:32:19 +0900297 }
298
Wale Ogunwale822e5122017-07-26 06:02:24 -0700299 /**
300 * @see #setAppBounds(Rect)
301 * @see #getAppBounds()
Steven Timotiuse597ca12017-09-05 15:46:29 -0700302 * @hide
Wale Ogunwale822e5122017-07-26 06:02:24 -0700303 */
304 public void setAppBounds(int left, int top, int right, int bottom) {
305 if (mAppBounds == null) {
306 mAppBounds = new Rect();
307 }
308
309 mAppBounds.set(left, top, right, bottom);
310 }
311
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700312 /** @see #setAppBounds(Rect) */
Wale Ogunwale822e5122017-07-26 06:02:24 -0700313 public Rect getAppBounds() {
314 return mAppBounds;
315 }
316
Bryce Leef3c6a472017-11-14 14:53:06 -0800317 /** @see #setBounds(Rect) */
318 public Rect getBounds() {
319 return mBounds;
320 }
321
Evan Roskye747c3e2018-10-30 20:06:41 -0700322 public int getRotation() {
323 return mRotation;
324 }
325
326 public void setRotation(int rotation) {
327 mRotation = rotation;
328 }
329
Wale Ogunwale687b4272017-07-27 02:56:23 -0700330 public void setWindowingMode(@WindowingMode int windowingMode) {
331 mWindowingMode = windowingMode;
332 }
333
334 @WindowingMode
335 public int getWindowingMode() {
336 return mWindowingMode;
337 }
338
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800339 /** @hide */
340 public void setDisplayWindowingMode(@WindowingMode int windowingMode) {
341 mDisplayWindowingMode = windowingMode;
342 }
343
Garfield Tan3129b852019-06-24 16:51:20 -0700344 /** @hide */
345 @WindowingMode
346 public int getDisplayWindowingMode() {
347 return mDisplayWindowingMode;
348 }
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800349
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700350 public void setActivityType(@ActivityType int activityType) {
351 if (mActivityType == activityType) {
352 return;
353 }
Wale Ogunwale6cbbc9a2017-09-06 19:01:03 -0700354
355 // Error check within system server that we are not changing activity type which can be
356 // dangerous. It is okay for things to change in the application process as it doesn't
357 // affect how other things is the system is managed.
358 if (isSystem()
359 && mActivityType != ACTIVITY_TYPE_UNDEFINED
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700360 && activityType != ACTIVITY_TYPE_UNDEFINED) {
361 throw new IllegalStateException("Can't change activity type once set: " + this
362 + " activityType=" + activityTypeToString(activityType));
363 }
364 mActivityType = activityType;
365 }
366
367 @ActivityType
368 public int getActivityType() {
369 return mActivityType;
370 }
371
Wale Ogunwale822e5122017-07-26 06:02:24 -0700372 public void setTo(WindowConfiguration other) {
Bryce Leef3c6a472017-11-14 14:53:06 -0800373 setBounds(other.mBounds);
Wale Ogunwale822e5122017-07-26 06:02:24 -0700374 setAppBounds(other.mAppBounds);
Wale Ogunwale687b4272017-07-27 02:56:23 -0700375 setWindowingMode(other.mWindowingMode);
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700376 setActivityType(other.mActivityType);
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900377 setAlwaysOnTop(other.mAlwaysOnTop);
Evan Roskye747c3e2018-10-30 20:06:41 -0700378 setRotation(other.mRotation);
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800379 setDisplayWindowingMode(other.mDisplayWindowingMode);
Wale Ogunwale822e5122017-07-26 06:02:24 -0700380 }
381
Steven Timotiuse597ca12017-09-05 15:46:29 -0700382 /** Set this object to completely undefined.
383 * @hide */
Wale Ogunwale822e5122017-07-26 06:02:24 -0700384 public void unset() {
385 setToDefaults();
386 }
387
Steven Timotiuse597ca12017-09-05 15:46:29 -0700388 /** @hide */
Wale Ogunwale822e5122017-07-26 06:02:24 -0700389 public void setToDefaults() {
390 setAppBounds(null);
Bryce Leef3c6a472017-11-14 14:53:06 -0800391 setBounds(null);
Wale Ogunwale687b4272017-07-27 02:56:23 -0700392 setWindowingMode(WINDOWING_MODE_UNDEFINED);
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700393 setActivityType(ACTIVITY_TYPE_UNDEFINED);
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900394 setAlwaysOnTop(ALWAYS_ON_TOP_UNDEFINED);
Evan Roskye747c3e2018-10-30 20:06:41 -0700395 setRotation(ROTATION_UNDEFINED);
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800396 setDisplayWindowingMode(WINDOWING_MODE_UNDEFINED);
Wale Ogunwale822e5122017-07-26 06:02:24 -0700397 }
398
399 /**
400 * Copies the fields from delta into this Configuration object, keeping
401 * track of which ones have changed. Any undefined fields in {@code delta}
402 * are ignored and not copied in to the current Configuration.
403 *
404 * @return a bit mask of the changed fields, as per {@link #diff}
Steven Timotiuse597ca12017-09-05 15:46:29 -0700405 * @hide
Wale Ogunwale822e5122017-07-26 06:02:24 -0700406 */
407 public @WindowConfig int updateFrom(@NonNull WindowConfiguration delta) {
408 int changed = 0;
Bryce Leef3c6a472017-11-14 14:53:06 -0800409 // Only allow override if bounds is not empty
410 if (!delta.mBounds.isEmpty() && !delta.mBounds.equals(mBounds)) {
411 changed |= WINDOW_CONFIG_BOUNDS;
412 setBounds(delta.mBounds);
413 }
Wale Ogunwale822e5122017-07-26 06:02:24 -0700414 if (delta.mAppBounds != null && !delta.mAppBounds.equals(mAppBounds)) {
415 changed |= WINDOW_CONFIG_APP_BOUNDS;
416 setAppBounds(delta.mAppBounds);
417 }
Wale Ogunwale687b4272017-07-27 02:56:23 -0700418 if (delta.mWindowingMode != WINDOWING_MODE_UNDEFINED
419 && mWindowingMode != delta.mWindowingMode) {
420 changed |= WINDOW_CONFIG_WINDOWING_MODE;
421 setWindowingMode(delta.mWindowingMode);
422 }
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700423 if (delta.mActivityType != ACTIVITY_TYPE_UNDEFINED
424 && mActivityType != delta.mActivityType) {
425 changed |= WINDOW_CONFIG_ACTIVITY_TYPE;
426 setActivityType(delta.mActivityType);
427 }
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900428 if (delta.mAlwaysOnTop != ALWAYS_ON_TOP_UNDEFINED
429 && mAlwaysOnTop != delta.mAlwaysOnTop) {
430 changed |= WINDOW_CONFIG_ALWAYS_ON_TOP;
431 setAlwaysOnTop(delta.mAlwaysOnTop);
432 }
Evan Roskye747c3e2018-10-30 20:06:41 -0700433 if (delta.mRotation != ROTATION_UNDEFINED && delta.mRotation != mRotation) {
434 changed |= WINDOW_CONFIG_ROTATION;
435 setRotation(delta.mRotation);
436 }
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800437 if (delta.mDisplayWindowingMode != WINDOWING_MODE_UNDEFINED
438 && mDisplayWindowingMode != delta.mDisplayWindowingMode) {
439 changed |= WINDOW_CONFIG_DISPLAY_WINDOWING_MODE;
440 setDisplayWindowingMode(delta.mDisplayWindowingMode);
441 }
Wale Ogunwale822e5122017-07-26 06:02:24 -0700442 return changed;
443 }
444
445 /**
Evan Roskyddedfd42019-10-04 13:38:38 -0700446 * Copies the fields specified by mask from delta into this Configuration object.
447 * @hide
448 */
449 public void setTo(@NonNull WindowConfiguration delta, @WindowConfig int mask) {
450 if ((mask & WINDOW_CONFIG_BOUNDS) != 0) {
451 setBounds(delta.mBounds);
452 }
453 if ((mask & WINDOW_CONFIG_APP_BOUNDS) != 0) {
454 setAppBounds(delta.mAppBounds);
455 }
456 if ((mask & WINDOW_CONFIG_WINDOWING_MODE) != 0) {
457 setWindowingMode(delta.mWindowingMode);
458 }
459 if ((mask & WINDOW_CONFIG_ACTIVITY_TYPE) != 0) {
460 setActivityType(delta.mActivityType);
461 }
462 if ((mask & WINDOW_CONFIG_ALWAYS_ON_TOP) != 0) {
463 setAlwaysOnTop(delta.mAlwaysOnTop);
464 }
465 if ((mask & WINDOW_CONFIG_ROTATION) != 0) {
466 setRotation(delta.mRotation);
467 }
468 if ((mask & WINDOW_CONFIG_DISPLAY_WINDOWING_MODE) != 0) {
469 setDisplayWindowingMode(delta.mDisplayWindowingMode);
470 }
471 }
472
473 /**
Wale Ogunwale822e5122017-07-26 06:02:24 -0700474 * Return a bit mask of the differences between this Configuration object and the given one.
475 * Does not change the values of either. Any undefined fields in <var>other</var> are ignored.
476 * @param other The configuration to diff against.
477 * @param compareUndefined If undefined values should be compared.
478 * @return Returns a bit mask indicating which configuration
479 * values has changed, containing any combination of {@link WindowConfig} flags.
480 *
481 * @see Configuration#diff(Configuration)
Steven Timotiuse597ca12017-09-05 15:46:29 -0700482 * @hide
Wale Ogunwale822e5122017-07-26 06:02:24 -0700483 */
484 public @WindowConfig long diff(WindowConfiguration other, boolean compareUndefined) {
485 long changes = 0;
486
Bryce Leef3c6a472017-11-14 14:53:06 -0800487 if (!mBounds.equals(other.mBounds)) {
488 changes |= WINDOW_CONFIG_BOUNDS;
489 }
490
Wale Ogunwale822e5122017-07-26 06:02:24 -0700491 // Make sure that one of the values is not null and that they are not equal.
492 if ((compareUndefined || other.mAppBounds != null)
493 && mAppBounds != other.mAppBounds
494 && (mAppBounds == null || !mAppBounds.equals(other.mAppBounds))) {
495 changes |= WINDOW_CONFIG_APP_BOUNDS;
496 }
497
Wale Ogunwale687b4272017-07-27 02:56:23 -0700498 if ((compareUndefined || other.mWindowingMode != WINDOWING_MODE_UNDEFINED)
499 && mWindowingMode != other.mWindowingMode) {
500 changes |= WINDOW_CONFIG_WINDOWING_MODE;
501 }
502
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700503 if ((compareUndefined || other.mActivityType != ACTIVITY_TYPE_UNDEFINED)
504 && mActivityType != other.mActivityType) {
505 changes |= WINDOW_CONFIG_ACTIVITY_TYPE;
506 }
507
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900508 if ((compareUndefined || other.mAlwaysOnTop != ALWAYS_ON_TOP_UNDEFINED)
509 && mAlwaysOnTop != other.mAlwaysOnTop) {
510 changes |= WINDOW_CONFIG_ALWAYS_ON_TOP;
511 }
512
Evan Roskye747c3e2018-10-30 20:06:41 -0700513 if ((compareUndefined || other.mRotation != ROTATION_UNDEFINED)
514 && mRotation != other.mRotation) {
515 changes |= WINDOW_CONFIG_ROTATION;
516 }
517
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800518 if ((compareUndefined || other.mDisplayWindowingMode != WINDOWING_MODE_UNDEFINED)
519 && mDisplayWindowingMode != other.mDisplayWindowingMode) {
520 changes |= WINDOW_CONFIG_DISPLAY_WINDOWING_MODE;
521 }
522
Wale Ogunwale822e5122017-07-26 06:02:24 -0700523 return changes;
524 }
525
526 @Override
527 public int compareTo(WindowConfiguration that) {
528 int n = 0;
529 if (mAppBounds == null && that.mAppBounds != null) {
530 return 1;
531 } else if (mAppBounds != null && that.mAppBounds == null) {
532 return -1;
533 } else if (mAppBounds != null && that.mAppBounds != null) {
534 n = mAppBounds.left - that.mAppBounds.left;
535 if (n != 0) return n;
536 n = mAppBounds.top - that.mAppBounds.top;
537 if (n != 0) return n;
538 n = mAppBounds.right - that.mAppBounds.right;
539 if (n != 0) return n;
540 n = mAppBounds.bottom - that.mAppBounds.bottom;
541 if (n != 0) return n;
542 }
Bryce Leef3c6a472017-11-14 14:53:06 -0800543
544 n = mBounds.left - that.mBounds.left;
545 if (n != 0) return n;
546 n = mBounds.top - that.mBounds.top;
547 if (n != 0) return n;
548 n = mBounds.right - that.mBounds.right;
549 if (n != 0) return n;
550 n = mBounds.bottom - that.mBounds.bottom;
551 if (n != 0) return n;
552
Wale Ogunwale687b4272017-07-27 02:56:23 -0700553 n = mWindowingMode - that.mWindowingMode;
554 if (n != 0) return n;
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700555 n = mActivityType - that.mActivityType;
556 if (n != 0) return n;
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900557 n = mAlwaysOnTop - that.mAlwaysOnTop;
Kazuki Takise148d00a2018-05-31 15:32:19 +0900558 if (n != 0) return n;
Evan Roskye747c3e2018-10-30 20:06:41 -0700559 n = mRotation - that.mRotation;
560 if (n != 0) return n;
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800561 n = mDisplayWindowingMode - that.mDisplayWindowingMode;
562 if (n != 0) return n;
Kazuki Takise148d00a2018-05-31 15:32:19 +0900563
Wale Ogunwale822e5122017-07-26 06:02:24 -0700564 // if (n != 0) return n;
565 return n;
566 }
567
Steven Timotiuse597ca12017-09-05 15:46:29 -0700568 /** @hide */
Wale Ogunwale822e5122017-07-26 06:02:24 -0700569 @Override
570 public boolean equals(Object that) {
571 if (that == null) return false;
572 if (that == this) return true;
573 if (!(that instanceof WindowConfiguration)) {
574 return false;
575 }
576 return this.compareTo((WindowConfiguration) that) == 0;
577 }
578
Steven Timotiuse597ca12017-09-05 15:46:29 -0700579 /** @hide */
Wale Ogunwale822e5122017-07-26 06:02:24 -0700580 @Override
581 public int hashCode() {
582 int result = 0;
583 if (mAppBounds != null) {
584 result = 31 * result + mAppBounds.hashCode();
585 }
Bryce Leef3c6a472017-11-14 14:53:06 -0800586 result = 31 * result + mBounds.hashCode();
587
Wale Ogunwale687b4272017-07-27 02:56:23 -0700588 result = 31 * result + mWindowingMode;
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700589 result = 31 * result + mActivityType;
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900590 result = 31 * result + mAlwaysOnTop;
Evan Roskye747c3e2018-10-30 20:06:41 -0700591 result = 31 * result + mRotation;
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800592 result = 31 * result + mDisplayWindowingMode;
Wale Ogunwale822e5122017-07-26 06:02:24 -0700593 return result;
594 }
595
Steven Timotiuse597ca12017-09-05 15:46:29 -0700596 /** @hide */
Wale Ogunwale822e5122017-07-26 06:02:24 -0700597 @Override
598 public String toString() {
Bryce Leef3c6a472017-11-14 14:53:06 -0800599 return "{ mBounds=" + mBounds
600 + " mAppBounds=" + mAppBounds
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700601 + " mWindowingMode=" + windowingModeToString(mWindowingMode)
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800602 + " mDisplayWindowingMode=" + windowingModeToString(mDisplayWindowingMode)
Kazuki Takise148d00a2018-05-31 15:32:19 +0900603 + " mActivityType=" + activityTypeToString(mActivityType)
Kazuki Takisef85197b2018-06-18 18:18:36 +0900604 + " mAlwaysOnTop=" + alwaysOnTopToString(mAlwaysOnTop)
Evan Roskye747c3e2018-10-30 20:06:41 -0700605 + " mRotation=" + (mRotation == ROTATION_UNDEFINED
606 ? "undefined" : rotationToString(mRotation))
Kazuki Takise148d00a2018-05-31 15:32:19 +0900607 + "}";
Wale Ogunwale687b4272017-07-27 02:56:23 -0700608 }
609
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700610 /**
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700611 * Write to a protocol buffer output stream.
612 * Protocol buffer message definition at {@link android.app.WindowConfigurationProto}
613 *
614 * @param protoOutputStream Stream to write the WindowConfiguration object to.
615 * @param fieldId Field Id of the WindowConfiguration as defined in the parent message
616 * @hide
617 */
618 public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId) {
619 final long token = protoOutputStream.start(fieldId);
620 if (mAppBounds != null) {
621 mAppBounds.writeToProto(protoOutputStream, APP_BOUNDS);
622 }
623 protoOutputStream.write(WINDOWING_MODE, mWindowingMode);
624 protoOutputStream.write(ACTIVITY_TYPE, mActivityType);
Adrian Roos5f8b52c2018-11-28 16:31:55 +0100625 if (mBounds != null) {
626 mBounds.writeToProto(protoOutputStream, BOUNDS);
627 }
Wale Ogunwale0d5609b2017-09-13 05:55:07 -0700628 protoOutputStream.end(token);
629 }
630
631 /**
Michael Wachenschwanzc8c26362018-09-07 14:59:25 -0700632 * Read from a protocol buffer input stream.
633 * Protocol buffer message definition at {@link android.app.WindowConfigurationProto}
634 *
635 * @param proto Stream to read the WindowConfiguration object from.
636 * @param fieldId Field Id of the WindowConfiguration as defined in the parent message
637 * @hide
638 */
639 public void readFromProto(ProtoInputStream proto, long fieldId)
640 throws IOException, WireTypeMismatchException {
641 final long token = proto.start(fieldId);
642 try {
643 while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
644 switch (proto.getFieldNumber()) {
645 case (int) APP_BOUNDS:
646 mAppBounds = new Rect();
647 mAppBounds.readFromProto(proto, APP_BOUNDS);
648 break;
Adrian Roos5f8b52c2018-11-28 16:31:55 +0100649 case (int) BOUNDS:
650 mBounds = new Rect();
651 mBounds.readFromProto(proto, BOUNDS);
652 break;
Michael Wachenschwanzc8c26362018-09-07 14:59:25 -0700653 case (int) WINDOWING_MODE:
654 mWindowingMode = proto.readInt(WINDOWING_MODE);
655 break;
656 case (int) ACTIVITY_TYPE:
657 mActivityType = proto.readInt(ACTIVITY_TYPE);
658 break;
659 }
660 }
661 } finally {
662 // Let caller handle any exceptions
663 proto.end(token);
664 }
665 }
666
667 /**
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700668 * Returns true if the activities associated with this window configuration display a shadow
669 * around their border.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700670 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700671 */
672 public boolean hasWindowShadow() {
673 return tasksAreFloating();
674 }
675
676 /**
677 * Returns true if the activities associated with this window configuration display a decor
678 * view.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700679 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700680 */
681 public boolean hasWindowDecorCaption() {
Yunfan Chen7daa6ac2018-11-29 18:16:44 -0800682 return mActivityType == ACTIVITY_TYPE_STANDARD && (mWindowingMode == WINDOWING_MODE_FREEFORM
683 || mDisplayWindowingMode == WINDOWING_MODE_FREEFORM);
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700684 }
685
686 /**
687 * Returns true if the tasks associated with this window configuration can be resized
688 * independently of their parent container.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700689 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700690 */
691 public boolean canResizeTask() {
692 return mWindowingMode == WINDOWING_MODE_FREEFORM;
693 }
694
Steven Timotiuse597ca12017-09-05 15:46:29 -0700695 /** Returns true if the task bounds should persist across power cycles.
696 * @hide */
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700697 public boolean persistTaskBounds() {
698 return mWindowingMode == WINDOWING_MODE_FREEFORM;
699 }
700
701 /**
702 * Returns true if the tasks associated with this window configuration are floating.
703 * Floating tasks are laid out differently as they are allowed to extend past the display bounds
704 * without overscan insets.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700705 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700706 */
707 public boolean tasksAreFloating() {
Evan Roskyb0e38882018-04-25 12:48:54 -0700708 return isFloating(mWindowingMode);
709 }
710
711 /**
712 * Returns true if the windowingMode represents a floating window.
713 * @hide
714 */
715 public static boolean isFloating(int windowingMode) {
716 return windowingMode == WINDOWING_MODE_FREEFORM || windowingMode == WINDOWING_MODE_PINNED;
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700717 }
718
719 /**
Evan Rosky1ac84462018-11-13 11:25:30 -0800720 * Returns true if the windowingMode represents a split window.
721 * @hide
722 */
723 public static boolean isSplitScreenWindowingMode(int windowingMode) {
724 return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
725 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
726 }
727
728 /**
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700729 * Returns true if the windows associated with this window configuration can receive input keys.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700730 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700731 */
732 public boolean canReceiveKeys() {
733 return mWindowingMode != WINDOWING_MODE_PINNED;
734 }
735
736 /**
737 * Returns true if the container associated with this window configuration is always-on-top of
738 * its siblings.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700739 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700740 */
741 public boolean isAlwaysOnTop() {
Kazuki Takise048e2662018-06-27 17:05:11 +0900742 return mWindowingMode == WINDOWING_MODE_PINNED
743 || (mWindowingMode == WINDOWING_MODE_FREEFORM && mAlwaysOnTop == ALWAYS_ON_TOP_ON);
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700744 }
745
746 /**
747 * Returns true if any visible windows belonging to apps with this window configuration should
748 * be kept on screen when the app is killed due to something like the low memory killer.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700749 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700750 */
751 public boolean keepVisibleDeadAppWindowOnScreen() {
752 return mWindowingMode != WINDOWING_MODE_PINNED;
753 }
754
755 /**
756 * Returns true if the backdrop on the client side should match the frame of the window.
757 * Returns false, if the backdrop should be fullscreen.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700758 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700759 */
760 public boolean useWindowFrameForBackdrop() {
761 return mWindowingMode == WINDOWING_MODE_FREEFORM || mWindowingMode == WINDOWING_MODE_PINNED;
762 }
763
764 /**
765 * Returns true if this container may be scaled without resizing, and windows within may need
766 * to be configured as such.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700767 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700768 */
769 public boolean windowsAreScaleable() {
770 return mWindowingMode == WINDOWING_MODE_PINNED;
771 }
772
773 /**
774 * Returns true if windows in this container should be given move animations by default.
Steven Timotiuse597ca12017-09-05 15:46:29 -0700775 * @hide
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700776 */
777 public boolean hasMovementAnimations() {
Jorim Jaggibb6ee9b2017-09-06 23:59:34 +0200778 return mWindowingMode != WINDOWING_MODE_PINNED;
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700779 }
780
Wale Ogunwale926aade2017-08-29 11:24:37 -0700781 /**
782 * Returns true if this container can be put in either
783 * {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} or
784 * {@link #WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} windowing modes based on its current state.
785 * @hide
786 */
787 public boolean supportSplitScreenWindowingMode() {
Wale Ogunwale2b07da82017-11-08 14:52:40 -0800788 return supportSplitScreenWindowingMode(mActivityType);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700789 }
790
791 /** @hide */
Wale Ogunwale2b07da82017-11-08 14:52:40 -0800792 public static boolean supportSplitScreenWindowingMode(int activityType) {
793 return activityType != ACTIVITY_TYPE_ASSISTANT;
Wale Ogunwale926aade2017-08-29 11:24:37 -0700794 }
795
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700796 /** @hide */
797 public static String windowingModeToString(@WindowingMode int windowingMode) {
Wale Ogunwale687b4272017-07-27 02:56:23 -0700798 switch (windowingMode) {
799 case WINDOWING_MODE_UNDEFINED: return "undefined";
800 case WINDOWING_MODE_FULLSCREEN: return "fullscreen";
801 case WINDOWING_MODE_PINNED: return "pinned";
Wale Ogunwale926aade2017-08-29 11:24:37 -0700802 case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return "split-screen-primary";
803 case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: return "split-screen-secondary";
Wale Ogunwale687b4272017-07-27 02:56:23 -0700804 case WINDOWING_MODE_FREEFORM: return "freeform";
805 }
806 return String.valueOf(windowingMode);
Wale Ogunwale822e5122017-07-26 06:02:24 -0700807 }
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700808
Steven Timotiuse597ca12017-09-05 15:46:29 -0700809 /** @hide */
Wale Ogunwale6fbde9f2017-08-24 07:24:12 -0700810 public static String activityTypeToString(@ActivityType int applicationType) {
811 switch (applicationType) {
812 case ACTIVITY_TYPE_UNDEFINED: return "undefined";
813 case ACTIVITY_TYPE_STANDARD: return "standard";
814 case ACTIVITY_TYPE_HOME: return "home";
815 case ACTIVITY_TYPE_RECENTS: return "recents";
816 case ACTIVITY_TYPE_ASSISTANT: return "assistant";
817 }
818 return String.valueOf(applicationType);
819 }
Kazuki Takisef85197b2018-06-18 18:18:36 +0900820
821 /** @hide */
822 public static String alwaysOnTopToString(@AlwaysOnTop int alwaysOnTop) {
823 switch (alwaysOnTop) {
824 case ALWAYS_ON_TOP_UNDEFINED: return "undefined";
825 case ALWAYS_ON_TOP_ON: return "on";
826 case ALWAYS_ON_TOP_OFF: return "off";
827 }
828 return String.valueOf(alwaysOnTop);
829 }
Wale Ogunwale822e5122017-07-26 06:02:24 -0700830}