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 android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.RequiresFeature; 22 import android.annotation.TestApi; 23 import android.content.pm.PackageManager; 24 import android.graphics.Rect; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 import android.util.Rational; 28 29 import java.util.ArrayList; 30 import java.util.List; 31 import java.util.Objects; 32 33 /** 34 * Represents a set of parameters used to initialize and update an Activity in picture-in-picture 35 * mode. 36 */ 37 public final class PictureInPictureParams implements Parcelable { 38 39 /** 40 * Builder class for {@link PictureInPictureParams} objects. 41 */ 42 public static class Builder { 43 44 @Nullable 45 private Rational mAspectRatio; 46 47 @Nullable 48 private Rational mExpandedAspectRatio; 49 50 @Nullable 51 private List<RemoteAction> mUserActions; 52 53 @Nullable 54 private RemoteAction mCloseAction; 55 56 @Nullable 57 private Rect mSourceRectHint; 58 59 private Boolean mAutoEnterEnabled; 60 61 private Boolean mSeamlessResizeEnabled; 62 63 private CharSequence mTitle; 64 65 private CharSequence mSubtitle; 66 67 private Boolean mIsLaunchIntoPip; 68 69 /** Default constructor */ Builder()70 public Builder() {} 71 72 /** 73 * Copy constructor 74 * @param original {@link PictureInPictureParams} instance this builder is built upon. 75 */ Builder(@onNull PictureInPictureParams original)76 public Builder(@NonNull PictureInPictureParams original) { 77 mAspectRatio = original.mAspectRatio; 78 mUserActions = original.mUserActions; 79 mCloseAction = original.mCloseAction; 80 mSourceRectHint = original.mSourceRectHint; 81 mAutoEnterEnabled = original.mAutoEnterEnabled; 82 mSeamlessResizeEnabled = original.mSeamlessResizeEnabled; 83 mTitle = original.mTitle; 84 mSubtitle = original.mSubtitle; 85 mIsLaunchIntoPip = original.mIsLaunchIntoPip; 86 } 87 88 /** 89 * Sets the aspect ratio. This aspect ratio is defined as the desired width / height, and 90 * does not change upon device rotation. 91 * 92 * @param aspectRatio the new aspect ratio for the activity in picture-in-picture, must be 93 * between 2.39:1 and 1:2.39 (inclusive). 94 * @return this builder instance. 95 */ setAspectRatio(Rational aspectRatio)96 public Builder setAspectRatio(Rational aspectRatio) { 97 mAspectRatio = aspectRatio; 98 return this; 99 } 100 101 /** 102 * Sets the aspect ratio for the expanded picture-in-picture mode. The aspect ratio is 103 * defined as the desired width / height. <br/> 104 * The aspect ratio cannot be changed from horizontal to vertical or vertical to horizontal 105 * while the PIP is shown. Any such changes will be ignored. <br/> 106 * 107 * Setting the expanded ratio shows the activity's support for expanded mode. 108 * 109 * @param expandedAspectRatio must not be between 2.39:1 and 1:2.39 (inclusive). If {@code 110 * null}, expanded picture-in-picture mode is not supported. 111 * @return this builder instance. 112 */ 113 @RequiresFeature(PackageManager.FEATURE_EXPANDED_PICTURE_IN_PICTURE) setExpandedAspectRatio(@ullable Rational expandedAspectRatio)114 public @NonNull Builder setExpandedAspectRatio(@Nullable Rational expandedAspectRatio) { 115 mExpandedAspectRatio = expandedAspectRatio; 116 return this; 117 } 118 119 /** 120 * Sets the user actions. If there are more than 121 * {@link Activity#getMaxNumPictureInPictureActions()} actions, then the input list 122 * will be truncated to that number. 123 * 124 * @param actions the new actions to show in the picture-in-picture menu. 125 * 126 * @return this builder instance. 127 * 128 * @see RemoteAction 129 */ setActions(List<RemoteAction> actions)130 public Builder setActions(List<RemoteAction> actions) { 131 if (mUserActions != null) { 132 mUserActions = null; 133 } 134 if (actions != null) { 135 mUserActions = new ArrayList<>(actions); 136 } 137 return this; 138 } 139 140 /** 141 * Sets a close action that should be invoked before the default close PiP action. The 142 * custom action must close the activity quickly using {@link Activity#finish()}. 143 * Otherwise, the system will forcibly close the PiP as if no custom close action was 144 * provided. 145 * 146 * If the action matches one set via {@link PictureInPictureParams.Builder#setActions(List)} 147 * it may be shown in place of that custom action in the menu. 148 * 149 * @param action to replace the system close action 150 * @return this builder instance. 151 * @see RemoteAction 152 */ 153 @NonNull setCloseAction(@ullable RemoteAction action)154 public Builder setCloseAction(@Nullable RemoteAction action) { 155 mCloseAction = action; 156 return this; 157 } 158 159 /** 160 * Sets the source bounds hint. These bounds are only used when an activity first enters 161 * picture-in-picture, and describe the bounds in window coordinates of activity entering 162 * picture-in-picture that will be visible following the transition. For the best effect, 163 * these bounds should also match the aspect ratio in the arguments. 164 * 165 * @param launchBounds window-coordinate bounds indicating the area of the activity that 166 * will still be visible following the transition into picture-in-picture (eg. the video 167 * view bounds in a video player) 168 * 169 * @return this builder instance. 170 */ setSourceRectHint(Rect launchBounds)171 public Builder setSourceRectHint(Rect launchBounds) { 172 if (launchBounds == null) { 173 mSourceRectHint = null; 174 } else { 175 mSourceRectHint = new Rect(launchBounds); 176 } 177 return this; 178 } 179 180 /** 181 * Sets whether the system will automatically put the activity in picture-in-picture mode 182 * without needing/waiting for the activity to call 183 * {@link Activity#enterPictureInPictureMode(PictureInPictureParams)}. 184 * 185 * If true, {@link Activity#onPictureInPictureRequested()} will never be called. 186 * 187 * This property is {@code false} by default. 188 * @param autoEnterEnabled {@code true} if the system will automatically put the activity 189 * in picture-in-picture mode. 190 * 191 * @return this builder instance. 192 */ 193 @NonNull setAutoEnterEnabled(boolean autoEnterEnabled)194 public Builder setAutoEnterEnabled(boolean autoEnterEnabled) { 195 mAutoEnterEnabled = autoEnterEnabled; 196 return this; 197 } 198 199 /** 200 * Sets whether the system can seamlessly resize the window while the activity is in 201 * picture-in-picture mode. This should normally be the case for video content and 202 * when it's set to {@code false}, system will perform transitions to overcome the 203 * artifacts due to resize. 204 * 205 * This property is {@code true} by default for backwards compatibility. 206 * @param seamlessResizeEnabled {@code true} if the system can seamlessly resize the window 207 * while activity is in picture-in-picture mode. 208 * @return this builder instance. 209 */ 210 @NonNull setSeamlessResizeEnabled(boolean seamlessResizeEnabled)211 public Builder setSeamlessResizeEnabled(boolean seamlessResizeEnabled) { 212 mSeamlessResizeEnabled = seamlessResizeEnabled; 213 return this; 214 } 215 216 /** 217 * Sets a title for the picture-in-picture window, which may be displayed by the system to 218 * give the user information about what this PIP is generally being used for. 219 * 220 * @param title General information about the PIP content 221 * @return this builder instance. 222 */ 223 @NonNull setTitle(@ullable CharSequence title)224 public Builder setTitle(@Nullable CharSequence title) { 225 mTitle = title; 226 return this; 227 } 228 229 /** 230 * Sets a subtitle for the picture-in-picture window, which may be displayed by the system 231 * to give the user more detailed information about what this PIP is displaying.<br/> 232 * 233 * Setting a title via {@link PictureInPictureParams.Builder#setTitle(CharSequence)} should 234 * be prioritized. 235 * 236 * @param subtitle Details about the PIP content. 237 * @return this builder instance 238 */ 239 @NonNull setSubtitle(@ullable CharSequence subtitle)240 public Builder setSubtitle(@Nullable CharSequence subtitle) { 241 mSubtitle = subtitle; 242 return this; 243 } 244 245 /** 246 * Sets whether the built {@link PictureInPictureParams} represents a launch into 247 * picture-in-picture request. 248 * 249 * This property is {@code false} by default. 250 * @param isLaunchIntoPip {@code true} if the built instance represents a launch into 251 * picture-in-picture request 252 * @return this builder instance. 253 */ 254 @NonNull setIsLaunchIntoPip(boolean isLaunchIntoPip)255 Builder setIsLaunchIntoPip(boolean isLaunchIntoPip) { 256 mIsLaunchIntoPip = isLaunchIntoPip; 257 return this; 258 } 259 260 /** 261 * @return an immutable {@link PictureInPictureParams} to be used when entering or updating 262 * the activity in picture-in-picture. 263 * 264 * @see Activity#enterPictureInPictureMode(PictureInPictureParams) 265 * @see Activity#setPictureInPictureParams(PictureInPictureParams) 266 */ build()267 public PictureInPictureParams build() { 268 PictureInPictureParams params = new PictureInPictureParams(mAspectRatio, 269 mExpandedAspectRatio, mUserActions, mCloseAction, mSourceRectHint, 270 mAutoEnterEnabled, mSeamlessResizeEnabled, mTitle, mSubtitle, 271 mIsLaunchIntoPip); 272 return params; 273 } 274 } 275 276 /** 277 * The expected aspect ratio of the picture-in-picture. 278 */ 279 @Nullable 280 private Rational mAspectRatio; 281 282 /** 283 * The expected aspect ratio of the expanded picture-in-picture window. 284 */ 285 @Nullable 286 private Rational mExpandedAspectRatio; 287 288 /** 289 * The set of actions that are associated with this activity when in picture-in-picture. 290 */ 291 @Nullable 292 private List<RemoteAction> mUserActions; 293 294 /** 295 * Action to replace the system close action. 296 */ 297 @Nullable 298 private RemoteAction mCloseAction; 299 300 /** 301 * The source bounds hint used when entering picture-in-picture, relative to the window bounds. 302 * We can use this internally for the transition into picture-in-picture to ensure that a 303 * particular source rect is visible throughout the whole transition. 304 */ 305 @Nullable 306 private Rect mSourceRectHint; 307 308 /** 309 * Whether the system is allowed to automatically put the activity in picture-in-picture mode. 310 * {@link #isAutoEnterEnabled()} defaults to {@code false} if this is not set. 311 */ 312 private Boolean mAutoEnterEnabled; 313 314 /** 315 * Whether system can seamlessly resize the window when activity is in picture-in-picture mode. 316 * {@link #isSeamlessResizeEnabled()} defaults to {@code true} if this is not set for 317 * backwards compatibility. 318 */ 319 private Boolean mSeamlessResizeEnabled; 320 321 /** 322 * Title of the picture-in-picture window to be displayed to the user. 323 */ 324 @Nullable 325 private CharSequence mTitle; 326 327 /** 328 * Subtitle for the picture-in-picture window to be displayed to the user. 329 */ 330 @Nullable 331 private CharSequence mSubtitle; 332 333 /** 334 * Whether this {@link PictureInPictureParams} represents a launch into 335 * picture-in-picture request. 336 * {@link #isLaunchIntoPip()} defaults to {@code false} is this is not set. 337 */ 338 private Boolean mIsLaunchIntoPip; 339 340 /** {@hide} */ PictureInPictureParams()341 PictureInPictureParams() { 342 } 343 344 /** {@hide} */ PictureInPictureParams(Parcel in)345 PictureInPictureParams(Parcel in) { 346 mAspectRatio = readRationalFromParcel(in); 347 mExpandedAspectRatio = readRationalFromParcel(in); 348 if (in.readInt() != 0) { 349 mUserActions = new ArrayList<>(); 350 in.readTypedList(mUserActions, RemoteAction.CREATOR); 351 } 352 mCloseAction = in.readTypedObject(RemoteAction.CREATOR); 353 if (in.readInt() != 0) { 354 mSourceRectHint = Rect.CREATOR.createFromParcel(in); 355 } 356 if (in.readInt() != 0) { 357 mAutoEnterEnabled = in.readBoolean(); 358 } 359 if (in.readInt() != 0) { 360 mSeamlessResizeEnabled = in.readBoolean(); 361 } 362 if (in.readInt() != 0) { 363 mTitle = in.readCharSequence(); 364 } 365 if (in.readInt() != 0) { 366 mSubtitle = in.readCharSequence(); 367 } 368 if (in.readInt() != 0) { 369 mIsLaunchIntoPip = in.readBoolean(); 370 } 371 } 372 373 /** {@hide} */ PictureInPictureParams(Rational aspectRatio, Rational expandedAspectRatio, List<RemoteAction> actions, RemoteAction closeAction, Rect sourceRectHint, Boolean autoEnterEnabled, Boolean seamlessResizeEnabled, CharSequence title, CharSequence subtitle, Boolean isLaunchIntoPip)374 PictureInPictureParams(Rational aspectRatio, Rational expandedAspectRatio, 375 List<RemoteAction> actions, RemoteAction closeAction, Rect sourceRectHint, 376 Boolean autoEnterEnabled, Boolean seamlessResizeEnabled, CharSequence title, 377 CharSequence subtitle, Boolean isLaunchIntoPip) { 378 mAspectRatio = aspectRatio; 379 mExpandedAspectRatio = expandedAspectRatio; 380 mUserActions = actions; 381 mCloseAction = closeAction; 382 mSourceRectHint = sourceRectHint; 383 mAutoEnterEnabled = autoEnterEnabled; 384 mSeamlessResizeEnabled = seamlessResizeEnabled; 385 mTitle = title; 386 mSubtitle = subtitle; 387 mIsLaunchIntoPip = isLaunchIntoPip; 388 } 389 390 /** 391 * Makes a copy from the other picture-in-picture args. 392 * @hide 393 */ PictureInPictureParams(PictureInPictureParams other)394 public PictureInPictureParams(PictureInPictureParams other) { 395 this(other.mAspectRatio, other.mExpandedAspectRatio, other.mUserActions, other.mCloseAction, 396 other.hasSourceBoundsHint() ? new Rect(other.getSourceRectHint()) : null, 397 other.mAutoEnterEnabled, other.mSeamlessResizeEnabled, 398 other.mTitle, other.mSubtitle, other.mIsLaunchIntoPip); 399 } 400 401 /** 402 * Copies the set parameters from the other picture-in-picture args. 403 * @hide 404 */ copyOnlySet(PictureInPictureParams otherArgs)405 public void copyOnlySet(PictureInPictureParams otherArgs) { 406 if (otherArgs.hasSetAspectRatio()) { 407 mAspectRatio = otherArgs.mAspectRatio; 408 } 409 410 // Copy either way because null can be used to explicitly unset the value 411 mExpandedAspectRatio = otherArgs.mExpandedAspectRatio; 412 413 if (otherArgs.hasSetActions()) { 414 mUserActions = otherArgs.mUserActions; 415 } 416 if (otherArgs.hasSetCloseAction()) { 417 mCloseAction = otherArgs.mCloseAction; 418 } 419 if (otherArgs.hasSourceBoundsHint()) { 420 mSourceRectHint = new Rect(otherArgs.getSourceRectHint()); 421 } 422 if (otherArgs.mAutoEnterEnabled != null) { 423 mAutoEnterEnabled = otherArgs.mAutoEnterEnabled; 424 } 425 if (otherArgs.mSeamlessResizeEnabled != null) { 426 mSeamlessResizeEnabled = otherArgs.mSeamlessResizeEnabled; 427 } 428 if (otherArgs.hasSetTitle()) { 429 mTitle = otherArgs.mTitle; 430 } 431 if (otherArgs.hasSetSubtitle()) { 432 mSubtitle = otherArgs.mSubtitle; 433 } 434 if (otherArgs.mIsLaunchIntoPip != null) { 435 mIsLaunchIntoPip = otherArgs.mIsLaunchIntoPip; 436 } 437 } 438 439 /** 440 * @return the aspect ratio. If none is set, return 0. 441 * @hide 442 */ 443 @TestApi getAspectRatioFloat()444 public float getAspectRatioFloat() { 445 if (mAspectRatio != null) { 446 return mAspectRatio.floatValue(); 447 } 448 return 0f; 449 } 450 451 /** 452 * Returns the expected aspect ratio of the picture-in-picture window. 453 * 454 * @return aspect ratio as the desired width / height or {@code null} if not set. 455 * @see PictureInPictureParams.Builder#setAspectRatio(Rational) 456 */ 457 @Nullable getAspectRatio()458 public Rational getAspectRatio() { 459 return mAspectRatio; 460 } 461 462 /** 463 * @return whether the aspect ratio is set. 464 * @hide 465 */ hasSetAspectRatio()466 public boolean hasSetAspectRatio() { 467 return mAspectRatio != null; 468 } 469 470 /** 471 * @return the expanded aspect ratio. If none is set, return 0. 472 * @hide 473 */ 474 @TestApi getExpandedAspectRatioFloat()475 public float getExpandedAspectRatioFloat() { 476 if (mExpandedAspectRatio != null) { 477 return mExpandedAspectRatio.floatValue(); 478 } 479 return 0f; 480 } 481 482 /** 483 * Returns the desired aspect ratio of the expanded picture-in-picture window. 484 * 485 * @return aspect ratio as the desired width / height or {@code null} if not set. 486 * @see PictureInPictureParams.Builder#setExpandedAspectRatio(Rational) 487 */ 488 @Nullable getExpandedAspectRatio()489 public Rational getExpandedAspectRatio() { 490 return mExpandedAspectRatio; 491 } 492 493 /** 494 * @return whether the expanded aspect ratio is set 495 * @hide 496 */ hasSetExpandedAspectRatio()497 public boolean hasSetExpandedAspectRatio() { 498 return mExpandedAspectRatio != null; 499 } 500 501 /** 502 * Returns the list of user actions that are associated with the activity when in 503 * picture-in-picture mode. 504 * 505 * @return the user actions in a new list. 506 * @see PictureInPictureParams.Builder#setActions(List) 507 */ 508 @NonNull getActions()509 public List<RemoteAction> getActions() { 510 if (mUserActions == null) { 511 return new ArrayList<>(); 512 } 513 return mUserActions; 514 } 515 516 /** 517 * @return whether the user actions are set. 518 * @hide 519 */ hasSetActions()520 public boolean hasSetActions() { 521 return mUserActions != null; 522 } 523 524 /** 525 * Returns the action that is to replace the system close action. 526 * 527 * @return the close action or {@code null} if not set. 528 * @see PictureInPictureParams.Builder#setCloseAction(RemoteAction) 529 */ 530 @Nullable getCloseAction()531 public RemoteAction getCloseAction() { 532 return mCloseAction; 533 } 534 535 /** 536 * @return whether the close action was set. 537 * @hide 538 */ hasSetCloseAction()539 public boolean hasSetCloseAction() { 540 return mCloseAction != null; 541 } 542 543 /** 544 * Truncates the set of actions to the given {@param size}. 545 * 546 * @hide 547 */ truncateActions(int size)548 public void truncateActions(int size) { 549 if (hasSetActions()) { 550 mUserActions = mUserActions.subList(0, Math.min(mUserActions.size(), size)); 551 } 552 } 553 554 /** 555 * Returns the source rect hint. 556 * 557 * @return the source rect hint also known as launch bounds or {@code null} if not set. 558 * @see PictureInPictureParams.Builder#setSourceRectHint(Rect) 559 */ 560 @Nullable getSourceRectHint()561 public Rect getSourceRectHint() { 562 return mSourceRectHint; 563 } 564 565 /** 566 * @return whether there are launch bounds set 567 * @hide 568 */ hasSourceBoundsHint()569 public boolean hasSourceBoundsHint() { 570 return mSourceRectHint != null && !mSourceRectHint.isEmpty(); 571 } 572 573 /** 574 * Returns whether auto enter picture-in-picture is enabled. 575 * 576 * @return {@code true} if the system will automatically put the activity in 577 * picture-in-picture mode. 578 * @see PictureInPictureParams.Builder#setAutoEnterEnabled(boolean) 579 */ isAutoEnterEnabled()580 public boolean isAutoEnterEnabled() { 581 return mAutoEnterEnabled == null ? false : mAutoEnterEnabled; 582 } 583 584 /** 585 * Returns whether seamless resize is enabled. 586 * 587 * @return true if the system can seamlessly resize the window while activity is in 588 * picture-in-picture mode. 589 * @see PictureInPictureParams.Builder#setSeamlessResizeEnabled(boolean) 590 */ isSeamlessResizeEnabled()591 public boolean isSeamlessResizeEnabled() { 592 return mSeamlessResizeEnabled == null ? true : mSeamlessResizeEnabled; 593 } 594 595 /** 596 * @return whether a title was set. 597 * @hide 598 */ hasSetTitle()599 public boolean hasSetTitle() { 600 return mTitle != null; 601 } 602 603 /** 604 * Returns the title of the picture-in-picture window that may be displayed to the user. 605 * 606 * @return title of the picture-in-picture window. 607 * @see PictureInPictureParams.Builder#setTitle(CharSequence) 608 */ 609 @Nullable getTitle()610 public CharSequence getTitle() { 611 return mTitle; 612 } 613 614 /** 615 * @return whether a subtitle was set. 616 * @hide 617 */ hasSetSubtitle()618 public boolean hasSetSubtitle() { 619 return mSubtitle != null; 620 } 621 622 /** 623 * Returns the subtitle of the picture-in-picture window that may be displayed to the user. 624 * 625 * @return subtitle of the picture-in-picture window. 626 * @see PictureInPictureParams.Builder#setSubtitle(CharSequence) 627 */ 628 @Nullable getSubtitle()629 public CharSequence getSubtitle() { 630 return mSubtitle; 631 } 632 633 /** 634 * @return whether this {@link PictureInPictureParams} represents a launch into pip request. 635 * @hide 636 */ isLaunchIntoPip()637 public boolean isLaunchIntoPip() { 638 return mIsLaunchIntoPip == null ? false : mIsLaunchIntoPip; 639 } 640 641 /** 642 * @return True if no parameters are set 643 * @hide 644 */ empty()645 public boolean empty() { 646 return !hasSourceBoundsHint() && !hasSetActions() && !hasSetCloseAction() 647 && !hasSetAspectRatio() && !hasSetExpandedAspectRatio() && mAutoEnterEnabled == null 648 && mSeamlessResizeEnabled == null && !hasSetTitle() 649 && !hasSetSubtitle() && mIsLaunchIntoPip == null; 650 } 651 652 @Override equals(Object o)653 public boolean equals(Object o) { 654 if (this == o) return true; 655 if (!(o instanceof PictureInPictureParams)) return false; 656 PictureInPictureParams that = (PictureInPictureParams) o; 657 return Objects.equals(mAutoEnterEnabled, that.mAutoEnterEnabled) 658 && Objects.equals(mSeamlessResizeEnabled, that.mSeamlessResizeEnabled) 659 && Objects.equals(mAspectRatio, that.mAspectRatio) 660 && Objects.equals(mExpandedAspectRatio, that.mExpandedAspectRatio) 661 && Objects.equals(mUserActions, that.mUserActions) 662 && Objects.equals(mCloseAction, that.mCloseAction) 663 && Objects.equals(mSourceRectHint, that.mSourceRectHint) 664 && Objects.equals(mTitle, that.mTitle) 665 && Objects.equals(mSubtitle, that.mSubtitle) 666 && Objects.equals(mIsLaunchIntoPip, that.mIsLaunchIntoPip); 667 } 668 669 @Override hashCode()670 public int hashCode() { 671 return Objects.hash(mAspectRatio, mExpandedAspectRatio, mUserActions, mCloseAction, 672 mSourceRectHint, mAutoEnterEnabled, mSeamlessResizeEnabled, mTitle, mSubtitle, 673 mIsLaunchIntoPip); 674 } 675 676 @Override describeContents()677 public int describeContents() { 678 return 0; 679 } 680 681 @Override writeToParcel(Parcel out, int flags)682 public void writeToParcel(Parcel out, int flags) { 683 writeRationalToParcel(mAspectRatio, out); 684 writeRationalToParcel(mExpandedAspectRatio, out); 685 if (mUserActions != null) { 686 out.writeInt(1); 687 out.writeTypedList(mUserActions, 0); 688 } else { 689 out.writeInt(0); 690 } 691 692 out.writeTypedObject(mCloseAction, 0); 693 694 if (mSourceRectHint != null) { 695 out.writeInt(1); 696 mSourceRectHint.writeToParcel(out, 0); 697 } else { 698 out.writeInt(0); 699 } 700 if (mAutoEnterEnabled != null) { 701 out.writeInt(1); 702 out.writeBoolean(mAutoEnterEnabled); 703 } else { 704 out.writeInt(0); 705 } 706 if (mSeamlessResizeEnabled != null) { 707 out.writeInt(1); 708 out.writeBoolean(mSeamlessResizeEnabled); 709 } else { 710 out.writeInt(0); 711 } 712 if (mTitle != null) { 713 out.writeInt(1); 714 out.writeCharSequence(mTitle); 715 } else { 716 out.writeInt(0); 717 } 718 if (mSubtitle != null) { 719 out.writeInt(1); 720 out.writeCharSequence(mSubtitle); 721 } else { 722 out.writeInt(0); 723 } 724 if (mIsLaunchIntoPip != null) { 725 out.writeInt(1); 726 out.writeBoolean(mIsLaunchIntoPip); 727 } else { 728 out.writeInt(0); 729 } 730 } 731 writeRationalToParcel(Rational rational, Parcel out)732 private void writeRationalToParcel(Rational rational, Parcel out) { 733 if (rational != null) { 734 out.writeInt(1); 735 out.writeInt(rational.getNumerator()); 736 out.writeInt(rational.getDenominator()); 737 } else { 738 out.writeInt(0); 739 } 740 } 741 readRationalFromParcel(Parcel in)742 private Rational readRationalFromParcel(Parcel in) { 743 if (in.readInt() != 0) { 744 return new Rational(in.readInt(), in.readInt()); 745 } 746 return null; 747 } 748 749 @Override toString()750 public String toString() { 751 return "PictureInPictureParams(" 752 + " aspectRatio=" + getAspectRatio() 753 + " expandedAspectRatio=" + mExpandedAspectRatio 754 + " sourceRectHint=" + getSourceRectHint() 755 + " hasSetActions=" + hasSetActions() 756 + " hasSetCloseAction=" + hasSetCloseAction() 757 + " isAutoPipEnabled=" + isAutoEnterEnabled() 758 + " isSeamlessResizeEnabled=" + isSeamlessResizeEnabled() 759 + " title=" + getTitle() 760 + " subtitle=" + getSubtitle() 761 + " isLaunchIntoPip=" + isLaunchIntoPip() 762 + ")"; 763 } 764 765 public static final @android.annotation.NonNull Creator<PictureInPictureParams> CREATOR = 766 new Creator<PictureInPictureParams>() { 767 public PictureInPictureParams createFromParcel(Parcel in) { 768 return new PictureInPictureParams(in); 769 } 770 public PictureInPictureParams[] newArray(int size) { 771 return new PictureInPictureParams[size]; 772 } 773 }; 774 } 775