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); } }
Constants | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
int | FLAG_KEY_MEDIA_FAST_FORWARD | Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_FAST_FORWARD RemoveControlClient.FLAG_KEY_MEDIA_FAST_FORWARD | |||||||||
int | FLAG_KEY_MEDIA_NEXT | Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_NEXT RemoveControlClient.FLAG_KEY_MEDIA_NEXT | |||||||||
int | FLAG_KEY_MEDIA_PAUSE | Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PAUSE RemoveControlClient.FLAG_KEY_MEDIA_PAUSE | |||||||||
int | FLAG_KEY_MEDIA_PLAY | Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PLAY RemoveControlClient.FLAG_KEY_MEDIA_PLAY | |||||||||
int | FLAG_KEY_MEDIA_PLAY_PAUSE | Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PLAY_PAUSE RemoveControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE | |||||||||
int | FLAG_KEY_MEDIA_PREVIOUS | Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PREVIOUS RemoveControlClient.FLAG_KEY_MEDIA_PREVIOUS | |||||||||
int | FLAG_KEY_MEDIA_REWIND | Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_REWIND RemoveControlClient.FLAG_KEY_MEDIA_REWIND | |||||||||
int | FLAG_KEY_MEDIA_STOP | Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_STOP RemoveControlClient.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 | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
Public Methods | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
Optionally call when no longer using the TransportController.
| |||||||||||
Must call from
Activity.dispatchKeyEvent to give
the transport an opportunity to intercept media keys. | |||||||||||
Retrieve amount, in percentage (0-100), that the media stream has been buffered
on to the local device.
| |||||||||||
Retrieve the current playback location in the media stream, in milliseconds.
| |||||||||||
Retrieve the total duration of the media stream, in milliseconds.
| |||||||||||
Return the
RemoteControlClient associated with this transport. | |||||||||||
Retrieves the flags for the media transport control buttons that this transport supports.
| |||||||||||
Return whether the player is currently playing its stream.
| |||||||||||
Move the controller into the paused state.
| |||||||||||
Start listening to changes in playback state.
| |||||||||||
Move to a new location in the media stream.
| |||||||||||
Move the controller into the playing state.
| |||||||||||
Move the controller into the stopped state.
| |||||||||||
Stop listening to changes in playback state.
|
[Expand]
Inherited Methods | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
From class
android.support.v4.media.TransportController
| |||||||||||
From class
java.lang.Object
|
Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_FAST_FORWARD RemoveControlClient.FLAG_KEY_MEDIA_FAST_FORWARD
Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_NEXT RemoveControlClient.FLAG_KEY_MEDIA_NEXT
Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PAUSE RemoveControlClient.FLAG_KEY_MEDIA_PAUSE
Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PLAY RemoveControlClient.FLAG_KEY_MEDIA_PLAY
Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PLAY_PAUSE RemoveControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE
Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_PREVIOUS RemoveControlClient.FLAG_KEY_MEDIA_PREVIOUS
Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_REWIND RemoveControlClient.FLAG_KEY_MEDIA_REWIND
Synonym for {@link android.media.RemoteControlClient#FLAG_KEY_MEDIA_STOP RemoveControlClient.FLAG_KEY_MEDIA_STOP
Synonym for KeyEvent.KEYCODE_MEDIA_PAUSE
Synonym for KeyEvent.KEYCODE_MEDIA_PLAY
Synonym for KeyEvent.KEYCODE_MEDIA_RECORD
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.
Must call from Activity.dispatchKeyEvent
to give
the transport an opportunity to intercept media keys. Any such keys will show up
in TransportPerformer
.
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.
Retrieve the current playback location in the media stream, in milliseconds.
Retrieve the total duration of the media stream, in milliseconds.
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.
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
Return whether the player is currently playing its stream.
Move the controller into the paused state. This updates the remote control client to indicate it is paused, but keeps audio focus.
Start listening to changes in playback state.
Move to a new location in the media stream.
pos | Position to move to, in milliseconds. |
---|
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.
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.
Stop listening to changes in playback state.