Update media controller sample.

Now use the new abstractions of TransportMediator.  Guess I should
also change the name of this sample to match it...  that'll be for
a future change. :)

Change-Id: I932f8215bba51dfaa1bd5766ab9551c9dc440657
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/media/MediaController.java b/samples/Support4Demos/src/com/example/android/supportv4/media/MediaController.java
index e7f9e08..d7d513d 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/media/MediaController.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/media/MediaController.java
@@ -16,6 +16,9 @@
 
 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 android.content.Context;
@@ -40,28 +43,38 @@
  */
 public class MediaController extends FrameLayout {
 
-    private MediaPlayerControl  mPlayer;
+    private TransportController mController;
     private Context mContext;
     private ProgressBar mProgress;
     private TextView mEndTime, mCurrentTime;
-    private boolean             mDragging;
-    private boolean             mUseFastForward;
-    private boolean             mFromXml;
-    private boolean             mListenersSet;
+    private boolean mDragging;
+    private boolean mUseFastForward;
+    private boolean mListenersSet;
+    private boolean mShowNext, mShowPrev;
     private View.OnClickListener mNextListener, mPrevListener;
-    StringBuilder               mFormatBuilder;
+    StringBuilder mFormatBuilder;
     Formatter mFormatter;
     private ImageButton mPauseButton;
-    private ImageButton         mFfwdButton;
-    private ImageButton         mRewButton;
-    private ImageButton         mNextButton;
-    private ImageButton         mPrevButton;
+    private ImageButton mFfwdButton;
+    private ImageButton mRewButton;
+    private ImageButton mNextButton;
+    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) {
         super(context, attrs);
         mContext = context;
         mUseFastForward = true;
-        mFromXml = true;
         LayoutInflater inflate = (LayoutInflater)
                 mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         inflate.inflate(R.layout.media_controller, this, true);
@@ -78,11 +91,35 @@
         this(context, true);
     }
 
-    public void setMediaPlayer(MediaPlayerControl player) {
-        mPlayer = player;
+    public void setMediaPlayer(TransportController controller) {
+        if (getWindowToken() != null) {
+            if (mController != null) {
+                mController.unregisterStateListener(mStateListener);
+            }
+            if (controller != null) {
+                controller.registerStateListener(mStateListener);
+            }
+        }
+        mController = controller;
         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() {
         mPauseButton = (ImageButton) findViewById(R.id.pause);
         if (mPauseButton != null) {
@@ -93,26 +130,22 @@
         mFfwdButton = (ImageButton) findViewById(R.id.ffwd);
         if (mFfwdButton != null) {
             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);
         if (mRewButton != null) {
             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
         mNextButton = (ImageButton) findViewById(R.id.next);
-        if (mNextButton != null && !mFromXml && !mListenersSet) {
+        if (mNextButton != null && !mListenersSet) {
             mNextButton.setVisibility(View.GONE);
         }
         mPrevButton = (ImageButton) findViewById(R.id.prev);
-        if (mPrevButton != null && !mFromXml && !mListenersSet) {
+        if (mPrevButton != null && !mListenersSet) {
             mPrevButton.setVisibility(View.GONE);
         }
 
@@ -137,28 +170,34 @@
      * Disable pause or seek buttons if the stream cannot be paused or seeked.
      * This requires the control interface to be a MediaPlayerControlExt
      */
-    private void disableUnsupportedButtons() {
-        try {
-            if (mPauseButton != null && !mPlayer.canPause()) {
-                mPauseButton.setEnabled(false);
-            }
-            if (mRewButton != null && !mPlayer.canSeekBackward()) {
-                mRewButton.setEnabled(false);
-            }
-            if (mFfwdButton != null && !mPlayer.canSeekForward()) {
-                mFfwdButton.setEnabled(false);
-            }
-        } catch (IncompatibleClassChangeError ex) {
-            // We were given an old version of the interface, that doesn't have
-            // the canPause/canSeekXYZ methods. This is OK, it just means we
-            // assume the media can be paused and seeked, and so we don't disable
-            // the buttons.
+    void updateButtons() {
+        int flags = mController.getTransportControlFlags();
+        boolean enabled = isEnabled();
+        if (mPauseButton != null) {
+            mPauseButton.setEnabled(enabled && (flags&TransportMediator.FLAG_KEY_MEDIA_PAUSE) != 0);
+        }
+        if (mRewButton != null) {
+            mRewButton.setEnabled(enabled && (flags&TransportMediator.FLAG_KEY_MEDIA_REWIND) != 0);
+        }
+        if (mFfwdButton != null) {
+            mFfwdButton.setEnabled(enabled &&
+                    (flags&TransportMediator.FLAG_KEY_MEDIA_FAST_FORWARD) != 0);
+        }
+        if (mPrevButton != null) {
+            mShowPrev = (flags&TransportMediator.FLAG_KEY_MEDIA_PREVIOUS) != 0
+                    || mPrevListener != null;
+            mPrevButton.setEnabled(enabled && mShowPrev);
+        }
+        if (mNextButton != null) {
+            mShowNext = (flags&TransportMediator.FLAG_KEY_MEDIA_NEXT) != 0
+                    || mNextListener != null;
+            mNextButton.setEnabled(enabled && mShowNext);
         }
     }
 
     public void refresh() {
         updateProgress();
-        disableUnsupportedButtons();
+        updateButtons();
         updatePausePlay();
     }
 
@@ -178,18 +217,18 @@
     }
 
     public int updateProgress() {
-        if (mPlayer == null || mDragging) {
+        if (mController == null || mDragging) {
             return 0;
         }
-        int position = mPlayer.getCurrentPosition();
-        int duration = mPlayer.getDuration();
+        int position = mController.getCurrentPosition();
+        int duration = mController.getDuration();
         if (mProgress != null) {
             if (duration > 0) {
                 // use long to avoid overflow
                 long pos = 1000L * position / duration;
                 mProgress.setProgress( (int) pos);
             }
-            int percent = mPlayer.getBufferPercentage();
+            int percent = mController.getBufferPercentage();
             mProgress.setSecondaryProgress(percent * 10);
         }
 
@@ -211,7 +250,7 @@
         if (mPauseButton == null)
             return;
 
-        if (mPlayer.isPlaying()) {
+        if (mController.isPlaying()) {
             mPauseButton.setImageResource(android.R.drawable.ic_media_pause);
         } else {
             mPauseButton.setImageResource(android.R.drawable.ic_media_play);
@@ -219,10 +258,10 @@
     }
 
     private void doPauseResume() {
-        if (mPlayer.isPlaying()) {
-            mPlayer.pause();
+        if (mController.isPlaying()) {
+            mController.pausePlaying();
         } else {
-            mPlayer.start();
+            mController.startPlaying();
         }
         updatePausePlay();
     }
@@ -250,9 +289,9 @@
                 return;
             }
 
-            long duration = mPlayer.getDuration();
+            long duration = mController.getDuration();
             long newposition = (duration * progress) / 1000L;
-            mPlayer.seekTo( (int) newposition);
+            mController.seekTo((int) newposition);
             if (mCurrentTime != null)
                 mCurrentTime.setText(stringForTime( (int) newposition));
         }
@@ -266,26 +305,8 @@
 
     @Override
     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);
+        updateButtons();
     }
 
     @Override
@@ -302,18 +323,18 @@
 
     private View.OnClickListener mRewListener = new View.OnClickListener() {
         public void onClick(View v) {
-            int pos = mPlayer.getCurrentPosition();
+            int pos = mController.getCurrentPosition();
             pos -= 5000; // milliseconds
-            mPlayer.seekTo(pos);
+            mController.seekTo(pos);
             updateProgress();
         }
     };
 
     private View.OnClickListener mFfwdListener = new View.OnClickListener() {
         public void onClick(View v) {
-            int pos = mPlayer.getCurrentPosition();
+            int pos = mController.getCurrentPosition();
             pos += 15000; // milliseconds
-            mPlayer.seekTo(pos);
+            mController.seekTo(pos);
             updateProgress();
         }
     };
@@ -321,12 +342,12 @@
     private void installPrevNextListeners() {
         if (mNextButton != null) {
             mNextButton.setOnClickListener(mNextListener);
-            mNextButton.setEnabled(mNextListener != null);
+            mNextButton.setEnabled(mShowNext);
         }
 
         if (mPrevButton != null) {
             mPrevButton.setOnClickListener(mPrevListener);
-            mPrevButton.setEnabled(mPrevListener != null);
+            mPrevButton.setEnabled(mShowPrev);
         }
     }
 
@@ -337,24 +358,13 @@
 
         installPrevNextListeners();
 
-        if (mNextButton != null && !mFromXml) {
+        if (mNextButton != null) {
             mNextButton.setVisibility(View.VISIBLE);
+            mShowNext = true;
         }
-        if (mPrevButton != null && !mFromXml) {
+        if (mPrevButton != null) {
             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();
-    }
 }
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/media/TransportControllerActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/media/TransportControllerActivity.java
index a4e0951..0041aa2 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/media/TransportControllerActivity.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/media/TransportControllerActivity.java
@@ -16,6 +16,8 @@
 
 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 android.app.ActionBar;
@@ -31,8 +33,6 @@
 import android.os.Bundle;
 import android.widget.VideoView;
 
-import android.support.v4.media.TransportController;
-
 public class TransportControllerActivity extends Activity {
 
     /**
@@ -40,92 +40,70 @@
      * file path.
      */
     private Content mContent;
-    private TransportController mTransportController;
+    private TransportMediator mTransportMediator;
     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
      * to the VideoView; some we need to capture to update our state.
      */
-    MediaController.MediaPlayerControl mMediaPlayerControl
-            = new MediaController.MediaPlayerControl() {
+    TransportPerformer mTransportPerformer = new TransportPerformer() {
 
         @Override
-        public void start() {
-            mTransportController.startPlaying();
+        public void onStart() {
             mContent.start();
         }
 
         @Override
-        public void pause() {
-            mTransportController.pausePlaying();
+        public void onStop() {
             mContent.pause();
         }
 
         @Override
-        public int getDuration() {
+        public void onPause() {
+            mContent.pause();
+        }
+
+        @Override
+        public int onGetDuration() {
             return mContent.getDuration();
         }
 
         @Override
-        public int getCurrentPosition() {
+        public int onGetCurrentPosition() {
             return mContent.getCurrentPosition();
         }
 
         @Override
-        public void seekTo(int pos) {
+        public void onSeekTo(int pos) {
             mContent.seekTo(pos);
         }
 
         @Override
-        public boolean isPlaying() {
+        public boolean onIsPlaying() {
             return mContent.isPlaying();
         }
 
         @Override
-        public int getBufferPercentage() {
+        public int onGetBufferPercentage() {
             return mContent.getBufferPercentage();
         }
 
         @Override
-        public boolean canPause() {
-            return mContent.canPause();
-        }
-
-        @Override
-        public boolean canSeekBackward() {
-            return mContent.canSeekBackward();
-        }
-
-        @Override
-        public boolean canSeekForward() {
-            return mContent.canSeekForward();
+        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;
         }
     };
 
@@ -139,7 +117,7 @@
             ActionBar.OnMenuVisibilityListener, MediaPlayer.OnPreparedListener,
             MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener {
         Activity mActivity;
-        TransportController mTransportController;
+        TransportMediator mTransportMediator;
         MediaController mMediaController;
         boolean mAddedMenuListener;
         boolean mMenusOpen;
@@ -169,12 +147,12 @@
             setOnErrorListener(this);
         }
 
-        public void init(Activity activity, TransportController transportController,
+        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;
-            mTransportController = transportController;
+            mTransportMediator = transportMediator;
             mMediaController = mediaController;
             pause();
         }
@@ -231,13 +209,13 @@
 
         @Override
         public void onCompletion(MediaPlayer mp) {
-            mTransportController.pausePlaying();
+            mTransportMediator.pausePlaying();
             pause();
         }
 
         @Override
         public boolean onError(MediaPlayer mp, int what, int extra) {
-            mTransportController.pausePlaying();
+            mTransportMediator.pausePlaying();
             pause();
             return false;
         }
@@ -309,16 +287,16 @@
         // Find the video player in our UI.
         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
         // 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.
-        mContent.init(this, mTransportController, mMediaController);
+        mContent.init(this, mTransportMediator, mMediaController);
         mContent.setVideoURI(Uri.parse("android.resource://" + getPackageName() +
                 "/" + R.raw.videoviewdemo));
     }
@@ -328,7 +306,7 @@
         // 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 (mTransportController.dispatchKeyEvent(event)) {
+        if (mTransportMediator.dispatchKeyEvent(event)) {
             return true;
         }