Merge "Update media controller sample." into jb-mr2-dev

This commit is contained in:
Dianne Hackborn
2013-04-10 18:58:52 +00:00
committed by Android (Google) Code Review
2 changed files with 140 additions and 152 deletions

View File

@@ -16,6 +16,9 @@
package com.example.android.supportv4.media; package com.example.android.supportv4.media;
import android.support.v4.media.TransportController;
import android.support.v4.media.TransportMediator;
import android.support.v4.media.TransportStateListener;
import com.example.android.supportv4.R; import com.example.android.supportv4.R;
import android.content.Context; import android.content.Context;
@@ -40,14 +43,14 @@ import java.util.Locale;
*/ */
public class MediaController extends FrameLayout { public class MediaController extends FrameLayout {
private MediaPlayerControl mPlayer; private TransportController mController;
private Context mContext; private Context mContext;
private ProgressBar mProgress; private ProgressBar mProgress;
private TextView mEndTime, mCurrentTime; private TextView mEndTime, mCurrentTime;
private boolean mDragging; private boolean mDragging;
private boolean mUseFastForward; private boolean mUseFastForward;
private boolean mFromXml;
private boolean mListenersSet; private boolean mListenersSet;
private boolean mShowNext, mShowPrev;
private View.OnClickListener mNextListener, mPrevListener; private View.OnClickListener mNextListener, mPrevListener;
StringBuilder mFormatBuilder; StringBuilder mFormatBuilder;
Formatter mFormatter; Formatter mFormatter;
@@ -57,11 +60,21 @@ public class MediaController extends FrameLayout {
private ImageButton mNextButton; private ImageButton mNextButton;
private ImageButton mPrevButton; private ImageButton mPrevButton;
private TransportStateListener mStateListener = new TransportStateListener() {
@Override
public void onPlayingChanged(TransportController controller) {
updatePausePlay();
}
@Override
public void onTransportControlsChanged(TransportController controller) {
updateButtons();
}
};
public MediaController(Context context, AttributeSet attrs) { public MediaController(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
mContext = context; mContext = context;
mUseFastForward = true; mUseFastForward = true;
mFromXml = true;
LayoutInflater inflate = (LayoutInflater) LayoutInflater inflate = (LayoutInflater)
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflate.inflate(R.layout.media_controller, this, true); inflate.inflate(R.layout.media_controller, this, true);
@@ -78,11 +91,35 @@ public class MediaController extends FrameLayout {
this(context, true); this(context, true);
} }
public void setMediaPlayer(MediaPlayerControl player) { public void setMediaPlayer(TransportController controller) {
mPlayer = player; if (getWindowToken() != null) {
if (mController != null) {
mController.unregisterStateListener(mStateListener);
}
if (controller != null) {
controller.registerStateListener(mStateListener);
}
}
mController = controller;
updatePausePlay(); updatePausePlay();
} }
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mController != null) {
mController.registerStateListener(mStateListener);
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mController != null) {
mController.unregisterStateListener(mStateListener);
}
}
private void initControllerView() { private void initControllerView() {
mPauseButton = (ImageButton) findViewById(R.id.pause); mPauseButton = (ImageButton) findViewById(R.id.pause);
if (mPauseButton != null) { if (mPauseButton != null) {
@@ -93,26 +130,22 @@ public class MediaController extends FrameLayout {
mFfwdButton = (ImageButton) findViewById(R.id.ffwd); mFfwdButton = (ImageButton) findViewById(R.id.ffwd);
if (mFfwdButton != null) { if (mFfwdButton != null) {
mFfwdButton.setOnClickListener(mFfwdListener); mFfwdButton.setOnClickListener(mFfwdListener);
if (!mFromXml) {
mFfwdButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE); mFfwdButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
} }
}
mRewButton = (ImageButton) findViewById(R.id.rew); mRewButton = (ImageButton) findViewById(R.id.rew);
if (mRewButton != null) { if (mRewButton != null) {
mRewButton.setOnClickListener(mRewListener); mRewButton.setOnClickListener(mRewListener);
if (!mFromXml) {
mRewButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE); mRewButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
} }
}
// By default these are hidden. They will be enabled when setPrevNextListeners() is called // By default these are hidden. They will be enabled when setPrevNextListeners() is called
mNextButton = (ImageButton) findViewById(R.id.next); mNextButton = (ImageButton) findViewById(R.id.next);
if (mNextButton != null && !mFromXml && !mListenersSet) { if (mNextButton != null && !mListenersSet) {
mNextButton.setVisibility(View.GONE); mNextButton.setVisibility(View.GONE);
} }
mPrevButton = (ImageButton) findViewById(R.id.prev); mPrevButton = (ImageButton) findViewById(R.id.prev);
if (mPrevButton != null && !mFromXml && !mListenersSet) { if (mPrevButton != null && !mListenersSet) {
mPrevButton.setVisibility(View.GONE); mPrevButton.setVisibility(View.GONE);
} }
@@ -137,28 +170,34 @@ public class MediaController extends FrameLayout {
* Disable pause or seek buttons if the stream cannot be paused or seeked. * Disable pause or seek buttons if the stream cannot be paused or seeked.
* This requires the control interface to be a MediaPlayerControlExt * This requires the control interface to be a MediaPlayerControlExt
*/ */
private void disableUnsupportedButtons() { void updateButtons() {
try { int flags = mController.getTransportControlFlags();
if (mPauseButton != null && !mPlayer.canPause()) { boolean enabled = isEnabled();
mPauseButton.setEnabled(false); if (mPauseButton != null) {
mPauseButton.setEnabled(enabled && (flags&TransportMediator.FLAG_KEY_MEDIA_PAUSE) != 0);
} }
if (mRewButton != null && !mPlayer.canSeekBackward()) { if (mRewButton != null) {
mRewButton.setEnabled(false); mRewButton.setEnabled(enabled && (flags&TransportMediator.FLAG_KEY_MEDIA_REWIND) != 0);
} }
if (mFfwdButton != null && !mPlayer.canSeekForward()) { if (mFfwdButton != null) {
mFfwdButton.setEnabled(false); mFfwdButton.setEnabled(enabled &&
(flags&TransportMediator.FLAG_KEY_MEDIA_FAST_FORWARD) != 0);
} }
} catch (IncompatibleClassChangeError ex) { if (mPrevButton != null) {
// We were given an old version of the interface, that doesn't have mShowPrev = (flags&TransportMediator.FLAG_KEY_MEDIA_PREVIOUS) != 0
// the canPause/canSeekXYZ methods. This is OK, it just means we || mPrevListener != null;
// assume the media can be paused and seeked, and so we don't disable mPrevButton.setEnabled(enabled && mShowPrev);
// the buttons. }
if (mNextButton != null) {
mShowNext = (flags&TransportMediator.FLAG_KEY_MEDIA_NEXT) != 0
|| mNextListener != null;
mNextButton.setEnabled(enabled && mShowNext);
} }
} }
public void refresh() { public void refresh() {
updateProgress(); updateProgress();
disableUnsupportedButtons(); updateButtons();
updatePausePlay(); updatePausePlay();
} }
@@ -178,18 +217,18 @@ public class MediaController extends FrameLayout {
} }
public int updateProgress() { public int updateProgress() {
if (mPlayer == null || mDragging) { if (mController == null || mDragging) {
return 0; return 0;
} }
int position = mPlayer.getCurrentPosition(); int position = mController.getCurrentPosition();
int duration = mPlayer.getDuration(); int duration = mController.getDuration();
if (mProgress != null) { if (mProgress != null) {
if (duration > 0) { if (duration > 0) {
// use long to avoid overflow // use long to avoid overflow
long pos = 1000L * position / duration; long pos = 1000L * position / duration;
mProgress.setProgress( (int) pos); mProgress.setProgress( (int) pos);
} }
int percent = mPlayer.getBufferPercentage(); int percent = mController.getBufferPercentage();
mProgress.setSecondaryProgress(percent * 10); mProgress.setSecondaryProgress(percent * 10);
} }
@@ -211,7 +250,7 @@ public class MediaController extends FrameLayout {
if (mPauseButton == null) if (mPauseButton == null)
return; return;
if (mPlayer.isPlaying()) { if (mController.isPlaying()) {
mPauseButton.setImageResource(android.R.drawable.ic_media_pause); mPauseButton.setImageResource(android.R.drawable.ic_media_pause);
} else { } else {
mPauseButton.setImageResource(android.R.drawable.ic_media_play); mPauseButton.setImageResource(android.R.drawable.ic_media_play);
@@ -219,10 +258,10 @@ public class MediaController extends FrameLayout {
} }
private void doPauseResume() { private void doPauseResume() {
if (mPlayer.isPlaying()) { if (mController.isPlaying()) {
mPlayer.pause(); mController.pausePlaying();
} else { } else {
mPlayer.start(); mController.startPlaying();
} }
updatePausePlay(); updatePausePlay();
} }
@@ -250,9 +289,9 @@ public class MediaController extends FrameLayout {
return; return;
} }
long duration = mPlayer.getDuration(); long duration = mController.getDuration();
long newposition = (duration * progress) / 1000L; long newposition = (duration * progress) / 1000L;
mPlayer.seekTo( (int) newposition); mController.seekTo((int) newposition);
if (mCurrentTime != null) if (mCurrentTime != null)
mCurrentTime.setText(stringForTime( (int) newposition)); mCurrentTime.setText(stringForTime( (int) newposition));
} }
@@ -266,26 +305,8 @@ public class MediaController extends FrameLayout {
@Override @Override
public void setEnabled(boolean enabled) { public void setEnabled(boolean enabled) {
if (mPauseButton != null) {
mPauseButton.setEnabled(enabled);
}
if (mFfwdButton != null) {
mFfwdButton.setEnabled(enabled);
}
if (mRewButton != null) {
mRewButton.setEnabled(enabled);
}
if (mNextButton != null) {
mNextButton.setEnabled(enabled && mNextListener != null);
}
if (mPrevButton != null) {
mPrevButton.setEnabled(enabled && mPrevListener != null);
}
if (mProgress != null) {
mProgress.setEnabled(enabled);
}
disableUnsupportedButtons();
super.setEnabled(enabled); super.setEnabled(enabled);
updateButtons();
} }
@Override @Override
@@ -302,18 +323,18 @@ public class MediaController extends FrameLayout {
private View.OnClickListener mRewListener = new View.OnClickListener() { private View.OnClickListener mRewListener = new View.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
int pos = mPlayer.getCurrentPosition(); int pos = mController.getCurrentPosition();
pos -= 5000; // milliseconds pos -= 5000; // milliseconds
mPlayer.seekTo(pos); mController.seekTo(pos);
updateProgress(); updateProgress();
} }
}; };
private View.OnClickListener mFfwdListener = new View.OnClickListener() { private View.OnClickListener mFfwdListener = new View.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
int pos = mPlayer.getCurrentPosition(); int pos = mController.getCurrentPosition();
pos += 15000; // milliseconds pos += 15000; // milliseconds
mPlayer.seekTo(pos); mController.seekTo(pos);
updateProgress(); updateProgress();
} }
}; };
@@ -321,12 +342,12 @@ public class MediaController extends FrameLayout {
private void installPrevNextListeners() { private void installPrevNextListeners() {
if (mNextButton != null) { if (mNextButton != null) {
mNextButton.setOnClickListener(mNextListener); mNextButton.setOnClickListener(mNextListener);
mNextButton.setEnabled(mNextListener != null); mNextButton.setEnabled(mShowNext);
} }
if (mPrevButton != null) { if (mPrevButton != null) {
mPrevButton.setOnClickListener(mPrevListener); mPrevButton.setOnClickListener(mPrevListener);
mPrevButton.setEnabled(mPrevListener != null); mPrevButton.setEnabled(mShowPrev);
} }
} }
@@ -337,24 +358,13 @@ public class MediaController extends FrameLayout {
installPrevNextListeners(); installPrevNextListeners();
if (mNextButton != null && !mFromXml) { if (mNextButton != null) {
mNextButton.setVisibility(View.VISIBLE); mNextButton.setVisibility(View.VISIBLE);
mShowNext = true;
} }
if (mPrevButton != null && !mFromXml) { if (mPrevButton != null) {
mPrevButton.setVisibility(View.VISIBLE); mPrevButton.setVisibility(View.VISIBLE);
mShowPrev = true;
} }
} }
public interface MediaPlayerControl {
void start();
void pause();
int getDuration();
int getCurrentPosition();
void seekTo(int pos);
boolean isPlaying();
int getBufferPercentage();
boolean canPause();
boolean canSeekBackward();
boolean canSeekForward();
}
} }

View File

@@ -16,6 +16,8 @@
package com.example.android.supportv4.media; package com.example.android.supportv4.media;
import android.support.v4.media.TransportMediator;
import android.support.v4.media.TransportPerformer;
import com.example.android.supportv4.R; import com.example.android.supportv4.R;
import android.app.ActionBar; import android.app.ActionBar;
@@ -31,8 +33,6 @@ import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.widget.VideoView; import android.widget.VideoView;
import android.support.v4.media.TransportController;
public class TransportControllerActivity extends Activity { public class TransportControllerActivity extends Activity {
/** /**
@@ -40,92 +40,70 @@ public class TransportControllerActivity extends Activity {
* file path. * file path.
*/ */
private Content mContent; private Content mContent;
private TransportController mTransportController; private TransportMediator mTransportMediator;
private MediaController mMediaController; private MediaController mMediaController;
/**
* Handle media buttons to start/stop video playback. Real implementations
* will probably handle more buttons, like skip and fast-forward.
*/
TransportController.Callbacks mTransportCallbacks = new TransportController.Callbacks() {
public boolean onMediaButtonDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case TransportController.KEYCODE_MEDIA_PLAY:
mMediaPlayerControl.start();
return true;
case TransportController.KEYCODE_MEDIA_PAUSE:
case KeyEvent.KEYCODE_MEDIA_STOP:
mMediaPlayerControl.pause();
return true;
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
case KeyEvent.KEYCODE_HEADSETHOOK:
if (mContent.isPlaying()) {
mMediaPlayerControl.pause();
} else {
mMediaPlayerControl.start();
}
}
return true;
}
};
/** /**
* Handle actions from on-screen media controls. Most of these are simple re-directs * 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. * to the VideoView; some we need to capture to update our state.
*/ */
MediaController.MediaPlayerControl mMediaPlayerControl TransportPerformer mTransportPerformer = new TransportPerformer() {
= new MediaController.MediaPlayerControl() {
@Override @Override
public void start() { public void onStart() {
mTransportController.startPlaying();
mContent.start(); mContent.start();
} }
@Override @Override
public void pause() { public void onStop() {
mTransportController.pausePlaying();
mContent.pause(); mContent.pause();
} }
@Override @Override
public int getDuration() { public void onPause() {
mContent.pause();
}
@Override
public int onGetDuration() {
return mContent.getDuration(); return mContent.getDuration();
} }
@Override @Override
public int getCurrentPosition() { public int onGetCurrentPosition() {
return mContent.getCurrentPosition(); return mContent.getCurrentPosition();
} }
@Override @Override
public void seekTo(int pos) { public void onSeekTo(int pos) {
mContent.seekTo(pos); mContent.seekTo(pos);
} }
@Override @Override
public boolean isPlaying() { public boolean onIsPlaying() {
return mContent.isPlaying(); return mContent.isPlaying();
} }
@Override @Override
public int getBufferPercentage() { public int onGetBufferPercentage() {
return mContent.getBufferPercentage(); return mContent.getBufferPercentage();
} }
@Override @Override
public boolean canPause() { public int onGetTransportControlFlags() {
return mContent.canPause(); 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()) {
@Override flags |= TransportMediator.FLAG_KEY_MEDIA_REWIND;
public boolean canSeekBackward() {
return mContent.canSeekBackward();
} }
if (mContent.canSeekForward()) {
@Override flags |= TransportMediator.FLAG_KEY_MEDIA_FAST_FORWARD;
public boolean canSeekForward() { }
return mContent.canSeekForward(); return flags;
} }
}; };
@@ -139,7 +117,7 @@ public class TransportControllerActivity extends Activity {
ActionBar.OnMenuVisibilityListener, MediaPlayer.OnPreparedListener, ActionBar.OnMenuVisibilityListener, MediaPlayer.OnPreparedListener,
MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener { MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener {
Activity mActivity; Activity mActivity;
TransportController mTransportController; TransportMediator mTransportMediator;
MediaController mMediaController; MediaController mMediaController;
boolean mAddedMenuListener; boolean mAddedMenuListener;
boolean mMenusOpen; boolean mMenusOpen;
@@ -169,12 +147,12 @@ public class TransportControllerActivity extends Activity {
setOnErrorListener(this); setOnErrorListener(this);
} }
public void init(Activity activity, TransportController transportController, public void init(Activity activity, TransportMediator transportMediator,
MediaController mediaController) { MediaController mediaController) {
// This called by the containing activity to supply the surrounding // This called by the containing activity to supply the surrounding
// state of the video player that it will interact with. // state of the video player that it will interact with.
mActivity = activity; mActivity = activity;
mTransportController = transportController; mTransportMediator = transportMediator;
mMediaController = mediaController; mMediaController = mediaController;
pause(); pause();
} }
@@ -231,13 +209,13 @@ public class TransportControllerActivity extends Activity {
@Override @Override
public void onCompletion(MediaPlayer mp) { public void onCompletion(MediaPlayer mp) {
mTransportController.pausePlaying(); mTransportMediator.pausePlaying();
pause(); pause();
} }
@Override @Override
public boolean onError(MediaPlayer mp, int what, int extra) { public boolean onError(MediaPlayer mp, int what, int extra) {
mTransportController.pausePlaying(); mTransportMediator.pausePlaying();
pause(); pause();
return false; return false;
} }
@@ -309,16 +287,16 @@ public class TransportControllerActivity extends Activity {
// Find the video player in our UI. // Find the video player in our UI.
mContent = (Content) findViewById(R.id.content); mContent = (Content) findViewById(R.id.content);
// Create and initialize the media control UI.
mMediaController = (MediaController) findViewById(R.id.media_controller);
mMediaController.setMediaPlayer(mMediaPlayerControl);
// Create transport controller to control video, giving the callback // Create transport controller to control video, giving the callback
// interface to receive actions from. // interface to receive actions from.
mTransportController = new TransportController(this, mTransportCallbacks); 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. // We're just playing a built-in demo video.
mContent.init(this, mTransportController, mMediaController); mContent.init(this, mTransportMediator, mMediaController);
mContent.setVideoURI(Uri.parse("android.resource://" + getPackageName() + mContent.setVideoURI(Uri.parse("android.resource://" + getPackageName() +
"/" + R.raw.videoviewdemo)); "/" + R.raw.videoviewdemo));
} }
@@ -328,7 +306,7 @@ public class TransportControllerActivity extends Activity {
// We first dispatch keys to the transport controller -- we want it // We first dispatch keys to the transport controller -- we want it
// to get to consume any media keys rather than letting whoever has focus // to get to consume any media keys rather than letting whoever has focus
// in the view hierarchy to potentially eat it. // in the view hierarchy to potentially eat it.
if (mTransportController.dispatchKeyEvent(event)) { if (mTransportMediator.dispatchKeyEvent(event)) {
return true; return true;
} }