Home | History | Annotate | Download | only in app
      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