2016年7月8日 星期五

Custom Android Media Controller


The default media controller of Android typically contains the buttons like "Play/Pause", "Rewind", "Fast Forward" and a progress slider. Instead of "Rewind" and "Fast Forward" buttons, sometimes what we need is a full screen toggle button. Based on this StackOverflow post, we can implement our own media controller instead of scratching in this post.

Pre-Conditions

  1. Download VideoControllerView.java and change the package name to match your project
  2. Download media_controller.xml into your project’s layout folder
  3. Download the 4 images into your project’s drawable folder: ic_media_play.png, ic_media_pause.png, ic_media_fullscreen_shrink.png and ic_media_fullscreen_stretch.png
  4. Visit Android Holo Colors Generator to create the style of SeekBar, and put them in drawable(or mipmap) and values/style.xml

    style.xml
    
    

Create an Activity(FullscreenVideoActivity.java) with Layout(activity_fullscreen_video.xml)

FullscreenVideoActivity.java

  1. Initial MediaPlayer and VideoControlView
  2. public class FullscreenVideoActivity extends Activity implements SurfaceHolder.Callback,
            MediaPlayer.OnPreparedListener, VideoControllerView.MediaPlayerControl {
        private String TAG = "FullscreenVideoActivity";
        SurfaceView videoSurface;
        private MediaPlayer mediaPlayer;
        private VideoControllerView controller;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_fullscreen_video);
            videoSurface = (SurfaceView) findViewById(R.id.videoSurface);
            SurfaceHolder videoHolder = videoSurface.getHolder();
            videoHolder.addCallback(this);
            String videoPath =  "android.resource://" + getPackageName() + "/" + R.raw
                    .sample_video;
            mediaPlayer = new MediaPlayer();
            controller = new VideoControllerView(this);
            try {
                mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                mediaPlayer.setDataSource(this, Uri.parse(videoPath));
                mediaPlayer.setOnPreparedListener(this);
            } catch (IllegalArgumentException | SecurityException | IllegalStateException |
                    IOException e) {
                e.printStackTrace();
            }
        }
    }
    
  3. Implement interface SurfaceHolder.Callback
    // Implement SurfaceHolder.Callback
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
    
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mediaPlayer.setDisplay(holder);
        mediaPlayer.prepareAsync();
    }
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {}
    // End SurfaceHolder.Callback
    
  4. Implement interface MediaPlayer.OnPreparedListener
    // Implement MediaPlayer.OnPreparedListener
    @Override
    public void onPrepared(MediaPlayer mp) {
        controller.setMediaPlayer(this);
        controller.setAnchorView((FrameLayout) findViewById(R.id.videoSurfaceContainer));
        mediaPlayer.start();
    }
    // End MediaPlayer.OnPreparedListener
    
  5. Implement interface VideoControllerView.MediaPlayerControl
    In the project, we implement toggleFullScreen() and isFullScreen() to switch between normal(PORTRAIT) and full-screen mode(LANDSCAPE).
    // Implement VideoMediaController.MediaPlayerControl
    @Override
    public boolean canPause() {
        return true;
    }
    
    @Override
    public boolean canSeekBackward() {
        return true;
    }
    
    @Override
    public boolean canSeekForward() {
        return true;
    }
    
    @Override
    public int getBufferPercentage() {
        return 0;
    }
    
    @Override
    public int getCurrentPosition() {
        return mediaPlayer.getCurrentPosition();
    }
    
    @Override
    public int getDuration() {
        return mediaPlayer.getDuration();
    }
    
    @Override
    public boolean isPlaying() {
        return mediaPlayer.isPlaying();
    }
    
    @Override
    public void pause() {
        mediaPlayer.pause();
    }
    
    @Override
    public void seekTo(int i) {
        mediaPlayer.seekTo(i);
    }
    
    @Override
    public void start() {
        mediaPlayer.start();
    }
    
    @Override
    public boolean isFullScreen() {
        boolean isFullScreen = (getResources().getConfiguration().orientation==2);
        Log.d(TAG, "isFullScreen: "+isFullScreen);
        return isFullScreen;
    }
    
    @Override
    public void toggleFullScreen() {
        Log.d(TAG, "toggleFullScreen");
        mediaPlayer.pause();
        if(getResources().getConfiguration().orientation==1){
            this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        }else{
            this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }
    }
    
  6. Implement touch event to show media controller
    //Show the media controller
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        controller.show();
        return false;
    }
    

activity_fullscreen_video.xml

  1. Default layout(PORTRAIT)
    
        
        
            
        
        
    
    
  2. Create LANDSCAPE layout
    Create a folder named layout-land in res, and create a layout file with the same name as activity_fullscreen_video.xml in it.

    
        
            
        
    
    

Comment the unused component in VideoControllerView.java

private void initControllerView(View v) {
    mPauseButton = (ImageButton) v.findViewById(R.id.pause);
    if (mPauseButton != null) {
        mPauseButton.requestFocus();
        mPauseButton.setOnClickListener(mPauseListener);
    }
    
    mFullscreenButton = (ImageButton) v.findViewById(R.id.fullscreen);
    if (mFullscreenButton != null) {
        mFullscreenButton.requestFocus();
        mFullscreenButton.setOnClickListener(mFullscreenListener);
    }

//        mFfwdButton = (ImageButton) v.findViewById(R.id.ffwd);
//        if (mFfwdButton != null) {
//            mFfwdButton.setOnClickListener(mFfwdListener);
//            if (!mFromXml) {
//                mFfwdButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
//            }
//        }
//
//        mRewButton = (ImageButton) v.findViewById(R.id.rew);
//        if (mRewButton != null) {
//            mRewButton.setOnClickListener(mRewListener);
//            if (!mFromXml) {
//                mRewButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
//            }
//        }

    // By default these are hidden. They will be enabled when setPrevNextListeners() is called 
//        mNextButton = (ImageButton) v.findViewById(R.id.next);
//        if (mNextButton != null && !mFromXml && !mListenersSet) {
//            mNextButton.setVisibility(View.GONE);
//        }
//        mPrevButton = (ImageButton) v.findViewById(R.id.prev);
//        if (mPrevButton != null && !mFromXml && !mListenersSet) {
//            mPrevButton.setVisibility(View.GONE);
//        }

    mProgress = (SeekBar) v.findViewById(R.id.mediacontroller_progress);
    if (mProgress != null) {
        if (mProgress instanceof SeekBar) {
            SeekBar seeker = (SeekBar) mProgress;
            seeker.setOnSeekBarChangeListener(mSeekListener);
        }
        mProgress.setMax(1000);
    }

    mEndTime = (TextView) v.findViewById(R.id.time);
    mCurrentTime = (TextView) v.findViewById(R.id.time_current);
    mFormatBuilder = new StringBuilder();
    mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());

    installPrevNextListeners();
}

Result

View on GitHub
技術提供:Blogger.