Home | History | Annotate | Download | only in media
      1 /*
      2  * Copyright (C) 2016 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 androidx.leanback.media;
     18 
     19 import android.content.Context;
     20 
     21 import androidx.annotation.CallSuper;
     22 
     23 import java.util.ArrayList;
     24 import java.util.List;
     25 
     26 /**
     27  * Base class for abstraction of media play/pause feature. A subclass of PlaybackGlue will contain
     28  * implementation of Media Player or a connection to playback Service. App initializes
     29  * PlaybackGlue subclass, associated it with a {@link PlaybackGlueHost}. {@link PlaybackGlueHost}
     30  * is typically implemented by a Fragment or an Activity, it provides the environment to render UI
     31  * for PlaybackGlue object, it optionally provides SurfaceHolder via {@link SurfaceHolderGlueHost}
     32  * to render video. A typical PlaybackGlue should release resources (e.g. MediaPlayer or connection
     33  * to playback Service) in {@link #onDetachedFromHost()}.
     34  * {@link #onDetachedFromHost()} is called in two cases:
     35  * <ul>
     36  * <li> app manually change it using {@link #setHost(PlaybackGlueHost)} call</li>
     37  * <li> When host (fragment or activity) is destroyed </li>
     38  * </ul>
     39  * In rare case if an PlaybackGlue wants to live outside fragment / activity life cycle, it may
     40  * manages resource release by itself.
     41  *
     42  * @see PlaybackGlueHost
     43  */
     44 public abstract class PlaybackGlue {
     45     private final Context mContext;
     46     private PlaybackGlueHost mPlaybackGlueHost;
     47 
     48     /**
     49      * Interface to allow clients to take action once the video is ready to play and start stop.
     50      */
     51     public abstract static class PlayerCallback {
     52         /**
     53          * Event for {@link #isPrepared()} changed.
     54          * @param glue The PlaybackGlue that has changed {@link #isPrepared()}.
     55          */
     56         public void onPreparedStateChanged(PlaybackGlue glue) {
     57         }
     58 
     59         /**
     60          * Event for Play/Pause state change. See {@link #isPlaying()}}.
     61          * @param glue The PlaybackGlue that has changed playing or pausing state.
     62          */
     63         public void onPlayStateChanged(PlaybackGlue glue) {
     64         }
     65 
     66         /**
     67          * Event of the current media is finished.
     68          * @param glue The PlaybackGlue that has finished current media playing.
     69          */
     70         public void onPlayCompleted(PlaybackGlue glue) {
     71         }
     72     }
     73 
     74     ArrayList<PlayerCallback> mPlayerCallbacks;
     75 
     76     /**
     77      * Constructor.
     78      */
     79     public PlaybackGlue(Context context) {
     80         this.mContext = context;
     81     }
     82 
     83     /**
     84      * Returns the context.
     85      */
     86     public Context getContext() {
     87         return mContext;
     88     }
     89 
     90     /**
     91      * Returns true when the media player is prepared to start media playback. When returning false,
     92      * app may listen to {@link PlayerCallback#onPreparedStateChanged(PlaybackGlue)} event.
     93      * @return True if prepared, false otherwise.
     94      */
     95     public boolean isPrepared() {
     96         return true;
     97     }
     98 
     99     /**
    100      * Add a PlayerCallback.
    101      * @param playerCallback The callback to add.
    102      */
    103     public void addPlayerCallback(PlayerCallback playerCallback) {
    104         if (mPlayerCallbacks == null) {
    105             mPlayerCallbacks = new ArrayList();
    106         }
    107         mPlayerCallbacks.add(playerCallback);
    108     }
    109 
    110     /**
    111      * Remove a PlayerCallback.
    112      * @param callback The callback to remove.
    113      */
    114     public void removePlayerCallback(PlayerCallback callback) {
    115         if (mPlayerCallbacks != null) {
    116             mPlayerCallbacks.remove(callback);
    117         }
    118     }
    119 
    120     /**
    121      * @return A snapshot of list of PlayerCallbacks set on the Glue.
    122      */
    123     protected List<PlayerCallback> getPlayerCallbacks() {
    124         if (mPlayerCallbacks == null) {
    125             return null;
    126         }
    127         return new ArrayList(mPlayerCallbacks);
    128     }
    129 
    130     /**
    131      * Returns true if media is currently playing.
    132      */
    133     public boolean isPlaying() {
    134         return false;
    135     }
    136 
    137     /**
    138      * Starts the media player. Does nothing if {@link #isPrepared()} is false. To wait
    139      * {@link #isPrepared()} to be true before playing, use {@link #playWhenPrepared()}.
    140      */
    141     public void play() {
    142     }
    143 
    144     /**
    145      * Starts play when {@link #isPrepared()} becomes true.
    146      */
    147     public void playWhenPrepared() {
    148         if (isPrepared()) {
    149             play();
    150         } else {
    151             addPlayerCallback(new PlayerCallback() {
    152                 @Override
    153                 public void onPreparedStateChanged(PlaybackGlue glue) {
    154                     if (glue.isPrepared()) {
    155                         removePlayerCallback(this);
    156                         play();
    157                     }
    158                 }
    159             });
    160         }
    161     }
    162 
    163     /**
    164      * Pauses the media player.
    165      */
    166     public void pause() {
    167     }
    168 
    169     /**
    170      * Goes to the next media item. This method is optional.
    171      */
    172     public void next() {
    173     }
    174 
    175     /**
    176      * Goes to the previous media item. This method is optional.
    177      */
    178     public void previous() {
    179     }
    180 
    181     /**
    182      * This method is used to associate a PlaybackGlue with the {@link PlaybackGlueHost} which
    183      * provides UI and optional {@link SurfaceHolderGlueHost}.
    184      *
    185      * @param host The host for the PlaybackGlue. Set to null to detach from the host.
    186      */
    187     public final void setHost(PlaybackGlueHost host) {
    188         if (mPlaybackGlueHost == host) {
    189             return;
    190         }
    191         if (mPlaybackGlueHost != null) {
    192             mPlaybackGlueHost.attachToGlue(null);
    193         }
    194         mPlaybackGlueHost = host;
    195         if (mPlaybackGlueHost != null) {
    196             mPlaybackGlueHost.attachToGlue(this);
    197         }
    198     }
    199 
    200     /**
    201      * This method is called when {@link PlaybackGlueHost is started. Subclass may override.
    202      */
    203     protected void onHostStart() {
    204     }
    205 
    206     /**
    207      * This method is called when {@link PlaybackGlueHost is stopped. Subclass may override.
    208      */
    209     protected void onHostStop() {
    210     }
    211 
    212     /**
    213      * This method is called when {@link PlaybackGlueHost is resumed. Subclass may override.
    214      */
    215     protected void onHostResume() {
    216     }
    217 
    218     /**
    219      * This method is called when {@link PlaybackGlueHost is paused. Subclass may override.
    220      */
    221     protected void onHostPause() {
    222     }
    223 
    224     /**
    225      * This method is called attached to associated {@link PlaybackGlueHost}. Subclass may override
    226      * and call super.onAttachedToHost().
    227      */
    228     @CallSuper
    229     protected void onAttachedToHost(PlaybackGlueHost host) {
    230         mPlaybackGlueHost = host;
    231         mPlaybackGlueHost.setHostCallback(new PlaybackGlueHost.HostCallback() {
    232             @Override
    233             public void onHostStart() {
    234                 PlaybackGlue.this.onHostStart();
    235             }
    236 
    237             @Override
    238             public void onHostStop() {
    239                 PlaybackGlue.this.onHostStop();
    240             }
    241 
    242             @Override
    243             public void onHostResume() {
    244                 PlaybackGlue.this.onHostResume();
    245             }
    246 
    247             @Override
    248             public void onHostPause() {
    249                 PlaybackGlue.this.onHostPause();
    250             }
    251 
    252             @Override
    253             public void onHostDestroy() {
    254                 setHost(null);
    255             }
    256         });
    257     }
    258 
    259     /**
    260      * This method is called when current associated {@link PlaybackGlueHost} is attached to a
    261      * different {@link PlaybackGlue} or {@link PlaybackGlueHost} is destroyed . Subclass may
    262      * override and call super.onDetachedFromHost() at last. A typical PlaybackGlue will release
    263      * resources (e.g. MediaPlayer or connection to playback service) in this method.
    264      */
    265     @CallSuper
    266     protected void onDetachedFromHost() {
    267         if (mPlaybackGlueHost != null) {
    268             mPlaybackGlueHost.setHostCallback(null);
    269             mPlaybackGlueHost = null;
    270         }
    271     }
    272 
    273     /**
    274      * @return Associated {@link PlaybackGlueHost} or null if not attached to host.
    275      */
    276     public PlaybackGlueHost getHost() {
    277         return mPlaybackGlueHost;
    278     }
    279 }
    280