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.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          */
     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          */
     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          */
     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          */
    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} */
    140     PictureInPictureParams() {
    141     }
    142 
    143     /** {@hide} */
    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} */
    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      */
    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
    186     public float getAspectRatio() {
    187         if (mAspectRatio != null) {
    188             return mAspectRatio.floatValue();
    189         }
    190         return 0f;
    191     }
    192 
    193     /** @hide */
    194     public Rational getAspectRatioRational() {
    195         return mAspectRatio;
    196     }
    197 
    198     /**
    199      * @return whether the aspect ratio is set.
    200      * @hide
    201      */
    202     public boolean hasSetAspectRatio() {
    203         return mAspectRatio != null;
    204     }
    205 
    206     /**
    207      * @return the set of user actions.
    208      * @hide
    209      */
    210     @TestApi
    211     public List<RemoteAction> getActions() {
    212         return mUserActions;
    213     }
    214 
    215     /**
    216      * @return whether the user actions are set.
    217      * @hide
    218      */
    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      */
    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
    238     public Rect getSourceRectHint() {
    239         return mSourceRectHint;
    240     }
    241 
    242     /**
    243      * @return whether there are launch bounds set
    244      * @hide
    245      */
    246     public boolean hasSourceBoundsHint() {
    247         return mSourceRectHint != null && !mSourceRectHint.isEmpty();
    248     }
    249 
    250     @Override
    251     public int describeContents() {
    252         return 0;
    253     }
    254 
    255     @Override
    256     public void writeToParcel(Parcel out, int flags) {
    257         if (mAspectRatio != null) {
    258             out.writeInt(1);
    259             out.writeInt(mAspectRatio.getNumerator());
    260             out.writeInt(mAspectRatio.getDenominator());
    261         } else {
    262             out.writeInt(0);
    263         }
    264         if (mUserActions != null) {
    265             out.writeInt(1);
    266             out.writeParcelableList(mUserActions, 0);
    267         } else {
    268             out.writeInt(0);
    269         }
    270         if (mSourceRectHint != null) {
    271             out.writeInt(1);
    272             mSourceRectHint.writeToParcel(out, 0);
    273         } else {
    274             out.writeInt(0);
    275         }
    276     }
    277 
    278     public static final @android.annotation.NonNull Creator<PictureInPictureParams> CREATOR =
    279             new Creator<PictureInPictureParams>() {
    280                 public PictureInPictureParams createFromParcel(Parcel in) {
    281                     return new PictureInPictureParams(in);
    282                 }
    283                 public PictureInPictureParams[] newArray(int size) {
    284                     return new PictureInPictureParams[size];
    285                 }
    286             };
    287 }
    288