Taking control of the MediaController progress slider

coco picture coco · Jul 19, 2012 · Viewed 7.1k times · Source

I need to catch touch events to the MediaController progress slider, so that updates to the MediaPlayer don't occur until the finger lifts off the slider.

[ Perhaps my situation is unique: I am playing streaming video that comes in multiple "stacks" for each "program". The next stack is not loaded until the previous one is finished. The slider needs to represent the duration of all stacks, and the progress of the "thumb" needs to represent total duration. This is easily done by overriding the getBufferPercentage(), getCurrentPosition(), and getDuration() methods of MediaPlayerControl ]

More problematic is "scrubbing" (moving the thumb) back and forth along the timeline. If it causes the data source to be set multiple times along with a seekTo for every movement, things very quickly bog down and crash. It would be better if the MediaPlayer did no action until the user has finished the scrub.

As others have written, Yes it would be best to write my own implementation of the MediaController. But why redo all that work? I tried extending MediaController, but that got complicated quickly. I just wanted to catch the touch events to the slider!

Answer

coco picture coco · Jul 19, 2012

One is able to get a handle to the elements of MediaController:

final int topContainerId1 = getResources().getIdentifier("mediacontroller_progress", "id", "android");
final SeekBar seekbar = (SeekBar) mController.findViewById(topContainerId1);

Then set a listener on the seekbar, which will require you to implement its three public methods:

seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        // Log.i("TAG", "#### onProgressChanged: " + progress);
        // update current position here
        }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
        // Log.i("TAG", "#### onStartTrackingTouch");
        // this tells the controller to stay visible while user scrubs
        mController.show(3600000);
        // if it is possible, pause the video
        if (playerState == MPState.Started || playerState == MPState.Paused) {
            mediaPlayer.pause();
            playerState = MPState.Paused;
        }
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        int seekValue = seekBar.getProgress();
        int newMinutes = Math.round((float)getTotalDuration() * (float)seekValue / (float)seekBar.getMax());
        // Log.i("TAG", "#### onStopTrackingTouch: " + newMinutes);
        mController.show(3000); // = sDefaultTimeout, hide in 3 seconds
    }
});

Caveats: This is not updating the current position as you scrub, the left-hand-side TextView time value. (I had a truly remarkable way to do this which this margin is too small to contain).