1 /* 2 * Copyright (C) 2021 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.FlaggedApi; 20 import android.annotation.NonNull; 21 import android.annotation.TestApi; 22 import android.content.res.Configuration; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 26 import java.util.Objects; 27 28 /** 29 * Used by {@link Activity#onPictureInPictureUiStateChanged(PictureInPictureUiState)}. 30 */ 31 public final class PictureInPictureUiState implements Parcelable { 32 33 private final boolean mIsStashed; 34 private final boolean mIsTransitioningToPip; 35 36 /** {@hide} */ PictureInPictureUiState(Parcel in)37 PictureInPictureUiState(Parcel in) { 38 mIsStashed = in.readBoolean(); 39 mIsTransitioningToPip = in.readBoolean(); 40 } 41 42 /** {@hide} */ 43 @TestApi PictureInPictureUiState(boolean isStashed)44 public PictureInPictureUiState(boolean isStashed) { 45 this(isStashed, false /* isEnteringPip */); 46 } 47 PictureInPictureUiState(boolean isStashed, boolean isTransitioningToPip)48 private PictureInPictureUiState(boolean isStashed, boolean isTransitioningToPip) { 49 mIsStashed = isStashed; 50 mIsTransitioningToPip = isTransitioningToPip; 51 } 52 53 /** 54 * Returns whether Picture-in-Picture is stashed or not. A stashed PiP means it is only 55 * partially visible to the user, with some parts of it being off-screen. This is usually a 56 * UI state that is triggered by the user, such as flinging the PiP to the edge or letting go 57 * of PiP while dragging partially off-screen. 58 * 59 * Developers can use this in conjunction with 60 * {@link Activity#onPictureInPictureUiStateChanged(PictureInPictureUiState)} to get a signal 61 * when the PiP stash state has changed. For example, if the state changed from {@code false} to 62 * {@code true}, developers can choose to temporarily pause video playback if PiP is of video 63 * content. Vice versa, if changing from {@code true} to {@code false} and video content is 64 * paused, developers can resume video playback. 65 * 66 * @see <a href="http://developer.android.com/about/versions/12/features/pip-improvements"> 67 * Picture in Picture (PiP) improvements</a> 68 */ isStashed()69 public boolean isStashed() { 70 return mIsStashed; 71 } 72 73 /** 74 * Returns {@code true} if the app is going to enter Picture-in-Picture (PiP) mode. 75 * 76 * This state is associated with the entering PiP animation. When that animation starts, 77 * whether via auto enter PiP or calling 78 * {@link Activity#enterPictureInPictureMode(PictureInPictureParams)} explicitly, app can expect 79 * {@link Activity#onPictureInPictureUiStateChanged(PictureInPictureUiState)} callback with 80 * {@link #isTransitioningToPip()} to be {@code true} first, 81 * followed by {@link Activity#onPictureInPictureModeChanged(boolean, Configuration)} when it 82 * fully settles in PiP mode. 83 * 84 * When app receives the 85 * {@link Activity#onPictureInPictureUiStateChanged(PictureInPictureUiState)} callback with 86 * {@link #isTransitioningToPip()} being {@code true}, it's recommended to hide certain UI 87 * elements, such as video controls, to archive a clean entering PiP animation. 88 * 89 * In case an application wants to restore the previously hidden UI elements when exiting 90 * PiP, it is recommended to do that in 91 * {@code onPictureInPictureModeChanged(isInPictureInPictureMode=false)} callback rather 92 * than the beginning of exit PiP animation. 93 */ 94 @FlaggedApi(Flags.FLAG_ENABLE_PIP_UI_STATE_CALLBACK_ON_ENTERING) isTransitioningToPip()95 public boolean isTransitioningToPip() { 96 return mIsTransitioningToPip; 97 } 98 99 @Override equals(Object o)100 public boolean equals(Object o) { 101 if (this == o) return true; 102 if (!(o instanceof PictureInPictureUiState)) return false; 103 PictureInPictureUiState that = (PictureInPictureUiState) o; 104 return mIsStashed == that.mIsStashed 105 && mIsTransitioningToPip == that.mIsTransitioningToPip; 106 } 107 108 @Override hashCode()109 public int hashCode() { 110 return Objects.hash(mIsStashed, mIsTransitioningToPip); 111 } 112 113 @Override describeContents()114 public int describeContents() { 115 return 0; 116 } 117 118 @Override writeToParcel(@onNull Parcel out, int flags)119 public void writeToParcel(@NonNull Parcel out, int flags) { 120 out.writeBoolean(mIsStashed); 121 out.writeBoolean(mIsTransitioningToPip); 122 } 123 124 public static final @android.annotation.NonNull Creator<PictureInPictureUiState> CREATOR = 125 new Creator<PictureInPictureUiState>() { 126 public PictureInPictureUiState createFromParcel(Parcel in) { 127 return new PictureInPictureUiState(in); 128 } 129 public PictureInPictureUiState[] newArray(int size) { 130 return new PictureInPictureUiState[size]; 131 } 132 }; 133 134 /** 135 * Builder class for {@link PictureInPictureUiState}. 136 * @hide 137 */ 138 @FlaggedApi(Flags.FLAG_ENABLE_PIP_UI_STATE_CALLBACK_ON_ENTERING) 139 public static final class Builder { 140 private boolean mIsStashed; 141 private boolean mIsTransitioningToPip; 142 143 /** Empty constructor. */ Builder()144 public Builder() { 145 } 146 147 /** 148 * Sets the {@link #mIsStashed} state. 149 * @return The same {@link Builder} instance. 150 */ setStashed(boolean isStashed)151 public Builder setStashed(boolean isStashed) { 152 mIsStashed = isStashed; 153 return this; 154 } 155 156 /** 157 * Sets the {@link #mIsTransitioningToPip} state. 158 * @return The same {@link Builder} instance. 159 */ setTransitioningToPip(boolean isEnteringPip)160 public Builder setTransitioningToPip(boolean isEnteringPip) { 161 mIsTransitioningToPip = isEnteringPip; 162 return this; 163 } 164 165 /** 166 * @return The constructed {@link PictureInPictureUiState} instance. 167 */ build()168 public PictureInPictureUiState build() { 169 return new PictureInPictureUiState(mIsStashed, mIsTransitioningToPip); 170 } 171 } 172 } 173