1 /* 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 17 package android.app; 18 19 import static android.app.ActivityThread.isSystem; 20 import static android.app.WindowConfigurationProto.ACTIVITY_TYPE; 21 import static android.app.WindowConfigurationProto.APP_BOUNDS; 22 import static android.app.WindowConfigurationProto.BOUNDS; 23 import static android.app.WindowConfigurationProto.WINDOWING_MODE; 24 import static android.view.Surface.rotationToString; 25 26 import android.annotation.IntDef; 27 import android.annotation.NonNull; 28 import android.annotation.TestApi; 29 import android.compat.annotation.UnsupportedAppUsage; 30 import android.content.res.Configuration; 31 import android.graphics.Rect; 32 import android.os.Parcel; 33 import android.os.Parcelable; 34 import android.util.proto.ProtoInputStream; 35 import android.util.proto.ProtoOutputStream; 36 import android.util.proto.WireTypeMismatchException; 37 import android.view.DisplayInfo; 38 39 import java.io.IOException; 40 41 /** 42 * Class that contains windowing configuration/state for other objects that contain windows directly 43 * or indirectly. E.g. Activities, Task, Displays, ... 44 * The test class is {@link com.android.server.wm.WindowConfigurationTests} which must be kept 45 * up-to-date and ran anytime changes are made to this class. 46 * @hide 47 */ 48 @TestApi 49 public class WindowConfiguration implements Parcelable, Comparable<WindowConfiguration> { 50 /** 51 * bounds that can differ from app bounds, which may include things such as insets. 52 * 53 * TODO: Investigate combining with {@link mAppBounds}. Can the latter be a product of the 54 * former? 55 */ 56 private Rect mBounds = new Rect(); 57 58 /** 59 * {@link android.graphics.Rect} defining app bounds. The dimensions override usages of 60 * {@link DisplayInfo#appHeight} and {@link DisplayInfo#appWidth} and mirrors these values at 61 * the display level. Lower levels can override these values to provide custom bounds to enforce 62 * features such as a max aspect ratio. 63 */ 64 private Rect mAppBounds; 65 66 /** 67 * The current rotation of this window container relative to the default 68 * orientation of the display it is on (regardless of how deep in the hierarchy 69 * it is). It is used by the configuration hierarchy to apply rotation-dependent 70 * policy during bounds calculation. 71 */ 72 private int mRotation = ROTATION_UNDEFINED; 73 74 /** Rotation is not defined, use the parent containers rotation. */ 75 public static final int ROTATION_UNDEFINED = -1; 76 77 /** The current windowing mode of the configuration. */ 78 private @WindowingMode int mWindowingMode; 79 80 /** The display windowing mode of the configuration */ 81 private @WindowingMode int mDisplayWindowingMode; 82 83 /** Windowing mode is currently not defined. */ 84 public static final int WINDOWING_MODE_UNDEFINED = 0; 85 /** Occupies the full area of the screen or the parent container. */ 86 public static final int WINDOWING_MODE_FULLSCREEN = 1; 87 /** Always on-top (always visible). of other siblings in its parent container. */ 88 public static final int WINDOWING_MODE_PINNED = 2; 89 /** The primary container driving the screen to be in split-screen mode. */ 90 public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3; 91 /** 92 * The containers adjacent to the {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} container in 93 * split-screen mode. 94 * NOTE: Containers launched with the windowing mode with APIs like 95 * {@link ActivityOptions#setLaunchWindowingMode(int)} will be launched in 96 * {@link #WINDOWING_MODE_FULLSCREEN} if the display isn't currently in split-screen windowing 97 * mode 98 * @see #WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY 99 */ 100 public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4; 101 /** 102 * Alias for {@link #WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} that makes it clear that the usage 103 * points for APIs like {@link ActivityOptions#setLaunchWindowingMode(int)} that the container 104 * will launch into fullscreen or split-screen secondary depending on if the device is currently 105 * in fullscreen mode or split-screen mode. 106 */ 107 public static final int WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY = 108 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 109 /** Can be freely resized within its parent container. */ 110 public static final int WINDOWING_MODE_FREEFORM = 5; 111 112 /** @hide */ 113 @IntDef(prefix = { "WINDOWING_MODE_" }, value = { 114 WINDOWING_MODE_UNDEFINED, 115 WINDOWING_MODE_FULLSCREEN, 116 WINDOWING_MODE_PINNED, 117 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, 118 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, 119 WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, 120 WINDOWING_MODE_FREEFORM, 121 }) 122 public @interface WindowingMode {} 123 124 /** The current activity type of the configuration. */ 125 private @ActivityType int mActivityType; 126 127 /** Activity type is currently not defined. */ 128 public static final int ACTIVITY_TYPE_UNDEFINED = 0; 129 /** Standard activity type. Nothing special about the activity... */ 130 public static final int ACTIVITY_TYPE_STANDARD = 1; 131 /** Home/Launcher activity type. */ 132 public static final int ACTIVITY_TYPE_HOME = 2; 133 /** Recents/Overview activity type. There is only one activity with this type in the system. */ 134 public static final int ACTIVITY_TYPE_RECENTS = 3; 135 /** Assistant activity type. */ 136 public static final int ACTIVITY_TYPE_ASSISTANT = 4; 137 138 /** @hide */ 139 @IntDef(prefix = { "ACTIVITY_TYPE_" }, value = { 140 ACTIVITY_TYPE_UNDEFINED, 141 ACTIVITY_TYPE_STANDARD, 142 ACTIVITY_TYPE_HOME, 143 ACTIVITY_TYPE_RECENTS, 144 ACTIVITY_TYPE_ASSISTANT, 145 }) 146 public @interface ActivityType {} 147 148 /** The current always on top status of the configuration. */ 149 private @AlwaysOnTop int mAlwaysOnTop; 150 151 /** Always on top is currently not defined. */ 152 private static final int ALWAYS_ON_TOP_UNDEFINED = 0; 153 /** Always on top is currently on for this configuration. */ 154 private static final int ALWAYS_ON_TOP_ON = 1; 155 /** Always on top is currently off for this configuration. */ 156 private static final int ALWAYS_ON_TOP_OFF = 2; 157 158 /** @hide */ 159 @IntDef(prefix = { "ALWAYS_ON_TOP_" }, value = { 160 ALWAYS_ON_TOP_UNDEFINED, 161 ALWAYS_ON_TOP_ON, 162 ALWAYS_ON_TOP_OFF, 163 }) 164 private @interface AlwaysOnTop {} 165 166 /** Bit that indicates that the {@link #mBounds} changed. 167 * @hide */ 168 public static final int WINDOW_CONFIG_BOUNDS = 1 << 0; 169 /** Bit that indicates that the {@link #mAppBounds} changed. 170 * @hide */ 171 public static final int WINDOW_CONFIG_APP_BOUNDS = 1 << 1; 172 /** Bit that indicates that the {@link #mWindowingMode} changed. 173 * @hide */ 174 public static final int WINDOW_CONFIG_WINDOWING_MODE = 1 << 2; 175 /** Bit that indicates that the {@link #mActivityType} changed. 176 * @hide */ 177 public static final int WINDOW_CONFIG_ACTIVITY_TYPE = 1 << 3; 178 /** Bit that indicates that the {@link #mAlwaysOnTop} changed. 179 * @hide */ 180 public static final int WINDOW_CONFIG_ALWAYS_ON_TOP = 1 << 4; 181 /** Bit that indicates that the {@link #mRotation} changed. 182 * @hide */ 183 public static final int WINDOW_CONFIG_ROTATION = 1 << 5; 184 /** Bit that indicates that the {@link #mDisplayWindowingMode} changed. 185 * @hide */ 186 public static final int WINDOW_CONFIG_DISPLAY_WINDOWING_MODE = 1 << 6; 187 188 /** @hide */ 189 @IntDef(flag = true, prefix = { "WINDOW_CONFIG_" }, value = { 190 WINDOW_CONFIG_BOUNDS, 191 WINDOW_CONFIG_APP_BOUNDS, 192 WINDOW_CONFIG_WINDOWING_MODE, 193 WINDOW_CONFIG_ACTIVITY_TYPE, 194 WINDOW_CONFIG_ALWAYS_ON_TOP, 195 WINDOW_CONFIG_ROTATION, 196 WINDOW_CONFIG_DISPLAY_WINDOWING_MODE, 197 }) 198 public @interface WindowConfig {} 199 200 /** @hide */ 201 public static final int PINNED_WINDOWING_MODE_ELEVATION_IN_DIP = 5; 202 203 @UnsupportedAppUsage WindowConfiguration()204 public WindowConfiguration() { 205 unset(); 206 } 207 208 /** @hide */ WindowConfiguration(WindowConfiguration configuration)209 public WindowConfiguration(WindowConfiguration configuration) { 210 setTo(configuration); 211 } 212 WindowConfiguration(Parcel in)213 private WindowConfiguration(Parcel in) { 214 readFromParcel(in); 215 } 216 217 @Override writeToParcel(Parcel dest, int flags)218 public void writeToParcel(Parcel dest, int flags) { 219 dest.writeParcelable(mBounds, flags); 220 dest.writeParcelable(mAppBounds, flags); 221 dest.writeInt(mWindowingMode); 222 dest.writeInt(mActivityType); 223 dest.writeInt(mAlwaysOnTop); 224 dest.writeInt(mRotation); 225 dest.writeInt(mDisplayWindowingMode); 226 } 227 readFromParcel(Parcel source)228 private void readFromParcel(Parcel source) { 229 mBounds = source.readParcelable(Rect.class.getClassLoader()); 230 mAppBounds = source.readParcelable(Rect.class.getClassLoader()); 231 mWindowingMode = source.readInt(); 232 mActivityType = source.readInt(); 233 mAlwaysOnTop = source.readInt(); 234 mRotation = source.readInt(); 235 mDisplayWindowingMode = source.readInt(); 236 } 237 238 @Override describeContents()239 public int describeContents() { 240 return 0; 241 } 242 243 /** @hide */ 244 public static final @android.annotation.NonNull Creator<WindowConfiguration> CREATOR = new Creator<WindowConfiguration>() { 245 @Override 246 public WindowConfiguration createFromParcel(Parcel in) { 247 return new WindowConfiguration(in); 248 } 249 250 @Override 251 public WindowConfiguration[] newArray(int size) { 252 return new WindowConfiguration[size]; 253 } 254 }; 255 256 /** 257 * Sets the bounds to the provided {@link Rect}. 258 * @param rect the new bounds value. 259 */ setBounds(Rect rect)260 public void setBounds(Rect rect) { 261 if (rect == null) { 262 mBounds.setEmpty(); 263 return; 264 } 265 266 mBounds.set(rect); 267 } 268 269 /** 270 * Set {@link #mAppBounds} to the input Rect. 271 * @param rect The rect value to set {@link #mAppBounds} to. 272 * @see #getAppBounds() 273 */ setAppBounds(Rect rect)274 public void setAppBounds(Rect rect) { 275 if (rect == null) { 276 mAppBounds = null; 277 return; 278 } 279 280 setAppBounds(rect.left, rect.top, rect.right, rect.bottom); 281 } 282 283 284 285 /** 286 * Sets whether this window should be always on top. 287 * @param alwaysOnTop {@code true} to set window always on top, otherwise {@code false} 288 * @hide 289 */ setAlwaysOnTop(boolean alwaysOnTop)290 public void setAlwaysOnTop(boolean alwaysOnTop) { 291 mAlwaysOnTop = alwaysOnTop ? ALWAYS_ON_TOP_ON : ALWAYS_ON_TOP_OFF; 292 } 293 setAlwaysOnTop(@lwaysOnTop int alwaysOnTop)294 private void setAlwaysOnTop(@AlwaysOnTop int alwaysOnTop) { 295 mAlwaysOnTop = alwaysOnTop; 296 } 297 298 /** 299 * @see #setAppBounds(Rect) 300 * @see #getAppBounds() 301 * @hide 302 */ setAppBounds(int left, int top, int right, int bottom)303 public void setAppBounds(int left, int top, int right, int bottom) { 304 if (mAppBounds == null) { 305 mAppBounds = new Rect(); 306 } 307 308 mAppBounds.set(left, top, right, bottom); 309 } 310 311 /** @see #setAppBounds(Rect) */ getAppBounds()312 public Rect getAppBounds() { 313 return mAppBounds; 314 } 315 316 /** @see #setBounds(Rect) */ getBounds()317 public Rect getBounds() { 318 return mBounds; 319 } 320 getRotation()321 public int getRotation() { 322 return mRotation; 323 } 324 setRotation(int rotation)325 public void setRotation(int rotation) { 326 mRotation = rotation; 327 } 328 setWindowingMode(@indowingMode int windowingMode)329 public void setWindowingMode(@WindowingMode int windowingMode) { 330 mWindowingMode = windowingMode; 331 } 332 333 @WindowingMode getWindowingMode()334 public int getWindowingMode() { 335 return mWindowingMode; 336 } 337 338 /** @hide */ setDisplayWindowingMode(@indowingMode int windowingMode)339 public void setDisplayWindowingMode(@WindowingMode int windowingMode) { 340 mDisplayWindowingMode = windowingMode; 341 } 342 343 setActivityType(@ctivityType int activityType)344 public void setActivityType(@ActivityType int activityType) { 345 if (mActivityType == activityType) { 346 return; 347 } 348 349 // Error check within system server that we are not changing activity type which can be 350 // dangerous. It is okay for things to change in the application process as it doesn't 351 // affect how other things is the system is managed. 352 if (isSystem() 353 && mActivityType != ACTIVITY_TYPE_UNDEFINED 354 && activityType != ACTIVITY_TYPE_UNDEFINED) { 355 throw new IllegalStateException("Can't change activity type once set: " + this 356 + " activityType=" + activityTypeToString(activityType)); 357 } 358 mActivityType = activityType; 359 } 360 361 @ActivityType getActivityType()362 public int getActivityType() { 363 return mActivityType; 364 } 365 setTo(WindowConfiguration other)366 public void setTo(WindowConfiguration other) { 367 setBounds(other.mBounds); 368 setAppBounds(other.mAppBounds); 369 setWindowingMode(other.mWindowingMode); 370 setActivityType(other.mActivityType); 371 setAlwaysOnTop(other.mAlwaysOnTop); 372 setRotation(other.mRotation); 373 setDisplayWindowingMode(other.mDisplayWindowingMode); 374 } 375 376 /** Set this object to completely undefined. 377 * @hide */ unset()378 public void unset() { 379 setToDefaults(); 380 } 381 382 /** @hide */ setToDefaults()383 public void setToDefaults() { 384 setAppBounds(null); 385 setBounds(null); 386 setWindowingMode(WINDOWING_MODE_UNDEFINED); 387 setActivityType(ACTIVITY_TYPE_UNDEFINED); 388 setAlwaysOnTop(ALWAYS_ON_TOP_UNDEFINED); 389 setRotation(ROTATION_UNDEFINED); 390 setDisplayWindowingMode(WINDOWING_MODE_UNDEFINED); 391 } 392 393 /** 394 * Copies the fields from delta into this Configuration object, keeping 395 * track of which ones have changed. Any undefined fields in {@code delta} 396 * are ignored and not copied in to the current Configuration. 397 * 398 * @return a bit mask of the changed fields, as per {@link #diff} 399 * @hide 400 */ updateFrom(@onNull WindowConfiguration delta)401 public @WindowConfig int updateFrom(@NonNull WindowConfiguration delta) { 402 int changed = 0; 403 // Only allow override if bounds is not empty 404 if (!delta.mBounds.isEmpty() && !delta.mBounds.equals(mBounds)) { 405 changed |= WINDOW_CONFIG_BOUNDS; 406 setBounds(delta.mBounds); 407 } 408 if (delta.mAppBounds != null && !delta.mAppBounds.equals(mAppBounds)) { 409 changed |= WINDOW_CONFIG_APP_BOUNDS; 410 setAppBounds(delta.mAppBounds); 411 } 412 if (delta.mWindowingMode != WINDOWING_MODE_UNDEFINED 413 && mWindowingMode != delta.mWindowingMode) { 414 changed |= WINDOW_CONFIG_WINDOWING_MODE; 415 setWindowingMode(delta.mWindowingMode); 416 } 417 if (delta.mActivityType != ACTIVITY_TYPE_UNDEFINED 418 && mActivityType != delta.mActivityType) { 419 changed |= WINDOW_CONFIG_ACTIVITY_TYPE; 420 setActivityType(delta.mActivityType); 421 } 422 if (delta.mAlwaysOnTop != ALWAYS_ON_TOP_UNDEFINED 423 && mAlwaysOnTop != delta.mAlwaysOnTop) { 424 changed |= WINDOW_CONFIG_ALWAYS_ON_TOP; 425 setAlwaysOnTop(delta.mAlwaysOnTop); 426 } 427 if (delta.mRotation != ROTATION_UNDEFINED && delta.mRotation != mRotation) { 428 changed |= WINDOW_CONFIG_ROTATION; 429 setRotation(delta.mRotation); 430 } 431 if (delta.mDisplayWindowingMode != WINDOWING_MODE_UNDEFINED 432 && mDisplayWindowingMode != delta.mDisplayWindowingMode) { 433 changed |= WINDOW_CONFIG_DISPLAY_WINDOWING_MODE; 434 setDisplayWindowingMode(delta.mDisplayWindowingMode); 435 } 436 return changed; 437 } 438 439 /** 440 * Return a bit mask of the differences between this Configuration object and the given one. 441 * Does not change the values of either. Any undefined fields in <var>other</var> are ignored. 442 * @param other The configuration to diff against. 443 * @param compareUndefined If undefined values should be compared. 444 * @return Returns a bit mask indicating which configuration 445 * values has changed, containing any combination of {@link WindowConfig} flags. 446 * 447 * @see Configuration#diff(Configuration) 448 * @hide 449 */ diff(WindowConfiguration other, boolean compareUndefined)450 public @WindowConfig long diff(WindowConfiguration other, boolean compareUndefined) { 451 long changes = 0; 452 453 if (!mBounds.equals(other.mBounds)) { 454 changes |= WINDOW_CONFIG_BOUNDS; 455 } 456 457 // Make sure that one of the values is not null and that they are not equal. 458 if ((compareUndefined || other.mAppBounds != null) 459 && mAppBounds != other.mAppBounds 460 && (mAppBounds == null || !mAppBounds.equals(other.mAppBounds))) { 461 changes |= WINDOW_CONFIG_APP_BOUNDS; 462 } 463 464 if ((compareUndefined || other.mWindowingMode != WINDOWING_MODE_UNDEFINED) 465 && mWindowingMode != other.mWindowingMode) { 466 changes |= WINDOW_CONFIG_WINDOWING_MODE; 467 } 468 469 if ((compareUndefined || other.mActivityType != ACTIVITY_TYPE_UNDEFINED) 470 && mActivityType != other.mActivityType) { 471 changes |= WINDOW_CONFIG_ACTIVITY_TYPE; 472 } 473 474 if ((compareUndefined || other.mAlwaysOnTop != ALWAYS_ON_TOP_UNDEFINED) 475 && mAlwaysOnTop != other.mAlwaysOnTop) { 476 changes |= WINDOW_CONFIG_ALWAYS_ON_TOP; 477 } 478 479 if ((compareUndefined || other.mRotation != ROTATION_UNDEFINED) 480 && mRotation != other.mRotation) { 481 changes |= WINDOW_CONFIG_ROTATION; 482 } 483 484 if ((compareUndefined || other.mDisplayWindowingMode != WINDOWING_MODE_UNDEFINED) 485 && mDisplayWindowingMode != other.mDisplayWindowingMode) { 486 changes |= WINDOW_CONFIG_DISPLAY_WINDOWING_MODE; 487 } 488 489 return changes; 490 } 491 492 @Override compareTo(WindowConfiguration that)493 public int compareTo(WindowConfiguration that) { 494 int n = 0; 495 if (mAppBounds == null && that.mAppBounds != null) { 496 return 1; 497 } else if (mAppBounds != null && that.mAppBounds == null) { 498 return -1; 499 } else if (mAppBounds != null && that.mAppBounds != null) { 500 n = mAppBounds.left - that.mAppBounds.left; 501 if (n != 0) return n; 502 n = mAppBounds.top - that.mAppBounds.top; 503 if (n != 0) return n; 504 n = mAppBounds.right - that.mAppBounds.right; 505 if (n != 0) return n; 506 n = mAppBounds.bottom - that.mAppBounds.bottom; 507 if (n != 0) return n; 508 } 509 510 n = mBounds.left - that.mBounds.left; 511 if (n != 0) return n; 512 n = mBounds.top - that.mBounds.top; 513 if (n != 0) return n; 514 n = mBounds.right - that.mBounds.right; 515 if (n != 0) return n; 516 n = mBounds.bottom - that.mBounds.bottom; 517 if (n != 0) return n; 518 519 n = mWindowingMode - that.mWindowingMode; 520 if (n != 0) return n; 521 n = mActivityType - that.mActivityType; 522 if (n != 0) return n; 523 n = mAlwaysOnTop - that.mAlwaysOnTop; 524 if (n != 0) return n; 525 n = mRotation - that.mRotation; 526 if (n != 0) return n; 527 n = mDisplayWindowingMode - that.mDisplayWindowingMode; 528 if (n != 0) return n; 529 530 // if (n != 0) return n; 531 return n; 532 } 533 534 /** @hide */ 535 @Override equals(Object that)536 public boolean equals(Object that) { 537 if (that == null) return false; 538 if (that == this) return true; 539 if (!(that instanceof WindowConfiguration)) { 540 return false; 541 } 542 return this.compareTo((WindowConfiguration) that) == 0; 543 } 544 545 /** @hide */ 546 @Override hashCode()547 public int hashCode() { 548 int result = 0; 549 if (mAppBounds != null) { 550 result = 31 * result + mAppBounds.hashCode(); 551 } 552 result = 31 * result + mBounds.hashCode(); 553 554 result = 31 * result + mWindowingMode; 555 result = 31 * result + mActivityType; 556 result = 31 * result + mAlwaysOnTop; 557 result = 31 * result + mRotation; 558 result = 31 * result + mDisplayWindowingMode; 559 return result; 560 } 561 562 /** @hide */ 563 @Override toString()564 public String toString() { 565 return "{ mBounds=" + mBounds 566 + " mAppBounds=" + mAppBounds 567 + " mWindowingMode=" + windowingModeToString(mWindowingMode) 568 + " mDisplayWindowingMode=" + windowingModeToString(mDisplayWindowingMode) 569 + " mActivityType=" + activityTypeToString(mActivityType) 570 + " mAlwaysOnTop=" + alwaysOnTopToString(mAlwaysOnTop) 571 + " mRotation=" + (mRotation == ROTATION_UNDEFINED 572 ? "undefined" : rotationToString(mRotation)) 573 + "}"; 574 } 575 576 /** 577 * Write to a protocol buffer output stream. 578 * Protocol buffer message definition at {@link android.app.WindowConfigurationProto} 579 * 580 * @param protoOutputStream Stream to write the WindowConfiguration object to. 581 * @param fieldId Field Id of the WindowConfiguration as defined in the parent message 582 * @hide 583 */ writeToProto(ProtoOutputStream protoOutputStream, long fieldId)584 public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId) { 585 final long token = protoOutputStream.start(fieldId); 586 if (mAppBounds != null) { 587 mAppBounds.writeToProto(protoOutputStream, APP_BOUNDS); 588 } 589 protoOutputStream.write(WINDOWING_MODE, mWindowingMode); 590 protoOutputStream.write(ACTIVITY_TYPE, mActivityType); 591 if (mBounds != null) { 592 mBounds.writeToProto(protoOutputStream, BOUNDS); 593 } 594 protoOutputStream.end(token); 595 } 596 597 /** 598 * Read from a protocol buffer input stream. 599 * Protocol buffer message definition at {@link android.app.WindowConfigurationProto} 600 * 601 * @param proto Stream to read the WindowConfiguration object from. 602 * @param fieldId Field Id of the WindowConfiguration as defined in the parent message 603 * @hide 604 */ readFromProto(ProtoInputStream proto, long fieldId)605 public void readFromProto(ProtoInputStream proto, long fieldId) 606 throws IOException, WireTypeMismatchException { 607 final long token = proto.start(fieldId); 608 try { 609 while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) { 610 switch (proto.getFieldNumber()) { 611 case (int) APP_BOUNDS: 612 mAppBounds = new Rect(); 613 mAppBounds.readFromProto(proto, APP_BOUNDS); 614 break; 615 case (int) BOUNDS: 616 mBounds = new Rect(); 617 mBounds.readFromProto(proto, BOUNDS); 618 break; 619 case (int) WINDOWING_MODE: 620 mWindowingMode = proto.readInt(WINDOWING_MODE); 621 break; 622 case (int) ACTIVITY_TYPE: 623 mActivityType = proto.readInt(ACTIVITY_TYPE); 624 break; 625 } 626 } 627 } finally { 628 // Let caller handle any exceptions 629 proto.end(token); 630 } 631 } 632 633 /** 634 * Returns true if the activities associated with this window configuration display a shadow 635 * around their border. 636 * @hide 637 */ hasWindowShadow()638 public boolean hasWindowShadow() { 639 return tasksAreFloating(); 640 } 641 642 /** 643 * Returns true if the activities associated with this window configuration display a decor 644 * view. 645 * @hide 646 */ hasWindowDecorCaption()647 public boolean hasWindowDecorCaption() { 648 return mActivityType == ACTIVITY_TYPE_STANDARD && (mWindowingMode == WINDOWING_MODE_FREEFORM 649 || mDisplayWindowingMode == WINDOWING_MODE_FREEFORM); 650 } 651 652 /** 653 * Returns true if the tasks associated with this window configuration can be resized 654 * independently of their parent container. 655 * @hide 656 */ canResizeTask()657 public boolean canResizeTask() { 658 return mWindowingMode == WINDOWING_MODE_FREEFORM; 659 } 660 661 /** Returns true if the task bounds should persist across power cycles. 662 * @hide */ persistTaskBounds()663 public boolean persistTaskBounds() { 664 return mWindowingMode == WINDOWING_MODE_FREEFORM; 665 } 666 667 /** 668 * Returns true if the tasks associated with this window configuration are floating. 669 * Floating tasks are laid out differently as they are allowed to extend past the display bounds 670 * without overscan insets. 671 * @hide 672 */ tasksAreFloating()673 public boolean tasksAreFloating() { 674 return isFloating(mWindowingMode); 675 } 676 677 /** 678 * Returns true if the windowingMode represents a floating window. 679 * @hide 680 */ isFloating(int windowingMode)681 public static boolean isFloating(int windowingMode) { 682 return windowingMode == WINDOWING_MODE_FREEFORM || windowingMode == WINDOWING_MODE_PINNED; 683 } 684 685 /** 686 * Returns true if the windowingMode represents a split window. 687 * @hide 688 */ isSplitScreenWindowingMode(int windowingMode)689 public static boolean isSplitScreenWindowingMode(int windowingMode) { 690 return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY 691 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 692 } 693 694 /** 695 * Returns true if the windows associated with this window configuration can receive input keys. 696 * @hide 697 */ canReceiveKeys()698 public boolean canReceiveKeys() { 699 return mWindowingMode != WINDOWING_MODE_PINNED; 700 } 701 702 /** 703 * Returns true if the container associated with this window configuration is always-on-top of 704 * its siblings. 705 * @hide 706 */ isAlwaysOnTop()707 public boolean isAlwaysOnTop() { 708 return mWindowingMode == WINDOWING_MODE_PINNED 709 || (mWindowingMode == WINDOWING_MODE_FREEFORM && mAlwaysOnTop == ALWAYS_ON_TOP_ON); 710 } 711 712 /** 713 * Returns true if any visible windows belonging to apps with this window configuration should 714 * be kept on screen when the app is killed due to something like the low memory killer. 715 * @hide 716 */ keepVisibleDeadAppWindowOnScreen()717 public boolean keepVisibleDeadAppWindowOnScreen() { 718 return mWindowingMode != WINDOWING_MODE_PINNED; 719 } 720 721 /** 722 * Returns true if the backdrop on the client side should match the frame of the window. 723 * Returns false, if the backdrop should be fullscreen. 724 * @hide 725 */ useWindowFrameForBackdrop()726 public boolean useWindowFrameForBackdrop() { 727 return mWindowingMode == WINDOWING_MODE_FREEFORM || mWindowingMode == WINDOWING_MODE_PINNED; 728 } 729 730 /** 731 * Returns true if this container may be scaled without resizing, and windows within may need 732 * to be configured as such. 733 * @hide 734 */ windowsAreScaleable()735 public boolean windowsAreScaleable() { 736 return mWindowingMode == WINDOWING_MODE_PINNED; 737 } 738 739 /** 740 * Returns true if windows in this container should be given move animations by default. 741 * @hide 742 */ hasMovementAnimations()743 public boolean hasMovementAnimations() { 744 return mWindowingMode != WINDOWING_MODE_PINNED; 745 } 746 747 /** 748 * Returns true if this container can be put in either 749 * {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} or 750 * {@link #WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} windowing modes based on its current state. 751 * @hide 752 */ supportSplitScreenWindowingMode()753 public boolean supportSplitScreenWindowingMode() { 754 return supportSplitScreenWindowingMode(mActivityType); 755 } 756 757 /** @hide */ supportSplitScreenWindowingMode(int activityType)758 public static boolean supportSplitScreenWindowingMode(int activityType) { 759 return activityType != ACTIVITY_TYPE_ASSISTANT; 760 } 761 762 /** @hide */ windowingModeToString(@indowingMode int windowingMode)763 public static String windowingModeToString(@WindowingMode int windowingMode) { 764 switch (windowingMode) { 765 case WINDOWING_MODE_UNDEFINED: return "undefined"; 766 case WINDOWING_MODE_FULLSCREEN: return "fullscreen"; 767 case WINDOWING_MODE_PINNED: return "pinned"; 768 case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return "split-screen-primary"; 769 case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: return "split-screen-secondary"; 770 case WINDOWING_MODE_FREEFORM: return "freeform"; 771 } 772 return String.valueOf(windowingMode); 773 } 774 775 /** @hide */ activityTypeToString(@ctivityType int applicationType)776 public static String activityTypeToString(@ActivityType int applicationType) { 777 switch (applicationType) { 778 case ACTIVITY_TYPE_UNDEFINED: return "undefined"; 779 case ACTIVITY_TYPE_STANDARD: return "standard"; 780 case ACTIVITY_TYPE_HOME: return "home"; 781 case ACTIVITY_TYPE_RECENTS: return "recents"; 782 case ACTIVITY_TYPE_ASSISTANT: return "assistant"; 783 } 784 return String.valueOf(applicationType); 785 } 786 787 /** @hide */ alwaysOnTopToString(@lwaysOnTop int alwaysOnTop)788 public static String alwaysOnTopToString(@AlwaysOnTop int alwaysOnTop) { 789 switch (alwaysOnTop) { 790 case ALWAYS_ON_TOP_UNDEFINED: return "undefined"; 791 case ALWAYS_ON_TOP_ON: return "on"; 792 case ALWAYS_ON_TOP_OFF: return "off"; 793 } 794 return String.valueOf(alwaysOnTop); 795 } 796 } 797