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.Nullable; 20 import android.annotation.TestApi; 21 import android.graphics.Rect; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 import android.util.Rational; 25 26 import java.util.ArrayList; 27 import java.util.List; 28 29 /** 30 * Represents a set of parameters used to initialize and update an Activity in picture-in-picture 31 * mode. 32 */ 33 public final class PictureInPictureParams implements Parcelable { 34 35 /** 36 * Builder class for {@link PictureInPictureParams} objects. 37 */ 38 public static class Builder { 39 40 @Nullable 41 private Rational mAspectRatio; 42 43 @Nullable 44 private List<RemoteAction> mUserActions; 45 46 @Nullable 47 private Rect mSourceRectHint; 48 49 /** 50 * Sets the aspect ratio. This aspect ratio is defined as the desired width / height, and 51 * does not change upon device rotation. 52 * 53 * @param aspectRatio the new aspect ratio for the activity in picture-in-picture, must be 54 * between 2.39:1 and 1:2.39 (inclusive). 55 * 56 * @return this builder instance. 57 */ setAspectRatio(Rational aspectRatio)58 public Builder setAspectRatio(Rational aspectRatio) { 59 mAspectRatio = aspectRatio; 60 return this; 61 } 62 63 /** 64 * Sets the user actions. If there are more than 65 * {@link Activity#getMaxNumPictureInPictureActions()} actions, then the input list 66 * will be truncated to that number. 67 * 68 * @param actions the new actions to show in the picture-in-picture menu. 69 * 70 * @return this builder instance. 71 * 72 * @see RemoteAction 73 */ setActions(List<RemoteAction> actions)74 public Builder setActions(List<RemoteAction> actions) { 75 if (mUserActions != null) { 76 mUserActions = null; 77 } 78 if (actions != null) { 79 mUserActions = new ArrayList<>(actions); 80 } 81 return this; 82 } 83 84 /** 85 * Sets the source bounds hint. These bounds are only used when an activity first enters 86 * picture-in-picture, and describe the bounds in window coordinates of activity entering 87 * picture-in-picture that will be visible following the transition. For the best effect, 88 * these bounds should also match the aspect ratio in the arguments. 89 * 90 * @param launchBounds window-coordinate bounds indicating the area of the activity that 91 * will still be visible following the transition into picture-in-picture (eg. the video 92 * view bounds in a video player) 93 * 94 * @return this builder instance. 95 */ setSourceRectHint(Rect launchBounds)96 public Builder setSourceRectHint(Rect launchBounds) { 97 if (launchBounds == null) { 98 mSourceRectHint = null; 99 } else { 100 mSourceRectHint = new Rect(launchBounds); 101 } 102 return this; 103 } 104 105 /** 106 * @return an immutable {@link PictureInPictureParams} to be used when entering or updating 107 * the activity in picture-in-picture. 108 * 109 * @see Activity#enterPictureInPictureMode(PictureInPictureParams) 110 * @see Activity#setPictureInPictureParams(PictureInPictureParams) 111 */ build()112 public PictureInPictureParams build() { 113 PictureInPictureParams params = new PictureInPictureParams(mAspectRatio, mUserActions, 114 mSourceRectHint); 115 return params; 116 } 117 } 118 119 /** 120 * The expected aspect ratio of the picture-in-picture. 121 */ 122 @Nullable 123 private Rational mAspectRatio; 124 125 /** 126 * The set of actions that are associated with this activity when in picture-in-picture. 127 */ 128 @Nullable 129 private List<RemoteAction> mUserActions; 130 131 /** 132 * The source bounds hint used when entering picture-in-picture, relative to the window bounds. 133 * We can use this internally for the transition into picture-in-picture to ensure that a 134 * particular source rect is visible throughout the whole transition. 135 */ 136 @Nullable 137 private Rect mSourceRectHint; 138 139 /** {@hide} */ PictureInPictureParams()140 PictureInPictureParams() { 141 } 142 143 /** {@hide} */ PictureInPictureParams(Parcel in)144 PictureInPictureParams(Parcel in) { 145 if (in.readInt() != 0) { 146 mAspectRatio = new Rational(in.readInt(), in.readInt()); 147 } 148 if (in.readInt() != 0) { 149 mUserActions = new ArrayList<>(); 150 in.readParcelableList(mUserActions, RemoteAction.class.getClassLoader()); 151 } 152 if (in.readInt() != 0) { 153 mSourceRectHint = Rect.CREATOR.createFromParcel(in); 154 } 155 } 156 157 /** {@hide} */ PictureInPictureParams(Rational aspectRatio, List<RemoteAction> actions, Rect sourceRectHint)158 PictureInPictureParams(Rational aspectRatio, List<RemoteAction> actions, 159 Rect sourceRectHint) { 160 mAspectRatio = aspectRatio; 161 mUserActions = actions; 162 mSourceRectHint = sourceRectHint; 163 } 164 165 /** 166 * Copies the set parameters from the other picture-in-picture args. 167 * @hide 168 */ copyOnlySet(PictureInPictureParams otherArgs)169 public void copyOnlySet(PictureInPictureParams otherArgs) { 170 if (otherArgs.hasSetAspectRatio()) { 171 mAspectRatio = otherArgs.mAspectRatio; 172 } 173 if (otherArgs.hasSetActions()) { 174 mUserActions = otherArgs.mUserActions; 175 } 176 if (otherArgs.hasSourceBoundsHint()) { 177 mSourceRectHint = new Rect(otherArgs.getSourceRectHint()); 178 } 179 } 180 181 /** 182 * @return the aspect ratio. If none is set, return 0. 183 * @hide 184 */ 185 @TestApi getAspectRatio()186 public float getAspectRatio() { 187 if (mAspectRatio != null) { 188 return mAspectRatio.floatValue(); 189 } 190 return 0f; 191 } 192 193 /** @hide */ getAspectRatioRational()194 public Rational getAspectRatioRational() { 195 return mAspectRatio; 196 } 197 198 /** 199 * @return whether the aspect ratio is set. 200 * @hide 201 */ hasSetAspectRatio()202 public boolean hasSetAspectRatio() { 203 return mAspectRatio != null; 204 } 205 206 /** 207 * @return the set of user actions. 208 * @hide 209 */ 210 @TestApi getActions()211 public List<RemoteAction> getActions() { 212 return mUserActions; 213 } 214 215 /** 216 * @return whether the user actions are set. 217 * @hide 218 */ hasSetActions()219 public boolean hasSetActions() { 220 return mUserActions != null; 221 } 222 223 /** 224 * Truncates the set of actions to the given {@param size}. 225 * @hide 226 */ truncateActions(int size)227 public void truncateActions(int size) { 228 if (hasSetActions()) { 229 mUserActions = mUserActions.subList(0, Math.min(mUserActions.size(), size)); 230 } 231 } 232 233 /** 234 * @return the source rect hint 235 * @hide 236 */ 237 @TestApi getSourceRectHint()238 public Rect getSourceRectHint() { 239 return mSourceRectHint; 240 } 241 242 /** 243 * @return whether there are launch bounds set 244 * @hide 245 */ hasSourceBoundsHint()246 public boolean hasSourceBoundsHint() { 247 return mSourceRectHint != null && !mSourceRectHint.isEmpty(); 248 } 249 250 /** 251 * @return True if no parameters are set 252 * @hide 253 */ empty()254 public boolean empty() { 255 return !hasSourceBoundsHint() && !hasSetActions() && !hasSetAspectRatio(); 256 } 257 258 @Override describeContents()259 public int describeContents() { 260 return 0; 261 } 262 263 @Override writeToParcel(Parcel out, int flags)264 public void writeToParcel(Parcel out, int flags) { 265 if (mAspectRatio != null) { 266 out.writeInt(1); 267 out.writeInt(mAspectRatio.getNumerator()); 268 out.writeInt(mAspectRatio.getDenominator()); 269 } else { 270 out.writeInt(0); 271 } 272 if (mUserActions != null) { 273 out.writeInt(1); 274 out.writeParcelableList(mUserActions, 0); 275 } else { 276 out.writeInt(0); 277 } 278 if (mSourceRectHint != null) { 279 out.writeInt(1); 280 mSourceRectHint.writeToParcel(out, 0); 281 } else { 282 out.writeInt(0); 283 } 284 } 285 286 public static final @android.annotation.NonNull Creator<PictureInPictureParams> CREATOR = 287 new Creator<PictureInPictureParams>() { 288 public PictureInPictureParams createFromParcel(Parcel in) { 289 return new PictureInPictureParams(in); 290 } 291 public PictureInPictureParams[] newArray(int size) { 292 return new PictureInPictureParams[size]; 293 } 294 }; 295 } 296