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.content.res.Configuration; 30 import android.graphics.Rect; 31 import android.os.Parcel; 32 import android.os.Parcelable; 33 import android.util.proto.ProtoInputStream; 34 import android.util.proto.ProtoOutputStream; 35 import android.util.proto.WireTypeMismatchException; 36 import android.view.DisplayInfo; 37 38 import java.io.IOException; 39 40 /** 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 */ 47 @TestApi 48 public class WindowConfiguration implements Parcelable, Comparable<WindowConfiguration> { 49 /** 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(); 56 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 65 /** 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 76 /** The current windowing mode of the configuration. */ 77 private @WindowingMode int mWindowingMode; 78 79 /** The display windowing mode of the configuration */ 80 private @WindowingMode int mDisplayWindowingMode; 81 82 /** Windowing mode is currently not defined. */ 83 public static final int WINDOWING_MODE_UNDEFINED = 0; 84 /** Occupies the full area of the screen or the parent container. */ 85 public static final int WINDOWING_MODE_FULLSCREEN = 1; 86 /** Always on-top (always visible). of other siblings in its parent container. */ 87 public static final int WINDOWING_MODE_PINNED = 2; 88 /** The primary container driving the screen to be in split-screen mode. */ 89 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. 93 * 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 98 */ 99 public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4; 100 /** 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; 108 /** Can be freely resized within its parent container. */ 109 public static final int WINDOWING_MODE_FREEFORM = 5; 110 111 /** @hide */ 112 @IntDef(prefix = { "WINDOWING_MODE_" }, value = { 113 WINDOWING_MODE_UNDEFINED, 114 WINDOWING_MODE_FULLSCREEN, 115 WINDOWING_MODE_PINNED, 116 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, 117 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, 118 WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, 119 WINDOWING_MODE_FREEFORM, 120 }) 121 public @interface WindowingMode {} 122 123 /** The current activity type of the configuration. */ 124 private @ActivityType int mActivityType; 125 126 /** Activity type is currently not defined. */ 127 public static final int ACTIVITY_TYPE_UNDEFINED = 0; 128 /** Standard activity type. Nothing special about the activity... */ 129 public static final int ACTIVITY_TYPE_STANDARD = 1; 130 /** Home/Launcher activity type. */ 131 public static final int ACTIVITY_TYPE_HOME = 2; 132 /** Recents/Overview activity type. There is only one activity with this type in the system. */ 133 public static final int ACTIVITY_TYPE_RECENTS = 3; 134 /** Assistant activity type. */ 135 public static final int ACTIVITY_TYPE_ASSISTANT = 4; 136 137 /** @hide */ 138 @IntDef(prefix = { "ACTIVITY_TYPE_" }, value = { 139 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 147 /** 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 165 /** Bit that indicates that the {@link #mBounds} changed. 166 * @hide */ 167 public static final int WINDOW_CONFIG_BOUNDS = 1 << 0; 168 /** Bit that indicates that the {@link #mAppBounds} changed. 169 * @hide */ 170 public static final int WINDOW_CONFIG_APP_BOUNDS = 1 << 1; 171 /** Bit that indicates that the {@link #mWindowingMode} changed. 172 * @hide */ 173 public static final int WINDOW_CONFIG_WINDOWING_MODE = 1 << 2; 174 /** Bit that indicates that the {@link #mActivityType} changed. 175 * @hide */ 176 public static final int WINDOW_CONFIG_ACTIVITY_TYPE = 1 << 3; 177 /** Bit that indicates that the {@link #mAlwaysOnTop} changed. 178 * @hide */ 179 public static final int WINDOW_CONFIG_ALWAYS_ON_TOP = 1 << 4; 180 /** Bit that indicates that the {@link #mRotation} changed. 181 * @hide */ 182 public static final int WINDOW_CONFIG_ROTATION = 1 << 5; 183 /** Bit that indicates that the {@link #mDisplayWindowingMode} changed. 184 * @hide */ 185 public static final int WINDOW_CONFIG_DISPLAY_WINDOWING_MODE = 1 << 6; 186 187 /** @hide */ 188 @IntDef(flag = true, prefix = { "WINDOW_CONFIG_" }, value = { 189 WINDOW_CONFIG_BOUNDS, 190 WINDOW_CONFIG_APP_BOUNDS, 191 WINDOW_CONFIG_WINDOWING_MODE, 192 WINDOW_CONFIG_ACTIVITY_TYPE, 193 WINDOW_CONFIG_ALWAYS_ON_TOP, 194 WINDOW_CONFIG_ROTATION, 195 WINDOW_CONFIG_DISPLAY_WINDOWING_MODE, 196 }) 197 public @interface WindowConfig {} 198 199 /** @hide */ 200 public static final int PINNED_WINDOWING_MODE_ELEVATION_IN_DIP = 5; 201 WindowConfiguration()202 public WindowConfiguration() { 203 unset(); 204 } 205 206 /** @hide */ WindowConfiguration(WindowConfiguration configuration)207 public WindowConfiguration(WindowConfiguration configuration) { 208 setTo(configuration); 209 } 210 WindowConfiguration(Parcel in)211 private WindowConfiguration(Parcel in) { 212 readFromParcel(in); 213 } 214 215 @Override writeToParcel(Parcel dest, int flags)216 public void writeToParcel(Parcel dest, int flags) { 217 dest.writeParcelable(mBounds, flags); 218 dest.writeParcelable(mAppBounds, flags); 219 dest.writeInt(mWindowingMode); 220 dest.writeInt(mActivityType); 221 dest.writeInt(mAlwaysOnTop); 222 dest.writeInt(mRotation); 223 dest.writeInt(mDisplayWindowingMode); 224 } 225 readFromParcel(Parcel source)226 private void readFromParcel(Parcel source) { 227 mBounds = source.readParcelable(Rect.class.getClassLoader()); 228 mAppBounds = source.readParcelable(Rect.class.getClassLoader()); 229 mWindowingMode = source.readInt(); 230 mActivityType = source.readInt(); 231 mAlwaysOnTop = source.readInt(); 232 mRotation = source.readInt(); 233 mDisplayWindowingMode = source.readInt(); 234 } 235 236 @Override describeContents()237 public int describeContents() { 238 return 0; 239 } 240 241 /** @hide */ 242 public static final @android.annotation.NonNull Creator<WindowConfiguration> CREATOR = new Creator<WindowConfiguration>() { 243 @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 /** 255 * Sets the bounds to the provided {@link Rect}. 256 * @param rect the new bounds value. 257 */ setBounds(Rect rect)258 public void setBounds(Rect rect) { 259 if (rect == null) { 260 mBounds.setEmpty(); 261 return; 262 } 263 264 mBounds.set(rect); 265 } 266 267 /** 268 * Set {@link #mAppBounds} to the input Rect. 269 * @param rect The rect value to set {@link #mAppBounds} to. 270 * @see #getAppBounds() 271 */ setAppBounds(Rect rect)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 281 282 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 */ setAlwaysOnTop(boolean alwaysOnTop)288 public void setAlwaysOnTop(boolean alwaysOnTop) { 289 mAlwaysOnTop = alwaysOnTop ? ALWAYS_ON_TOP_ON : ALWAYS_ON_TOP_OFF; 290 } 291 setAlwaysOnTop(@lwaysOnTop int alwaysOnTop)292 private void setAlwaysOnTop(@AlwaysOnTop int alwaysOnTop) { 293 mAlwaysOnTop = alwaysOnTop; 294 } 295 296 /** 297 * @see #setAppBounds(Rect) 298 * @see #getAppBounds() 299 * @hide 300 */ setAppBounds(int left, int top, int right, int bottom)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 309 /** @see #setAppBounds(Rect) */ getAppBounds()310 public Rect getAppBounds() { 311 return mAppBounds; 312 } 313 314 /** @see #setBounds(Rect) */ getBounds()315 public Rect getBounds() { 316 return mBounds; 317 } 318 getRotation()319 public int getRotation() { 320 return mRotation; 321 } 322 setRotation(int rotation)323 public void setRotation(int rotation) { 324 mRotation = rotation; 325 } 326 setWindowingMode(@indowingMode int windowingMode)327 public void setWindowingMode(@WindowingMode int windowingMode) { 328 mWindowingMode = windowingMode; 329 } 330 331 @WindowingMode getWindowingMode()332 public int getWindowingMode() { 333 return mWindowingMode; 334 } 335 336 /** @hide */ setDisplayWindowingMode(@indowingMode int windowingMode)337 public void setDisplayWindowingMode(@WindowingMode int windowingMode) { 338 mDisplayWindowingMode = windowingMode; 339 } 340 341 setActivityType(@ctivityType int activityType)342 public void setActivityType(@ActivityType int activityType) { 343 if (mActivityType == activityType) { 344 return; 345 } 346 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 352 && 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 getActivityType()360 public int getActivityType() { 361 return mActivityType; 362 } 363 setTo(WindowConfiguration other)364 public void setTo(WindowConfiguration other) { 365 setBounds(other.mBounds); 366 setAppBounds(other.mAppBounds); 367 setWindowingMode(other.mWindowingMode); 368 setActivityType(other.mActivityType); 369 setAlwaysOnTop(other.mAlwaysOnTop); 370 setRotation(other.mRotation); 371 setDisplayWindowingMode(other.mDisplayWindowingMode); 372 } 373 374 /** Set this object to completely undefined. 375 * @hide */ unset()376 public void unset() { 377 setToDefaults(); 378 } 379 380 /** @hide */ setToDefaults()381 public void setToDefaults() { 382 setAppBounds(null); 383 setBounds(null); 384 setWindowingMode(WINDOWING_MODE_UNDEFINED); 385 setActivityType(ACTIVITY_TYPE_UNDEFINED); 386 setAlwaysOnTop(ALWAYS_ON_TOP_UNDEFINED); 387 setRotation(ROTATION_UNDEFINED); 388 setDisplayWindowingMode(WINDOWING_MODE_UNDEFINED); 389 } 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} 397 * @hide 398 */ updateFrom(@onNull WindowConfiguration delta)399 public @WindowConfig int updateFrom(@NonNull WindowConfiguration delta) { 400 int changed = 0; 401 // 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 } 406 if (delta.mAppBounds != null && !delta.mAppBounds.equals(mAppBounds)) { 407 changed |= WINDOW_CONFIG_APP_BOUNDS; 408 setAppBounds(delta.mAppBounds); 409 } 410 if (delta.mWindowingMode != WINDOWING_MODE_UNDEFINED 411 && mWindowingMode != delta.mWindowingMode) { 412 changed |= WINDOW_CONFIG_WINDOWING_MODE; 413 setWindowingMode(delta.mWindowingMode); 414 } 415 if (delta.mActivityType != ACTIVITY_TYPE_UNDEFINED 416 && mActivityType != delta.mActivityType) { 417 changed |= WINDOW_CONFIG_ACTIVITY_TYPE; 418 setActivityType(delta.mActivityType); 419 } 420 if (delta.mAlwaysOnTop != ALWAYS_ON_TOP_UNDEFINED 421 && mAlwaysOnTop != delta.mAlwaysOnTop) { 422 changed |= WINDOW_CONFIG_ALWAYS_ON_TOP; 423 setAlwaysOnTop(delta.mAlwaysOnTop); 424 } 425 if (delta.mRotation != ROTATION_UNDEFINED && delta.mRotation != mRotation) { 426 changed |= WINDOW_CONFIG_ROTATION; 427 setRotation(delta.mRotation); 428 } 429 if (delta.mDisplayWindowingMode != WINDOWING_MODE_UNDEFINED 430 && mDisplayWindowingMode != delta.mDisplayWindowingMode) { 431 changed |= WINDOW_CONFIG_DISPLAY_WINDOWING_MODE; 432 setDisplayWindowingMode(delta.mDisplayWindowingMode); 433 } 434 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) 446 * @hide 447 */ diff(WindowConfiguration other, boolean compareUndefined)448 public @WindowConfig long diff(WindowConfiguration other, boolean compareUndefined) { 449 long changes = 0; 450 451 if (!mBounds.equals(other.mBounds)) { 452 changes |= WINDOW_CONFIG_BOUNDS; 453 } 454 455 // 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 462 if ((compareUndefined || other.mWindowingMode != WINDOWING_MODE_UNDEFINED) 463 && mWindowingMode != other.mWindowingMode) { 464 changes |= WINDOW_CONFIG_WINDOWING_MODE; 465 } 466 467 if ((compareUndefined || other.mActivityType != ACTIVITY_TYPE_UNDEFINED) 468 && mActivityType != other.mActivityType) { 469 changes |= WINDOW_CONFIG_ACTIVITY_TYPE; 470 } 471 472 if ((compareUndefined || other.mAlwaysOnTop != ALWAYS_ON_TOP_UNDEFINED) 473 && mAlwaysOnTop != other.mAlwaysOnTop) { 474 changes |= WINDOW_CONFIG_ALWAYS_ON_TOP; 475 } 476 477 if ((compareUndefined || other.mRotation != ROTATION_UNDEFINED) 478 && mRotation != other.mRotation) { 479 changes |= WINDOW_CONFIG_ROTATION; 480 } 481 482 if ((compareUndefined || other.mDisplayWindowingMode != WINDOWING_MODE_UNDEFINED) 483 && mDisplayWindowingMode != other.mDisplayWindowingMode) { 484 changes |= WINDOW_CONFIG_DISPLAY_WINDOWING_MODE; 485 } 486 487 return changes; 488 } 489 490 @Override compareTo(WindowConfiguration that)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 } 507 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 517 n = mWindowingMode - that.mWindowingMode; 518 if (n != 0) return n; 519 n = mActivityType - that.mActivityType; 520 if (n != 0) return n; 521 n = mAlwaysOnTop - that.mAlwaysOnTop; 522 if (n != 0) return n; 523 n = mRotation - that.mRotation; 524 if (n != 0) return n; 525 n = mDisplayWindowingMode - that.mDisplayWindowingMode; 526 if (n != 0) return n; 527 528 // if (n != 0) return n; 529 return n; 530 } 531 532 /** @hide */ 533 @Override equals(Object that)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 543 /** @hide */ 544 @Override hashCode()545 public int hashCode() { 546 int result = 0; 547 if (mAppBounds != null) { 548 result = 31 * result + mAppBounds.hashCode(); 549 } 550 result = 31 * result + mBounds.hashCode(); 551 552 result = 31 * result + mWindowingMode; 553 result = 31 * result + mActivityType; 554 result = 31 * result + mAlwaysOnTop; 555 result = 31 * result + mRotation; 556 result = 31 * result + mDisplayWindowingMode; 557 return result; 558 } 559 560 /** @hide */ 561 @Override toString()562 public String toString() { 563 return "{ mBounds=" + mBounds 564 + " mAppBounds=" + mAppBounds 565 + " mWindowingMode=" + windowingModeToString(mWindowingMode) 566 + " mDisplayWindowingMode=" + windowingModeToString(mDisplayWindowingMode) 567 + " mActivityType=" + activityTypeToString(mActivityType) 568 + " mAlwaysOnTop=" + alwaysOnTopToString(mAlwaysOnTop) 569 + " mRotation=" + (mRotation == ROTATION_UNDEFINED 570 ? "undefined" : rotationToString(mRotation)) 571 + "}"; 572 } 573 574 /** 575 * 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 */ writeToProto(ProtoOutputStream protoOutputStream, long fieldId)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); 589 if (mBounds != null) { 590 mBounds.writeToProto(protoOutputStream, BOUNDS); 591 } 592 protoOutputStream.end(token); 593 } 594 595 /** 596 * 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 */ readFromProto(ProtoInputStream proto, long fieldId)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; 613 case (int) BOUNDS: 614 mBounds = new Rect(); 615 mBounds.readFromProto(proto, BOUNDS); 616 break; 617 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 /** 632 * Returns true if the activities associated with this window configuration display a shadow 633 * around their border. 634 * @hide 635 */ hasWindowShadow()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. 643 * @hide 644 */ hasWindowDecorCaption()645 public boolean hasWindowDecorCaption() { 646 return mActivityType == ACTIVITY_TYPE_STANDARD && (mWindowingMode == WINDOWING_MODE_FREEFORM 647 || mDisplayWindowingMode == WINDOWING_MODE_FREEFORM); 648 } 649 650 /** 651 * Returns true if the tasks associated with this window configuration can be resized 652 * independently of their parent container. 653 * @hide 654 */ canResizeTask()655 public boolean canResizeTask() { 656 return mWindowingMode == WINDOWING_MODE_FREEFORM; 657 } 658 659 /** Returns true if the task bounds should persist across power cycles. 660 * @hide */ persistTaskBounds()661 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. 669 * @hide 670 */ tasksAreFloating()671 public boolean tasksAreFloating() { 672 return isFloating(mWindowingMode); 673 } 674 675 /** 676 * Returns true if the windowingMode represents a floating window. 677 * @hide 678 */ isFloating(int windowingMode)679 public static boolean isFloating(int windowingMode) { 680 return windowingMode == WINDOWING_MODE_FREEFORM || windowingMode == WINDOWING_MODE_PINNED; 681 } 682 683 /** 684 * Returns true if the windowingMode represents a split window. 685 * @hide 686 */ isSplitScreenWindowingMode(int windowingMode)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 /** 693 * Returns true if the windows associated with this window configuration can receive input keys. 694 * @hide 695 */ canReceiveKeys()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. 703 * @hide 704 */ isAlwaysOnTop()705 public boolean isAlwaysOnTop() { 706 return mWindowingMode == WINDOWING_MODE_PINNED 707 || (mWindowingMode == WINDOWING_MODE_FREEFORM && mAlwaysOnTop == ALWAYS_ON_TOP_ON); 708 } 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. 713 * @hide 714 */ keepVisibleDeadAppWindowOnScreen()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. 722 * @hide 723 */ useWindowFrameForBackdrop()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. 731 * @hide 732 */ windowsAreScaleable()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. 739 * @hide 740 */ hasMovementAnimations()741 public boolean hasMovementAnimations() { 742 return mWindowingMode != WINDOWING_MODE_PINNED; 743 } 744 745 /** 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 */ supportSplitScreenWindowingMode()751 public boolean supportSplitScreenWindowingMode() { 752 return supportSplitScreenWindowingMode(mActivityType); 753 } 754 755 /** @hide */ supportSplitScreenWindowingMode(int activityType)756 public static boolean supportSplitScreenWindowingMode(int activityType) { 757 return activityType != ACTIVITY_TYPE_ASSISTANT; 758 } 759 760 /** @hide */ windowingModeToString(@indowingMode int windowingMode)761 public static String windowingModeToString(@WindowingMode int windowingMode) { 762 switch (windowingMode) { 763 case WINDOWING_MODE_UNDEFINED: return "undefined"; 764 case WINDOWING_MODE_FULLSCREEN: return "fullscreen"; 765 case WINDOWING_MODE_PINNED: return "pinned"; 766 case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return "split-screen-primary"; 767 case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: return "split-screen-secondary"; 768 case WINDOWING_MODE_FREEFORM: return "freeform"; 769 } 770 return String.valueOf(windowingMode); 771 } 772 773 /** @hide */ activityTypeToString(@ctivityType int applicationType)774 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 } 784 785 /** @hide */ alwaysOnTopToString(@lwaysOnTop int alwaysOnTop)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 } 794 } 795