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