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