Home | History | Annotate | Download | only in media
      1 /*
      2  * Copyright (C) 2013 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 com.example.android.supportv4.media;
     18 
     19 //BEGIN_INCLUDE(complete)
     20 import android.support.v4.media.TransportMediator;
     21 import android.support.v4.media.TransportPerformer;
     22 import com.example.android.supportv4.R;
     23 
     24 import android.app.ActionBar;
     25 import android.content.Context;
     26 import android.media.MediaPlayer;
     27 import android.os.Handler;
     28 import android.util.AttributeSet;
     29 import android.view.KeyEvent;
     30 import android.view.View;
     31 
     32 import android.app.Activity;
     33 import android.net.Uri;
     34 import android.os.Bundle;
     35 import android.widget.VideoView;
     36 
     37 public class TransportControllerActivity extends Activity {
     38 
     39     /**
     40      * TODO: Set the path variable to a streaming video URL or a local media
     41      * file path.
     42      */
     43     private Content mContent;
     44     private TransportMediator mTransportMediator;
     45     private MediaController mMediaController;
     46 
     47     /**
     48      * Handle actions from on-screen media controls.  Most of these are simple re-directs
     49      * to the VideoView; some we need to capture to update our state.
     50      */
     51     TransportPerformer mTransportPerformer = new TransportPerformer() {
     52         @Override public void onStart() {
     53             mContent.start();
     54         }
     55 
     56         @Override public void onStop() {
     57             mContent.pause();
     58         }
     59 
     60         @Override public void onPause() {
     61             mContent.pause();
     62         }
     63 
     64         @Override public long onGetDuration() {
     65             return mContent.getDuration();
     66         }
     67 
     68         @Override public long onGetCurrentPosition() {
     69             return mContent.getCurrentPosition();
     70         }
     71 
     72         @Override public void onSeekTo(long pos) {
     73             mContent.seekTo((int)pos);
     74         }
     75 
     76         @Override public boolean onIsPlaying() {
     77             return mContent.isPlaying();
     78         }
     79 
     80         @Override public int onGetBufferPercentage() {
     81             return mContent.getBufferPercentage();
     82         }
     83 
     84         @Override public int onGetTransportControlFlags() {
     85             int flags = TransportMediator.FLAG_KEY_MEDIA_PLAY
     86                     | TransportMediator.FLAG_KEY_MEDIA_PLAY_PAUSE
     87                     | TransportMediator.FLAG_KEY_MEDIA_STOP;
     88             if (mContent.canPause()) {
     89                 flags |= TransportMediator.FLAG_KEY_MEDIA_PAUSE;
     90             }
     91             if (mContent.canSeekBackward()) {
     92                 flags |= TransportMediator.FLAG_KEY_MEDIA_REWIND;
     93             }
     94             if (mContent.canSeekForward()) {
     95                 flags |= TransportMediator.FLAG_KEY_MEDIA_FAST_FORWARD;
     96             }
     97             return flags;
     98         }
     99     };
    100 
    101     /**
    102      * This is the actual video player.  It is the top-level content of
    103      * the activity's view hierarchy, going under the status bar and nav
    104      * bar areas.
    105      */
    106     public static class Content extends VideoView implements
    107             View.OnSystemUiVisibilityChangeListener, View.OnClickListener,
    108             ActionBar.OnMenuVisibilityListener, MediaPlayer.OnPreparedListener,
    109             MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener {
    110         Activity mActivity;
    111         TransportMediator mTransportMediator;
    112         MediaController mMediaController;
    113         boolean mAddedMenuListener;
    114         boolean mMenusOpen;
    115         boolean mPaused;
    116         boolean mNavVisible;
    117         int mLastSystemUiVis;
    118 
    119         Runnable mNavHider = new Runnable() {
    120             @Override public void run() {
    121                 setNavVisibility(false);
    122             }
    123         };
    124 
    125         Runnable mProgressUpdater = new Runnable() {
    126             @Override public void run() {
    127                 mMediaController.updateProgress();
    128                 getHandler().postDelayed(this, 1000);
    129             }
    130         };
    131 
    132         public Content(Context context, AttributeSet attrs) {
    133             super(context, attrs);
    134             setOnSystemUiVisibilityChangeListener(this);
    135             setOnClickListener(this);
    136             setOnPreparedListener(this);
    137             setOnCompletionListener(this);
    138             setOnErrorListener(this);
    139         }
    140 
    141         public void init(Activity activity, TransportMediator transportMediator,
    142                 MediaController mediaController) {
    143             // This called by the containing activity to supply the surrounding
    144             // state of the video player that it will interact with.
    145             mActivity = activity;
    146             mTransportMediator = transportMediator;
    147             mMediaController = mediaController;
    148             pause();
    149         }
    150 
    151         @Override protected void onAttachedToWindow() {
    152             super.onAttachedToWindow();
    153             if (mActivity != null) {
    154                 mAddedMenuListener = true;
    155                 mActivity.getActionBar().addOnMenuVisibilityListener(this);
    156             }
    157         }
    158 
    159         @Override protected void onDetachedFromWindow() {
    160             super.onDetachedFromWindow();
    161             if (mAddedMenuListener) {
    162                 mActivity.getActionBar().removeOnMenuVisibilityListener(this);
    163             }
    164             mNavVisible = false;
    165         }
    166 
    167         @Override public void onSystemUiVisibilityChange(int visibility) {
    168             // Detect when we go out of nav-hidden mode, to clear our state
    169             // back to having the full UI chrome up.  Only do this when
    170             // the state is changing and nav is no longer hidden.
    171             int diff = mLastSystemUiVis ^ visibility;
    172             mLastSystemUiVis = visibility;
    173             if ((diff&SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
    174                     && (visibility&SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
    175                 setNavVisibility(true);
    176             }
    177         }
    178 
    179         @Override protected void onWindowVisibilityChanged(int visibility) {
    180             super.onWindowVisibilityChanged(visibility);
    181 
    182             // When we become visible or invisible, play is paused.
    183             pause();
    184         }
    185 
    186         @Override public void onClick(View v) {
    187             // Clicking anywhere makes the navigation visible.
    188             setNavVisibility(true);
    189         }
    190 
    191         @Override public void onMenuVisibilityChanged(boolean isVisible) {
    192             mMenusOpen = isVisible;
    193             setNavVisibility(true);
    194         }
    195 
    196         @Override
    197         public void onPrepared(MediaPlayer mp) {
    198             mMediaController.setEnabled(true);
    199         }
    200 
    201         @Override
    202         public void onCompletion(MediaPlayer mp) {
    203             mTransportMediator.pausePlaying();
    204             pause();
    205         }
    206 
    207         @Override
    208         public boolean onError(MediaPlayer mp, int what, int extra) {
    209             mTransportMediator.pausePlaying();
    210             pause();
    211             return false;
    212         }
    213 
    214         @Override public void start() {
    215             super.start();
    216             mPaused = false;
    217             setKeepScreenOn(true);
    218             setNavVisibility(true);
    219             mMediaController.refresh();
    220             scheduleProgressUpdater();
    221         }
    222 
    223         @Override public void pause() {
    224             super.pause();
    225             mPaused = true;
    226             setKeepScreenOn(false);
    227             setNavVisibility(true);
    228             mMediaController.refresh();
    229             scheduleProgressUpdater();
    230         }
    231 
    232         void scheduleProgressUpdater() {
    233             Handler h = getHandler();
    234             if (h != null) {
    235                 if (mNavVisible && !mPaused) {
    236                     h.removeCallbacks(mProgressUpdater);
    237                     h.post(mProgressUpdater);
    238                 } else {
    239                     h.removeCallbacks(mProgressUpdater);
    240                 }
    241             }
    242         }
    243 
    244         void setNavVisibility(boolean visible) {
    245             int newVis = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
    246                     | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
    247                     | SYSTEM_UI_FLAG_LAYOUT_STABLE;
    248             if (!visible) {
    249                 newVis |= SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_FULLSCREEN
    250                         | SYSTEM_UI_FLAG_HIDE_NAVIGATION;
    251             }
    252 
    253             // If we are now visible, schedule a timer for us to go invisible.
    254             if (visible) {
    255                 Handler h = getHandler();
    256                 if (h != null) {
    257                     h.removeCallbacks(mNavHider);
    258                     if (!mMenusOpen && !mPaused) {
    259                         // If the menus are open or play is paused, we will not auto-hide.
    260                         h.postDelayed(mNavHider, 3000);
    261                     }
    262                 }
    263             }
    264 
    265             // Set the new desired visibility.
    266             setSystemUiVisibility(newVis);
    267             mNavVisible = visible;
    268             mMediaController.setVisibility(visible ? VISIBLE : INVISIBLE);
    269             scheduleProgressUpdater();
    270         }
    271     }
    272 
    273     @Override
    274     public void onCreate(Bundle icicle) {
    275         super.onCreate(icicle);
    276         setContentView(R.layout.videoview);
    277 
    278         // Find the video player in our UI.
    279         mContent = (Content) findViewById(R.id.content);
    280 
    281         // Create transport controller to control video, giving the callback
    282         // interface to receive actions from.
    283         mTransportMediator = new TransportMediator(this, mTransportPerformer);
    284 
    285         // Create and initialize the media control UI.
    286         mMediaController = (MediaController) findViewById(R.id.media_controller);
    287         mMediaController.setMediaPlayer(mTransportMediator);
    288 
    289         // We're just playing a built-in demo video.
    290         mContent.init(this, mTransportMediator, mMediaController);
    291         mContent.setVideoURI(Uri.parse("android.resource://" + getPackageName() +
    292                 "/" + R.raw.videoviewdemo));
    293     }
    294 
    295     @Override
    296     public boolean dispatchKeyEvent(KeyEvent event) {
    297         // We first dispatch keys to the transport controller -- we want it
    298         // to get to consume any media keys rather than letting whoever has focus
    299         // in the view hierarchy to potentially eat it.
    300         if (mTransportMediator.dispatchKeyEvent(event)) {
    301             return true;
    302         }
    303 
    304         return super.dispatchKeyEvent(event);
    305     }
    306 }
    307 //END_INCLUDE(complete)
    308