Home | History | Annotate | Download | only in app
      1 // CHECKSTYLE:OFF Generated code
      2 /* This file is auto-generated from {}DetailsSupportFragmentBackgroundController.java.  DO NOT MODIFY. */
      3 
      4 /*
      5  * Copyright (C) 2017 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  */
     19 package androidx.leanback.app;
     20 
     21 import android.animation.PropertyValuesHolder;
     22 import android.app.Fragment;
     23 import android.graphics.Bitmap;
     24 import android.graphics.Color;
     25 import android.graphics.drawable.ColorDrawable;
     26 import android.graphics.drawable.Drawable;
     27 
     28 import androidx.annotation.ColorInt;
     29 import androidx.annotation.NonNull;
     30 import androidx.annotation.Nullable;
     31 import androidx.leanback.R;
     32 import androidx.leanback.graphics.FitWidthBitmapDrawable;
     33 import androidx.leanback.media.PlaybackGlue;
     34 import androidx.leanback.media.PlaybackGlueHost;
     35 import androidx.leanback.widget.DetailsParallaxDrawable;
     36 import androidx.leanback.widget.ParallaxTarget;
     37 
     38 /**
     39  * Controller for DetailsFragment parallax background and embedded video play.
     40  * <p>
     41  * The parallax background drawable is made of two parts: cover drawable (by default
     42  * {@link FitWidthBitmapDrawable}) above the details overview row and bottom drawable (by default
     43  * {@link ColorDrawable}) below the details overview row. While vertically scrolling rows, the size
     44  * of cover drawable and bottom drawable will be updated and the cover drawable will by default
     45  * perform a parallax shift using {@link FitWidthBitmapDrawable#PROPERTY_VERTICAL_OFFSET}.
     46  * </p>
     47  * <pre>
     48  *        ***************************
     49  *        *      Cover Drawable     *
     50  *        * (FitWidthBitmapDrawable)*
     51  *        *                         *
     52  *        ***************************
     53  *        *    DetailsOverviewRow   *
     54  *        *                         *
     55  *        ***************************
     56  *        *     Bottom Drawable     *
     57  *        *      (ColorDrawable)    *
     58  *        *         Related         *
     59  *        *         Content         *
     60  *        ***************************
     61  * </pre>
     62  * Both parallax background drawable and embedded video play are optional. App must call
     63  * {@link #enableParallax()} and/or {@link #setupVideoPlayback(PlaybackGlue)} explicitly.
     64  * The PlaybackGlue is automatically {@link PlaybackGlue#play()} when fragment starts and
     65  * {@link PlaybackGlue#pause()} when fragment stops. When video is ready to play, cover drawable
     66  * will be faded out.
     67  * Example:
     68  * <pre>
     69  * DetailsFragmentBackgroundController mController = new DetailsFragmentBackgroundController(this);
     70  *
     71  * public void onCreate(Bundle savedInstance) {
     72  *     super.onCreate(savedInstance);
     73  *     MediaPlayerGlue player = new MediaPlayerGlue(..);
     74  *     player.setUrl(...);
     75  *     mController.enableParallax();
     76  *     mController.setupVideoPlayback(player);
     77  * }
     78  *
     79  * static class MyLoadBitmapTask extends ... {
     80  *     WeakReference<MyFragment> mFragmentRef;
     81  *     MyLoadBitmapTask(MyFragment fragment) {
     82  *         mFragmentRef = new WeakReference(fragment);
     83  *     }
     84  *     protected void onPostExecute(Bitmap bitmap) {
     85  *         MyFragment fragment = mFragmentRef.get();
     86  *         if (fragment != null) {
     87  *             fragment.mController.setCoverBitmap(bitmap);
     88  *         }
     89  *     }
     90  * }
     91  *
     92  * public void onStart() {
     93  *     new MyLoadBitmapTask(this).execute(url);
     94  * }
     95  *
     96  * public void onStop() {
     97  *     mController.setCoverBitmap(null);
     98  * }
     99  * </pre>
    100  * <p>
    101  * To customize cover drawable and/or bottom drawable, app should call
    102  * {@link #enableParallax(Drawable, Drawable, ParallaxTarget.PropertyValuesHolderTarget)}.
    103  * If app supplies a custom cover Drawable, it should not call {@link #setCoverBitmap(Bitmap)}.
    104  * If app supplies a custom bottom Drawable, it should not call {@link #setSolidColor(int)}.
    105  * </p>
    106  * <p>
    107  * To customize playback fragment, app should override {@link #onCreateVideoFragment()} and
    108  * {@link #onCreateGlueHost()}.
    109  * </p>
    110  *
    111  * @deprecated use {@link DetailsSupportFragmentBackgroundController}
    112  */
    113 @Deprecated
    114 public class DetailsFragmentBackgroundController {
    115 
    116     final DetailsFragment mFragment;
    117     DetailsParallaxDrawable mParallaxDrawable;
    118     int mParallaxDrawableMaxOffset;
    119     PlaybackGlue mPlaybackGlue;
    120     DetailsBackgroundVideoHelper mVideoHelper;
    121     Bitmap mCoverBitmap;
    122     int mSolidColor;
    123     boolean mCanUseHost = false;
    124     boolean mInitialControlVisible = false;
    125 
    126     private Fragment mLastVideoFragmentForGlueHost;
    127 
    128     /**
    129      * Creates a DetailsFragmentBackgroundController for a DetailsFragment. Note that
    130      * each DetailsFragment can only associate with one DetailsFragmentBackgroundController.
    131      *
    132      * @param fragment The DetailsFragment to control background and embedded video playing.
    133      * @throws IllegalStateException If fragment was already associated with another controller.
    134      */
    135     public DetailsFragmentBackgroundController(DetailsFragment fragment) {
    136         if (fragment.mDetailsBackgroundController != null) {
    137             throw new IllegalStateException("Each DetailsFragment is allowed to initialize "
    138                     + "DetailsFragmentBackgroundController once");
    139         }
    140         fragment.mDetailsBackgroundController = this;
    141         mFragment = fragment;
    142     }
    143 
    144     /**
    145      * Enables default parallax background using a {@link FitWidthBitmapDrawable} as cover drawable
    146      * and {@link ColorDrawable} as bottom drawable. A vertical parallax movement will be applied
    147      * to the FitWidthBitmapDrawable. App may use {@link #setSolidColor(int)} and
    148      * {@link #setCoverBitmap(Bitmap)} to change the content of bottom drawable and cover drawable.
    149      * This method must be called before {@link #setupVideoPlayback(PlaybackGlue)}.
    150      *
    151      * @see #setCoverBitmap(Bitmap)
    152      * @see #setSolidColor(int)
    153      * @throws IllegalStateException If {@link #setupVideoPlayback(PlaybackGlue)} was called.
    154      */
    155     public void enableParallax() {
    156         int offset = mParallaxDrawableMaxOffset;
    157         if (offset == 0) {
    158             offset = FragmentUtil.getContext(mFragment).getResources()
    159                     .getDimensionPixelSize(R.dimen.lb_details_cover_drawable_parallax_movement);
    160         }
    161         Drawable coverDrawable = new FitWidthBitmapDrawable();
    162         ColorDrawable colorDrawable = new ColorDrawable();
    163         enableParallax(coverDrawable, colorDrawable,
    164                 new ParallaxTarget.PropertyValuesHolderTarget(
    165                         coverDrawable,
    166                         PropertyValuesHolder.ofInt(FitWidthBitmapDrawable.PROPERTY_VERTICAL_OFFSET,
    167                                 0, -offset)
    168                 ));
    169     }
    170 
    171     /**
    172      * Enables parallax background using a custom cover drawable at top and a custom bottom
    173      * drawable. This method must be called before {@link #setupVideoPlayback(PlaybackGlue)}.
    174      *
    175      * @param coverDrawable Custom cover drawable shown at top. {@link #setCoverBitmap(Bitmap)}
    176      *                      will not work if coverDrawable is not {@link FitWidthBitmapDrawable};
    177      *                      in that case it's app's responsibility to set content into
    178      *                      coverDrawable.
    179      * @param bottomDrawable Drawable shown at bottom. {@link #setSolidColor(int)} will not work
    180      *                       if bottomDrawable is not {@link ColorDrawable}; in that case it's app's
    181      *                       responsibility to set content of bottomDrawable.
    182      * @param coverDrawableParallaxTarget Target to perform parallax effect within coverDrawable.
    183      *                                    Use null for no parallax movement effect.
    184      *                                    Example to move bitmap within FitWidthBitmapDrawable:
    185      *                                    new ParallaxTarget.PropertyValuesHolderTarget(
    186      *                                        coverDrawable, PropertyValuesHolder.ofInt(
    187      *                                            FitWidthBitmapDrawable.PROPERTY_VERTICAL_OFFSET,
    188      *                                            0, -120))
    189      * @throws IllegalStateException If {@link #setupVideoPlayback(PlaybackGlue)} was called.
    190      */
    191     public void enableParallax(@NonNull Drawable coverDrawable, @NonNull Drawable bottomDrawable,
    192                                @Nullable ParallaxTarget.PropertyValuesHolderTarget
    193                                        coverDrawableParallaxTarget) {
    194         if (mParallaxDrawable != null) {
    195             return;
    196         }
    197         // if bitmap is set before enableParallax, use it as initial value.
    198         if (mCoverBitmap != null && coverDrawable instanceof FitWidthBitmapDrawable) {
    199             ((FitWidthBitmapDrawable) coverDrawable).setBitmap(mCoverBitmap);
    200         }
    201         // if solid color is set before enableParallax, use it as initial value.
    202         if (mSolidColor != Color.TRANSPARENT && bottomDrawable instanceof ColorDrawable) {
    203             ((ColorDrawable) bottomDrawable).setColor(mSolidColor);
    204         }
    205         if (mPlaybackGlue != null) {
    206             throw new IllegalStateException("enableParallaxDrawable must be called before "
    207                     + "enableVideoPlayback");
    208         }
    209         mParallaxDrawable = new DetailsParallaxDrawable(
    210                 FragmentUtil.getContext(mFragment),
    211                 mFragment.getParallax(),
    212                 coverDrawable,
    213                 bottomDrawable,
    214                 coverDrawableParallaxTarget);
    215         mFragment.setBackgroundDrawable(mParallaxDrawable);
    216         // create a VideoHelper with null PlaybackGlue for changing CoverDrawable visibility
    217         // before PlaybackGlue is ready.
    218         mVideoHelper = new DetailsBackgroundVideoHelper(null,
    219                 mFragment.getParallax(), mParallaxDrawable.getCoverDrawable());
    220     }
    221 
    222     /**
    223      * Enable video playback and set proper {@link PlaybackGlueHost}. This method by default
    224      * creates a VideoFragment and VideoFragmentGlueHost to host the PlaybackGlue.
    225      * This method must be called after calling details Fragment super.onCreate(). This method
    226      * can be called multiple times to replace existing PlaybackGlue or calling
    227      * setupVideoPlayback(null) to clear. Note a typical {@link PlaybackGlue} subclass releases
    228      * resources in {@link PlaybackGlue#onDetachedFromHost()}, when the {@link PlaybackGlue}
    229      * subclass is not doing that, it's app's responsibility to release the resources.
    230      *
    231      * @param playbackGlue The new PlaybackGlue to set as background or null to clear existing one.
    232      * @see #onCreateVideoFragment()
    233      * @see #onCreateGlueHost().
    234      */
    235     @SuppressWarnings("ReferenceEquality")
    236     public void setupVideoPlayback(@NonNull PlaybackGlue playbackGlue) {
    237         if (mPlaybackGlue == playbackGlue) {
    238             return;
    239         }
    240 
    241         PlaybackGlueHost playbackGlueHost = null;
    242         if (mPlaybackGlue != null) {
    243             playbackGlueHost = mPlaybackGlue.getHost();
    244             mPlaybackGlue.setHost(null);
    245         }
    246 
    247         mPlaybackGlue = playbackGlue;
    248         mVideoHelper.setPlaybackGlue(mPlaybackGlue);
    249         if (mCanUseHost && mPlaybackGlue != null) {
    250             if (playbackGlueHost == null
    251                     || mLastVideoFragmentForGlueHost != findOrCreateVideoFragment()) {
    252                 mPlaybackGlue.setHost(createGlueHost());
    253                 mLastVideoFragmentForGlueHost = findOrCreateVideoFragment();
    254             } else {
    255                 mPlaybackGlue.setHost(playbackGlueHost);
    256             }
    257         }
    258     }
    259 
    260     /**
    261      * Returns current PlaybackGlue or null if not set or cleared.
    262      *
    263      * @return Current PlaybackGlue or null
    264      */
    265     public final PlaybackGlue getPlaybackGlue() {
    266         return mPlaybackGlue;
    267     }
    268 
    269     /**
    270      * Precondition allows user navigate to video fragment using DPAD. Default implementation
    271      * returns true if PlaybackGlue is not null. Subclass may override, e.g. only allow navigation
    272      * when {@link PlaybackGlue#isPrepared()} is true. Note this method does not block
    273      * app calls {@link #switchToVideo}.
    274      *
    275      * @return True allow to navigate to video fragment.
    276      */
    277     public boolean canNavigateToVideoFragment() {
    278         return mPlaybackGlue != null;
    279     }
    280 
    281     void switchToVideoBeforeCreate() {
    282         mVideoHelper.crossFadeBackgroundToVideo(true, true);
    283         mInitialControlVisible = true;
    284     }
    285 
    286     /**
    287      * Switch to video fragment, note that this method is not affected by result of
    288      * {@link #canNavigateToVideoFragment()}. If the method is called in DetailsFragment.onCreate()
    289      * it will make video fragment to be initially focused once it is created.
    290      * <p>
    291      * Calling switchToVideo() in DetailsFragment.onCreate() will clear the activity enter
    292      * transition and shared element transition.
    293      * </p>
    294      * <p>
    295      * If switchToVideo() is called after {@link DetailsFragment#prepareEntranceTransition()} and
    296      * before {@link DetailsFragment#onEntranceTransitionEnd()}, it will be ignored.
    297      * </p>
    298      * <p>
    299      * If {@link DetailsFragment#prepareEntranceTransition()} is called after switchToVideo(), an
    300      * IllegalStateException will be thrown.
    301      * </p>
    302      */
    303     public final void switchToVideo() {
    304         mFragment.switchToVideo();
    305     }
    306 
    307     /**
    308      * Switch to rows fragment.
    309      */
    310     public final void switchToRows() {
    311         mFragment.switchToRows();
    312     }
    313 
    314     /**
    315      * When fragment is started and no running transition. First set host if not yet set, second
    316      * start playing if it was paused before.
    317      */
    318     void onStart() {
    319         if (!mCanUseHost) {
    320             mCanUseHost = true;
    321             if (mPlaybackGlue != null) {
    322                 mPlaybackGlue.setHost(createGlueHost());
    323                 mLastVideoFragmentForGlueHost = findOrCreateVideoFragment();
    324             }
    325         }
    326         if (mPlaybackGlue != null && mPlaybackGlue.isPrepared()) {
    327             mPlaybackGlue.play();
    328         }
    329     }
    330 
    331     void onStop() {
    332         if (mPlaybackGlue != null) {
    333             mPlaybackGlue.pause();
    334         }
    335     }
    336 
    337     /**
    338      * Disable parallax that would auto-start video playback
    339      * @return true if video fragment is visible or false otherwise.
    340      */
    341     boolean disableVideoParallax() {
    342         if (mVideoHelper != null) {
    343             mVideoHelper.stopParallax();
    344             return mVideoHelper.isVideoVisible();
    345         }
    346         return false;
    347     }
    348 
    349     /**
    350      * Returns the cover drawable at top. Returns null if {@link #enableParallax()} is not called.
    351      * By default it's a {@link FitWidthBitmapDrawable}.
    352      *
    353      * @return The cover drawable at top.
    354      */
    355     public final Drawable getCoverDrawable() {
    356         if (mParallaxDrawable == null) {
    357             return null;
    358         }
    359         return mParallaxDrawable.getCoverDrawable();
    360     }
    361 
    362     /**
    363      * Returns the drawable at bottom. Returns null if {@link #enableParallax()} is not called.
    364      * By default it's a {@link ColorDrawable}.
    365      *
    366      * @return The bottom drawable.
    367      */
    368     public final Drawable getBottomDrawable() {
    369         if (mParallaxDrawable == null) {
    370             return null;
    371         }
    372         return mParallaxDrawable.getBottomDrawable();
    373     }
    374 
    375     /**
    376      * Creates a Fragment to host {@link PlaybackGlue}. Returns a new {@link VideoFragment} by
    377      * default. App may override and return a different fragment and it also must override
    378      * {@link #onCreateGlueHost()}.
    379      *
    380      * @return A new fragment used in {@link #onCreateGlueHost()}.
    381      * @see #onCreateGlueHost()
    382      * @see #setupVideoPlayback(PlaybackGlue)
    383      */
    384     public Fragment onCreateVideoFragment() {
    385         return new VideoFragment();
    386     }
    387 
    388     /**
    389      * Creates a PlaybackGlueHost to host PlaybackGlue. App may override this if it overrides
    390      * {@link #onCreateVideoFragment()}. This method must be called after calling Fragment
    391      * super.onCreate(). When override this method, app may call
    392      * {@link #findOrCreateVideoFragment()} to get or create a fragment.
    393      *
    394      * @return A new PlaybackGlueHost to host PlaybackGlue.
    395      * @see #onCreateVideoFragment()
    396      * @see #findOrCreateVideoFragment()
    397      * @see #setupVideoPlayback(PlaybackGlue)
    398      */
    399     public PlaybackGlueHost onCreateGlueHost() {
    400         return new VideoFragmentGlueHost((VideoFragment) findOrCreateVideoFragment());
    401     }
    402 
    403     PlaybackGlueHost createGlueHost() {
    404         PlaybackGlueHost host = onCreateGlueHost();
    405         if (mInitialControlVisible) {
    406             host.showControlsOverlay(false);
    407         } else {
    408             host.hideControlsOverlay(false);
    409         }
    410         return host;
    411     }
    412 
    413     /**
    414      * Adds or gets fragment for rendering video in DetailsFragment. A subclass that
    415      * overrides {@link #onCreateGlueHost()} should call this method to get a fragment for creating
    416      * a {@link PlaybackGlueHost}.
    417      *
    418      * @return Fragment the added or restored fragment responsible for rendering video.
    419      * @see #onCreateGlueHost()
    420      */
    421     public final Fragment findOrCreateVideoFragment() {
    422         return mFragment.findOrCreateVideoFragment();
    423     }
    424 
    425     /**
    426      * Convenient method to set Bitmap in cover drawable. If app is not using default
    427      * {@link FitWidthBitmapDrawable}, app should not use this method  It's safe to call
    428      * setCoverBitmap() before calling {@link #enableParallax()}.
    429      *
    430      * @param bitmap bitmap to set as cover.
    431      */
    432     public final void setCoverBitmap(Bitmap bitmap) {
    433         mCoverBitmap = bitmap;
    434         Drawable drawable = getCoverDrawable();
    435         if (drawable instanceof FitWidthBitmapDrawable) {
    436             ((FitWidthBitmapDrawable) drawable).setBitmap(mCoverBitmap);
    437         }
    438     }
    439 
    440     /**
    441      * Returns Bitmap set by {@link #setCoverBitmap(Bitmap)}.
    442      *
    443      * @return Bitmap for cover drawable.
    444      */
    445     public final Bitmap getCoverBitmap() {
    446         return mCoverBitmap;
    447     }
    448 
    449     /**
    450      * Returns color set by {@link #setSolidColor(int)}.
    451      *
    452      * @return Solid color used for bottom drawable.
    453      */
    454     public final @ColorInt int getSolidColor() {
    455         return mSolidColor;
    456     }
    457 
    458     /**
    459      * Convenient method to set color in bottom drawable. If app is not using default
    460      * {@link ColorDrawable}, app should not use this method. It's safe to call setSolidColor()
    461      * before calling {@link #enableParallax()}.
    462      *
    463      * @param color color for bottom drawable.
    464      */
    465     public final void setSolidColor(@ColorInt int color) {
    466         mSolidColor = color;
    467         Drawable bottomDrawable = getBottomDrawable();
    468         if (bottomDrawable instanceof ColorDrawable) {
    469             ((ColorDrawable) bottomDrawable).setColor(color);
    470         }
    471     }
    472 
    473     /**
    474      * Sets default parallax offset in pixels for bitmap moving vertically. This method must
    475      * be called before {@link #enableParallax()}.
    476      *
    477      * @param offset Offset in pixels (e.g. 120).
    478      * @see #enableParallax()
    479      */
    480     public final void setParallaxDrawableMaxOffset(int offset) {
    481         if (mParallaxDrawable != null) {
    482             throw new IllegalStateException("enableParallax already called");
    483         }
    484         mParallaxDrawableMaxOffset = offset;
    485     }
    486 
    487     /**
    488      * Returns Default parallax offset in pixels for bitmap moving vertically.
    489      * When 0, a default value would be used.
    490      *
    491      * @return Default parallax offset in pixels for bitmap moving vertically.
    492      * @see #enableParallax()
    493      */
    494     public final int getParallaxDrawableMaxOffset() {
    495         return mParallaxDrawableMaxOffset;
    496     }
    497 
    498 }
    499