Most visited

Recently visited

TransportMediator

public class TransportMediator
extends TransportController

java.lang.Object
   ↳ android.support.v4.media.TransportController
     ↳ android.support.v4.media.TransportMediator


Helper for implementing a media transport control (with play, pause, skip, and other media actions). Takes care of both key events and advanced features like RemoteControlClient. This class is intended to serve as an intermediary between transport controls (whether they be on-screen controls, hardware buttons, remote controls) and the actual player. The player is represented by a single TransportPerformer that must be supplied to this class. On-screen controls that want to control and show the state of the player should do this through calls to the TransportController interface.

Here is a simple but fairly complete sample of a video player that is built around this class. Note that the MediaController class used here is not the one included in the standard Android framework, but a custom implementation. Real applications often implement their own transport controls, or you can copy the implementation here out of Support4Demos.

import android.support.v4.media.TransportMediator;
import android.support.v4.media.TransportPerformer;
import com.example.android.supportv4.R;

import android.app.ActionBar;
import android.content.Context;
import android.media.MediaPlayer;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;

import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.widget.VideoView;

public class TransportControllerActivity extends Activity {

    /**
     * TODO: Set the path variable to a streaming video URL or a local media
     * file path.
     */
    private Content mContent;
    private TransportMediator mTransportMediator;
    private MediaController mMediaController;

    /**
     * Handle actions from on-screen media controls.  Most of these are simple re-directs
     * to the VideoView; some we need to capture to update our state.
     */
    TransportPerformer mTransportPerformer = new TransportPerformer() {
        @Override public void onStart() {
            mContent.start();
        }

        @Override public void onStop() {
            mContent.pause();
        }

        @Override public void onPause() {
            mContent.pause();
        }

        @Override public long onGetDuration() {
            return mContent.getDuration();
        }

        @Override public long onGetCurrentPosition() {
            return mContent.getCurrentPosition();
        }

        @Override public void onSeekTo(long pos) {
            mContent.seekTo((int)pos);
        }

        @Override public boolean onIsPlaying() {
            return mContent.isPlaying();
        }

        @Override public int onGetBufferPercentage() {
            return mContent.getBufferPercentage();
        }

        @Override public int onGetTransportControlFlags() {
            int flags = TransportMediator.FLAG_KEY_MEDIA_PLAY
                    | TransportMediator.FLAG_KEY_MEDIA_PLAY_PAUSE
                    | TransportMediator.FLAG_KEY_MEDIA_STOP;
            if (mContent.canPause()) {
                flags |= TransportMediator.FLAG_KEY_MEDIA_PAUSE;
            }
            if (mContent.canSeekBackward()) {
                flags |= TransportMediator.FLAG_KEY_MEDIA_REWIND;
            }
            if (mContent.canSeekForward()) {
                flags |= TransportMediator.FLAG_KEY_MEDIA_FAST_FORWARD;
            }
            return flags;
        }
    };

    /**
     * This is the actual video player.  It is the top-level content of
     * the activity's view hierarchy, going under the status bar and nav
     * bar areas.
     */
    public static class Content extends VideoView implements
            View.OnSystemUiVisibilityChangeListener, View.OnClickListener,
            ActionBar.OnMenuVisibilityListener, MediaPlayer.OnPreparedListener,
            MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener {
        Activity mActivity;
        TransportMediator mTransportMediator;
        MediaController mMediaController;
        boolean mAddedMenuListener;
        boolean mMenusOpen;
        boolean mPaused;
        boolean mNavVisible;
        int mLastSystemUiVis;

        Runnable mNavHider = new Runnable() {
            @Override public void run() {
                setNavVisibility(false);
            }
        };

        Runnable mProgressUpdater = new Runnable() {
            @Override public void run() {
                mMediaController.updateProgress();
                getHandler().postDelayed(this, 1000);
            }
        };

        public Content(Context context, AttributeSet attrs) {
            super(context, attrs);
            setOnSystemUiVisibilityChangeListener(this);
            setOnClickListener(this);
            setOnPreparedListener(this);
            setOnCompletionListener(this);
            setOnErrorListener(this);
        }

        public void init(Activity activity, TransportMediator transportMediator,
                MediaController mediaController) {
            // This called by the containing activity to supply the surrounding
            // state of the video player that it will interact with.
            mActivity = activity;
            mTransportMediator = transportMediator;
            mMediaController = mediaController;
            pause();
        }

        @Override protected void onAttachedToWindow() {
            super.onAttachedToWindow();
            if (mActivity != null) {
                mAddedMenuListener = true;
                mActivity.getActionBar().addOnMenuVisibilityListener(this);
            }
        }

        @Override protected void onDetachedFromWindow() {
            super.onDetachedFromWindow();
            if (mAddedMenuListener) {
                mActivity.getActionBar().removeOnMenuVisibilityListener(this);
            }
            mNavVisible = false;
        }

        @Override public void onSystemUiVisibilityChange(int visibility) {
            // Detect when we go out of nav-hidden mode, to clear our state
            // back to having the full UI chrome up.  Only do this when
            // the state is changing and nav is no longer hidden.
            int diff = mLastSystemUiVis ^ visibility;
            mLastSystemUiVis = visibility;
            if ((diff&SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
                    && (visibility&SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
                setNavVisibility(true);
            }
        }

        @Override protected void onWindowVisibilityChanged(int visibility) {
            super.onWindowVisibilityChanged(visibility);

            // When we become visible or invisible, play is paused.
            pause();
        }

        @Override public void onClick(View v) {
            // Clicking anywhere makes the navigation visible.
            setNavVisibility(true);
        }

        @Override public void onMenuVisibilityChanged(boolean isVisible) {
            mMenusOpen = isVisible;
            setNavVisibility(true);
        }

        @Override
        public void onPrepared(MediaPlayer mp) {
            mMediaController.setEnabled(true);
        }

        @Override
        public void onCompletion(MediaPlayer mp) {
            mTransportMediator.pausePlaying();
            pause();
        }

        @Override
        public boolean onError(MediaPlayer mp, int what, int extra) {
            mTransportMediator.pausePlaying();
            pause();
            return false;
        }

        @Override public void start() {
            super.start();
            mPaused = false;
            setKeepScreenOn(true);
            setNavVisibility(true);
            mMediaController.refresh();
            scheduleProgressUpdater();
        }

        @Override public void pause() {
            super.pause();
            mPaused = true;
            setKeepScreenOn(false);
            setNavVisibility(true);
            mMediaController.refresh();
            scheduleProgressUpdater();
        }

        void scheduleProgressUpdater() {
            Handler h = getHandler();
            if (h != null) {
                if (mNavVisible && !mPaused) {
                    h.removeCallbacks(mProgressUpdater);
                    h.post(mProgressUpdater);
                } else {
                    h.removeCallbacks(mProgressUpdater);
                }
            }
        }

        void setNavVisibility(boolean visible) {
            int newVis = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | SYSTEM_UI_FLAG_LAYOUT_STABLE;
            if (!visible) {
                newVis |= SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_FULLSCREEN
                        | SYSTEM_UI_FLAG_HIDE_NAVIGATION;
            }

            // If we are now visible, schedule a timer for us to go invisible.
            if (visible) {
                Handler h = getHandler();
                if (h != null) {
                    h.removeCallbacks(mNavHider);
                    if (!mMenusOpen && !mPaused) {
                        // If the menus are open or play is paused, we will not auto-hide.
                        h.postDelayed(mNavHider, 3000);
                    }
                }
            }

            // Set the new desired visibility.
            setSystemUiVisibility(newVis);
            mNavVisible = visible;
            mMediaController.setVisibility(visible ? VISIBLE : INVISIBLE);
            scheduleProgressUpdater();
        }
    }

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.videoview);

        // Find the video player in our UI.
        mContent = (Content) findViewById(R.id.content);

        // Create transport controller to control video, giving the callback
        // interface to receive actions from.
        mTransportMediator = new TransportMediator(this, mTransportPerformer);

        // Create and initialize the media control UI.
        mMediaController = (MediaController) findViewById(R.id.media_controller);
        mMediaController.setMediaPlayer(mTransportMediator);

        // We're just playing a built-in demo video.
        mContent.init(this, mTransportMediator, mMediaController);
        mContent.setVideoURI(Uri.parse("android.resource://" + getPackageName() +
                "/" + R.raw.videoviewdemo));
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        // We first dispatch keys to the transport controller -- we want it
        // to get to consume any media keys rather than letting whoever has focus
        // in the view hierarchy to potentially eat it.
        if (mTransportMediator.dispatchKeyEvent(event)) {
            return true;
        }

        return super.dispatchKeyEvent(event);
    }
}

Summary

Constants

int FLAG_KEY_MEDIA_FAST_FORWARD

Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_FAST_FORWARD RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD

int FLAG_KEY_MEDIA_NEXT

Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_NEXT RemoteControlClient.FLAG_KEY_MEDIA_NEXT

int FLAG_KEY_MEDIA_PAUSE

Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PAUSE RemoteControlClient.FLAG_KEY_MEDIA_PAUSE

int FLAG_KEY_MEDIA_PLAY

Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PLAY RemoteControlClient.FLAG_KEY_MEDIA_PLAY

int FLAG_KEY_MEDIA_PLAY_PAUSE

Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PLAY_PAUSE RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE

int FLAG_KEY_MEDIA_PREVIOUS

Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PREVIOUS RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS

int FLAG_KEY_MEDIA_REWIND

Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_REWIND RemoteControlClient.FLAG_KEY_MEDIA_REWIND

int FLAG_KEY_MEDIA_STOP

Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_STOP RemoteControlClient.FLAG_KEY_MEDIA_STOP

int KEYCODE_MEDIA_PAUSE

Synonym for KeyEvent.KEYCODE_MEDIA_PAUSE

int KEYCODE_MEDIA_PLAY

Synonym for KeyEvent.KEYCODE_MEDIA_PLAY

int KEYCODE_MEDIA_RECORD

Synonym for KeyEvent.KEYCODE_MEDIA_RECORD

Public constructors

TransportMediator(Activity activity, TransportPerformer callbacks)
TransportMediator(View view, TransportPerformer callbacks)

Public methods

void destroy()

Optionally call when no longer using the TransportController.

boolean dispatchKeyEvent(KeyEvent event)

Must call from Activity.dispatchKeyEvent to give the transport an opportunity to intercept media keys.

int getBufferPercentage()

Retrieve amount, in percentage (0-100), that the media stream has been buffered on to the local device.

long getCurrentPosition()

Retrieve the current playback location in the media stream, in milliseconds.

long getDuration()

Retrieve the total duration of the media stream, in milliseconds.

Object getRemoteControlClient()

Return the RemoteControlClient associated with this transport.

int getTransportControlFlags()

Retrieves the flags for the media transport control buttons that this transport supports.

boolean isPlaying()

Return whether the player is currently playing its stream.

void pausePlaying()

Move the controller into the paused state.

void refreshState()
void registerStateListener(TransportStateListener listener)

Start listening to changes in playback state.

void seekTo(long pos)

Move to a new location in the media stream.

void startPlaying()

Move the controller into the playing state.

void stopPlaying()

Move the controller into the stopped state.

void unregisterStateListener(TransportStateListener listener)

Stop listening to changes in playback state.

Inherited methods

From class android.support.v4.media.TransportController
From class java.lang.Object

Constants

FLAG_KEY_MEDIA_FAST_FORWARD

int FLAG_KEY_MEDIA_FAST_FORWARD

Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_FAST_FORWARD RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD

Constant Value: 64 (0x00000040)

FLAG_KEY_MEDIA_NEXT

int FLAG_KEY_MEDIA_NEXT

Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_NEXT RemoteControlClient.FLAG_KEY_MEDIA_NEXT

Constant Value: 128 (0x00000080)

FLAG_KEY_MEDIA_PAUSE

int FLAG_KEY_MEDIA_PAUSE

Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PAUSE RemoteControlClient.FLAG_KEY_MEDIA_PAUSE

Constant Value: 16 (0x00000010)

FLAG_KEY_MEDIA_PLAY

int FLAG_KEY_MEDIA_PLAY

Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PLAY RemoteControlClient.FLAG_KEY_MEDIA_PLAY

Constant Value: 4 (0x00000004)

FLAG_KEY_MEDIA_PLAY_PAUSE

int FLAG_KEY_MEDIA_PLAY_PAUSE

Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PLAY_PAUSE RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE

Constant Value: 8 (0x00000008)

FLAG_KEY_MEDIA_PREVIOUS

int FLAG_KEY_MEDIA_PREVIOUS

Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PREVIOUS RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS

Constant Value: 1 (0x00000001)

FLAG_KEY_MEDIA_REWIND

int FLAG_KEY_MEDIA_REWIND

Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_REWIND RemoteControlClient.FLAG_KEY_MEDIA_REWIND

Constant Value: 2 (0x00000002)

FLAG_KEY_MEDIA_STOP

int FLAG_KEY_MEDIA_STOP

Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_STOP RemoteControlClient.FLAG_KEY_MEDIA_STOP

Constant Value: 32 (0x00000020)

KEYCODE_MEDIA_PAUSE

int KEYCODE_MEDIA_PAUSE

Synonym for KeyEvent.KEYCODE_MEDIA_PAUSE

Constant Value: 127 (0x0000007f)

KEYCODE_MEDIA_PLAY

int KEYCODE_MEDIA_PLAY

Synonym for KeyEvent.KEYCODE_MEDIA_PLAY

Constant Value: 126 (0x0000007e)

KEYCODE_MEDIA_RECORD

int KEYCODE_MEDIA_RECORD

Synonym for KeyEvent.KEYCODE_MEDIA_RECORD

Constant Value: 130 (0x00000082)

Public constructors

TransportMediator

TransportMediator (Activity activity, 
                TransportPerformer callbacks)

Parameters
activity Activity
callbacks TransportPerformer

TransportMediator

TransportMediator (View view, 
                TransportPerformer callbacks)

Parameters
view View
callbacks TransportPerformer

Public methods

destroy

void destroy ()

Optionally call when no longer using the TransportController. Its resources will also be automatically cleaned up when your activity/view is detached from its window, so you don't normally need to call this explicitly.

dispatchKeyEvent

boolean dispatchKeyEvent (KeyEvent event)

Must call from Activity.dispatchKeyEvent to give the transport an opportunity to intercept media keys. Any such keys will show up in TransportPerformer.

Returns
boolean

getBufferPercentage

int getBufferPercentage ()

Retrieve amount, in percentage (0-100), that the media stream has been buffered on to the local device. Return 100 if the stream is always local.

Returns
int

getCurrentPosition

long getCurrentPosition ()

Retrieve the current playback location in the media stream, in milliseconds.

Returns
long

getDuration

long getDuration ()

Retrieve the total duration of the media stream, in milliseconds.

Returns
long

getRemoteControlClient

Object getRemoteControlClient ()

Return the RemoteControlClient associated with this transport. This returns a generic Object since the RemoteControlClient is not availble before ICE_CREAM_SANDWICH. Further, this class will not use RemoteControlClient in its implementation until JELLY_BEAN_MR2. You should always check for null here and not do anything with the RemoteControlClient if none is given; this way you don't need to worry about the current platform API version.

Note that this class takes possession of the RemoteControlClient.OnGetPlaybackPositionListener and RemoteControlClient.OnPlaybackPositionUpdateListener callbacks; you will interact with these through TransportPerformer.onGetCurrentPosition and TransportPerformer.onSeekTo, respectively.

Returns
Object

getTransportControlFlags

int getTransportControlFlags ()

Retrieves the flags for the media transport control buttons that this transport supports. Result is a combination of the following flags: FLAG_KEY_MEDIA_PREVIOUS, FLAG_KEY_MEDIA_REWIND, FLAG_KEY_MEDIA_PLAY, FLAG_KEY_MEDIA_PLAY_PAUSE, FLAG_KEY_MEDIA_PAUSE, FLAG_KEY_MEDIA_STOP, FLAG_KEY_MEDIA_FAST_FORWARD, FLAG_KEY_MEDIA_NEXT

Returns
int

isPlaying

boolean isPlaying ()

Return whether the player is currently playing its stream.

Returns
boolean

pausePlaying

void pausePlaying ()

Move the controller into the paused state. This updates the remote control client to indicate it is paused, but keeps audio focus.

refreshState

void refreshState ()

registerStateListener

void registerStateListener (TransportStateListener listener)

Start listening to changes in playback state.

Parameters
listener TransportStateListener

seekTo

void seekTo (long pos)

Move to a new location in the media stream.

Parameters
pos long: Position to move to, in milliseconds.

startPlaying

void startPlaying ()

Move the controller into the playing state. This updates the remote control client to indicate it is playing, and takes audio focus for the app.

stopPlaying

void stopPlaying ()

Move the controller into the stopped state. This updates the remote control client to indicate it is stopped, and removes audio focus from the app.

unregisterStateListener

void unregisterStateListener (TransportStateListener listener)

Stop listening to changes in playback state.

Parameters
listener TransportStateListener

Hooray!