Showing posts with label Android code sample: MediaPlayer. Show all posts
Showing posts with label Android code sample: MediaPlayer. Show all posts

Monday, May 2, 2016

Intent.ACTION_GET_CONTENT to open mp3, play using MediaPlayer, tested on Android 5.1 Lollipop


Refer to my old exercise of MediaPlayer "Display playing time for MediaPlayer", open mp3 using Intent of "ACTION_GET_CONTENT", then pass the media path, data.getData().getPath(), to mediaPlayer.setDataSource(). But it not work now.

To fix it, modify to pass data.getData() to mediaPlayer.setDataSource().

Tested on Android emulator running 5.5 Lollipop:


MainActivity.java
package com.blogspot.android_er.androidplayer;

import android.content.Intent;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class MainActivity extends AppCompatActivity {

    TextView info, state;
    Button buttonOpen, buttonOpenNew;
    Button buttonPlay, buttonPause, buttonStop;
    SeekBar timeLine;
    LinearLayout timeFrame;
    TextView timePos, timeDur;

    final static int RQS_OPEN_AUDIO_MP3 = 1;
    final static int RQS_OPEN_AUDIO_MP3_NEW = 2;

    MediaPlayer mediaPlayer;
    String srcPath = null;

    enum MP_State {
        Idle, Initialized, Prepared, Started, Paused,
        Stopped, PlaybackCompleted, End, Error, Preparing
    }

    MP_State mediaPlayerState;

    //ScheduledExecutorService myScheduledExecutorService;

    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        buttonOpen = (Button) findViewById(R.id.open);
        buttonOpen.setOnClickListener(buttonOpenOnClickListener);
        buttonOpenNew = (Button) findViewById(R.id.opennew);
        buttonOpenNew.setOnClickListener(buttonOpenNewOnClickListener);

        info = (TextView) findViewById(R.id.info);
        state = (TextView) findViewById(R.id.state);

        buttonPlay = (Button) findViewById(R.id.play);
        buttonPlay.setOnClickListener(buttonPlayOnClickListener);
        buttonPause = (Button) findViewById(R.id.pause);
        buttonPause.setOnClickListener(buttonPauseOnClickListener);
        buttonStop = (Button) findViewById(R.id.stop);
        buttonStop.setOnClickListener(buttonStopOnClickListener);

        //
        timeLine = (SeekBar) findViewById(R.id.seekbartimeline);
        timeFrame = (LinearLayout) findViewById(R.id.timeframe);
        timePos = (TextView) findViewById(R.id.pos);
        timeDur = (TextView) findViewById(R.id.dur);

        ScheduledExecutorService myScheduledExecutorService
                = Executors.newScheduledThreadPool(1);

        myScheduledExecutorService.scheduleWithFixedDelay(
                new Runnable() {
                    @Override
                    public void run() {
                        monitorHandler.sendMessage(monitorHandler.obtainMessage());
                    }
                },
                200, //initialDelay
                200, //delay
                TimeUnit.MILLISECONDS);

    }

    Handler monitorHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            mediaPlayerMonitor();
        }

    };

    private void mediaPlayerMonitor() {
        if (mediaPlayer == null) {
            timeLine.setVisibility(View.INVISIBLE);
            timeFrame.setVisibility(View.INVISIBLE);
        } else {
            if (mediaPlayer.isPlaying()) {
                timeLine.setVisibility(View.VISIBLE);
                timeFrame.setVisibility(View.VISIBLE);

                int mediaDuration = mediaPlayer.getDuration();
                int mediaPosition = mediaPlayer.getCurrentPosition();
                timeLine.setMax(mediaDuration);
                timeLine.setProgress(mediaPosition);
                timePos.setText(String.valueOf((float) mediaPosition / 1000) + "s");
                timeDur.setText(String.valueOf((float) mediaDuration / 1000) + "s");
            } else {
                timeLine.setVisibility(View.INVISIBLE);
                timeFrame.setVisibility(View.INVISIBLE);
            }
        }
    }

    MediaPlayer.OnErrorListener mediaPlayerOnErrorListener
            = new MediaPlayer.OnErrorListener() {

        @Override
        public boolean onError(MediaPlayer mp, int what, int extra) {
            // TODO Auto-generated method stub

            mediaPlayerState = MP_State.Error;
            showMediaPlayerState();

            return false;
        }
    };


    private void cmdReset() {
        if (mediaPlayer == null) {
            mediaPlayer = new MediaPlayer();
            mediaPlayer.setOnErrorListener(mediaPlayerOnErrorListener);
        }
        mediaPlayer.reset();
        mediaPlayerState = MP_State.Idle;
        showMediaPlayerState();
    }

    private void cmdSetDataSource(Uri uri) {
        if (mediaPlayerState == MP_State.Idle) {
            try {
                mediaPlayer.setDataSource(MainActivity.this, uri);
                mediaPlayerState = MP_State.Initialized;
            } catch (IllegalArgumentException e) {
                Toast.makeText(MainActivity.this,
                        e.toString(), Toast.LENGTH_LONG).show();
                e.printStackTrace();
            } catch (IllegalStateException e) {
                Toast.makeText(MainActivity.this,
                        e.toString(), Toast.LENGTH_LONG).show();
                e.printStackTrace();
            } catch (IOException e) {
                Toast.makeText(MainActivity.this,
                        e.toString(), Toast.LENGTH_LONG).show();
                e.printStackTrace();
            }
        } else {
            Toast.makeText(MainActivity.this,
                    "Invalid State@cmdSetDataSource - skip",
                    Toast.LENGTH_LONG).show();
        }

        showMediaPlayerState();
    }

    private void cmdSetDataSource(String path) {
        if (mediaPlayerState == MP_State.Idle) {
            try {
                mediaPlayer.setDataSource(path);
                mediaPlayerState = MP_State.Initialized;
            } catch (IllegalArgumentException e) {
                Toast.makeText(MainActivity.this,
                        e.toString(), Toast.LENGTH_LONG).show();
                e.printStackTrace();
            } catch (IllegalStateException e) {
                Toast.makeText(MainActivity.this,
                        e.toString(), Toast.LENGTH_LONG).show();
                e.printStackTrace();
            } catch (IOException e) {
                Toast.makeText(MainActivity.this,
                        e.toString(), Toast.LENGTH_LONG).show();
                e.printStackTrace();
            }
        } else {
            Toast.makeText(MainActivity.this,
                    "Invalid State@cmdSetDataSource - skip",
                    Toast.LENGTH_LONG).show();
        }

        showMediaPlayerState();
    }

    private void cmdPrepare() {

        if (mediaPlayerState == MP_State.Initialized
                || mediaPlayerState == MP_State.Stopped) {
            try {
                mediaPlayer.prepare();
                mediaPlayerState = MP_State.Prepared;
            } catch (IllegalStateException e) {
                Toast.makeText(MainActivity.this,
                        e.toString(), Toast.LENGTH_LONG).show();
                e.printStackTrace();
            } catch (IOException e) {
                Toast.makeText(MainActivity.this,
                        e.toString(), Toast.LENGTH_LONG).show();
                e.printStackTrace();
            }
        } else {
            Toast.makeText(MainActivity.this,
                    "Invalid State@cmdPrepare() - skip",
                    Toast.LENGTH_LONG).show();
        }

        showMediaPlayerState();
    }

    private void cmdStart() {
        if (mediaPlayerState == MP_State.Prepared
                || mediaPlayerState == MP_State.Started
                || mediaPlayerState == MP_State.Paused
                || mediaPlayerState == MP_State.PlaybackCompleted) {
            mediaPlayer.start();
            mediaPlayerState = MP_State.Started;
        } else {
            Toast.makeText(MainActivity.this,
                    "Invalid State@cmdStart() - skip",
                    Toast.LENGTH_LONG).show();
        }

        showMediaPlayerState();
    }

    private void cmdPause() {
        if (mediaPlayerState == MP_State.Started
                || mediaPlayerState == MP_State.Paused) {
            mediaPlayer.pause();
            mediaPlayerState = MP_State.Paused;
        } else {
            Toast.makeText(MainActivity.this,
                    "Invalid State@cmdPause() - skip",
                    Toast.LENGTH_LONG).show();
        }
        showMediaPlayerState();
    }

    private void cmdStop() {

        if (mediaPlayerState == MP_State.Prepared
                || mediaPlayerState == MP_State.Started
                || mediaPlayerState == MP_State.Stopped
                || mediaPlayerState == MP_State.Paused
                || mediaPlayerState == MP_State.PlaybackCompleted) {
            mediaPlayer.stop();
            mediaPlayerState = MP_State.Stopped;
        } else {
            Toast.makeText(MainActivity.this,
                    "Invalid State@cmdStop() - skip",
                    Toast.LENGTH_LONG).show();
        }
        showMediaPlayerState();

    }

    private void showMediaPlayerState() {

        switch (mediaPlayerState) {
            case Idle:
                state.setText("Idle");
                break;
            case Initialized:
                state.setText("Initialized");
                break;
            case Prepared:
                state.setText("Prepared");
                break;
            case Started:
                state.setText("Started");
                break;
            case Paused:
                state.setText("Paused");
                break;
            case Stopped:
                state.setText("Stopped");
                break;
            case PlaybackCompleted:
                state.setText("PlaybackCompleted");
                break;
            case End:
                state.setText("End");
                break;
            case Error:
                state.setText("Error");
                break;
            case Preparing:
                state.setText("Preparing");
                break;
            default:
                state.setText("Unknown!");
        }
    }

    View.OnClickListener buttonPlayOnClickListener
            = new View.OnClickListener() {

        @Override
        public void onClick(View v) {

            if (srcPath == null) {
                Toast.makeText(MainActivity.this,
                        "No file selected",
                        Toast.LENGTH_LONG).show();
            } else {
                cmdPrepare();
                cmdStart();
            }

        }

    };

    View.OnClickListener buttonPauseOnClickListener
            = new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            cmdPause();
        }

    };

    View.OnClickListener buttonStopOnClickListener
            = new View.OnClickListener() {

        @Override
        public void onClick(View v) {

            cmdStop();

        }

    };

    View.OnClickListener buttonOpenOnClickListener
            = new View.OnClickListener() {

        @Override
        public void onClick(View arg0) {
            Intent intent = new Intent();
            intent.setType("audio/mp3");
            intent.setAction(Intent.ACTION_GET_CONTENT);
            startActivityForResult(Intent.createChooser(
                    intent, "Open Audio (mp3) file"), RQS_OPEN_AUDIO_MP3);

        }
    };

    View.OnClickListener buttonOpenNewOnClickListener
            = new View.OnClickListener() {

        @Override
        public void onClick(View arg0) {
            Intent intent = new Intent();
            intent.setType("audio/mp3");
            intent.setAction(Intent.ACTION_GET_CONTENT);
            startActivityForResult(Intent.createChooser(
                    intent, "Open Audio (mp3) file"), RQS_OPEN_AUDIO_MP3_NEW);

        }
    };

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == RESULT_OK) {
            if (requestCode == RQS_OPEN_AUDIO_MP3) {
//work on my old post at that time, but not work now!!!
//http://android-er.blogspot.com/2012/06/display-playing-time-for-mediaplayer.html
                Uri audioFileUri = data.getData();

                srcPath = audioFileUri.getPath();
                info.setText(audioFileUri.toString() + "\n" + srcPath);

                cmdReset();
                cmdSetDataSource(srcPath);

            }else if(requestCode == RQS_OPEN_AUDIO_MP3_NEW){
                //New version,
                Uri audioFileUri = data.getData();

                srcPath = audioFileUri.getPath();
                info.setText(audioFileUri.toString() + "\n" + srcPath);

                cmdReset();
                cmdSetDataSource(audioFileUri);
            }
        }
    }
}


layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context="com.blogspot.android_er.androidplayer.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Button
        android:id="@+id/open"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Open MP3 file" />

    <Button
        android:id="@+id/opennew"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Open MP3 file (NEW)" />

    <TextView
        android:id="@+id/info"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/play"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Play" />

    <Button
        android:id="@+id/pause"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Pause" />

    <Button
        android:id="@+id/stop"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Stop" />

    <TextView
        android:id="@+id/state"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

    <SeekBar
        android:id="@+id/seekbartimeline"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:visibility="invisible" />

    <LinearLayout
        android:id="@+id/timeframe"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:visibility="invisible">

        <TextView
            android:id="@+id/pos"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/dur"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="right" />
    </LinearLayout>

</LinearLayout>


uses-permission of "android.permission.READ_EXTERNAL_STORAGE" is needed in AndroidManifest.xml


download filesDownload the files .

Related:
Open mp3 using Intent.ACTION_OPEN_DOCUMENT, ACTION_GET_CONTENT and ACTION_PICK, with checking and requesting permission at runtime.

Monday, April 18, 2016

Add MediaController to MediaPlayer


This example show how to add MediaController to simple MediaPlayer in previous example.


MainActivity.java
package com.blogspot.android_er.androidmediaplayer;

import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.MediaController;
import android.widget.Toast;

import java.io.IOException;

public class MainActivity extends AppCompatActivity
        implements SurfaceHolder.Callback, MediaPlayer.OnPreparedListener,
        MediaController.MediaPlayerControl {

    private SurfaceView surfaceView;
    private SurfaceHolder surfaceHolder;
    private MediaPlayer mediaPlayer;

    private MediaController mediaController;
    private Handler handler = new Handler();

    String videoSource =
            "https://sites.google.com/site/androidexample9/download/RunningClock.mp4";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        surfaceView = (SurfaceView)findViewById(R.id.surfaceview);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);

        surfaceView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if(mediaController != null){
                    mediaController.show();
                }
                return false;
            }
        });

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {

        Toast.makeText(MainActivity.this,
                "surfaceCreated()", Toast.LENGTH_LONG).show();
        mediaPlayer = new MediaPlayer();
        mediaPlayer.setDisplay(surfaceHolder);
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mediaPlayer.setOnPreparedListener(this);
        try {
            mediaPlayer.setDataSource(videoSource);
            mediaPlayer.prepare();

            mediaController = new MediaController(this);

        } catch (IOException e) {
            e.printStackTrace();
            Toast.makeText(MainActivity.this,
                    "something wrong!\n" + e.toString(),
                    Toast.LENGTH_LONG).show();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder,
                               int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        mediaPlayer.start();
        Toast.makeText(MainActivity.this,
                "onPrepared()", Toast.LENGTH_LONG).show();

        mediaController.setMediaPlayer(this);
        mediaController.setAnchorView(surfaceView);
        handler.post(new Runnable() {

            public void run() {
                mediaController.setEnabled(true);
                mediaController.show();
            }
        });
    }

    @Override
    public void start() {
        mediaPlayer.start();
    }

    @Override
    public void pause() {
        mediaPlayer.pause();
    }

    @Override
    public int getDuration() {
        return mediaPlayer.getDuration();
    }

    @Override
    public int getCurrentPosition() {
        return mediaPlayer.getCurrentPosition();
    }

    @Override
    public void seekTo(int pos) {
        mediaPlayer.seekTo(pos);
    }

    @Override
    public boolean isPlaying() {
        return mediaPlayer.isPlaying();
    }

    @Override
    public int getBufferPercentage() {
        return 0;
    }

    @Override
    public boolean canPause() {
        return true;
    }

    @Override
    public boolean canSeekBackward() {
        return true;
    }

    @Override
    public boolean canSeekForward() {
        return true;
    }

    @Override
    public int getAudioSessionId() {
        return mediaPlayer.getAudioSessionId();
    }
}


For layout and permission, refer to the previous post "MediaPlayer example to play video from Internet".


Saturday, April 16, 2016

MediaPlayer example to play video from Internet


Example using MediaPlayer/SurfaceView example to play video from Internet.

MainActivity.java
package com.blogspot.android_er.androidmediaplayer;

import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;

import java.io.IOException;

public class MainActivity extends AppCompatActivity
        implements SurfaceHolder.Callback, MediaPlayer.OnPreparedListener {

    private SurfaceView surfaceView;
    private SurfaceHolder surfaceHolder;
    private MediaPlayer mediaPlayer;

    String videoSource =
            "https://sites.google.com/site/androidexample9/download/RunningClock.mp4";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        surfaceView = (SurfaceView)findViewById(R.id.surfaceview);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {

        Toast.makeText(MainActivity.this,
                "surfaceCreated()", Toast.LENGTH_LONG).show();
        mediaPlayer = new MediaPlayer();
        mediaPlayer.setDisplay(surfaceHolder);
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mediaPlayer.setOnPreparedListener(this);
        try {
            mediaPlayer.setDataSource(videoSource);
            mediaPlayer.prepare();
        } catch (IOException e) {
            e.printStackTrace();
            Toast.makeText(MainActivity.this,
                    "something wrong!\n" + e.toString(),
                    Toast.LENGTH_LONG).show();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder,
                               int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        mediaPlayer.start();
        Toast.makeText(MainActivity.this,
                "onPrepared()", Toast.LENGTH_LONG).show();
    }
}


layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:orientation="vertical"
    tools:context="com.blogspot.android_er.androidmediaplayer.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <SurfaceView
        android:id="@+id/surfaceview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>


uses-permission of "android.permission.INTERNET" is needed in AndroidManifest.xml.



Next:
Add MediaController to MediaPlayer

Related:
- VideoView example to play video from Internet

Monday, February 9, 2015

Create audio Visualizer for MediaPlayer

This example create audio Visualizer for MediaPlayer, reference Android demo example: ApiDemos > Media > AudioTx. Permission android.permission.RECORD_AUDIO is needed,  to use visualizer.

remark@2016-10-18:
I found that the example code removed from Android Studio examples list, may be it is  NOT work now.



Create custom VisualizerView extends View, VisualizerView.java
package com.example.androidaudiovisualizer;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;

public class VisualizerView extends View {

 private byte[] mBytes;
 private float[] mPoints;
 private Rect mRect = new Rect();
 private Paint mForePaint = new Paint();

 public VisualizerView(Context context) {
  super(context);
  init();
 }

 public VisualizerView(Context context, AttributeSet attrs) {
  super(context, attrs);
  init();
 }

 public VisualizerView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  init();
 }

 private void init() {
  mBytes = null;
  mForePaint.setStrokeWidth(1f);
  mForePaint.setAntiAlias(true);
  mForePaint.setColor(Color.rgb(0, 128, 255));
 }

 public void updateVisualizer(byte[] bytes) {
  mBytes = bytes;
  invalidate();
 }

 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  if (mBytes == null) {
   return;
  }
  if (mPoints == null || mPoints.length < mBytes.length * 4) {
   mPoints = new float[mBytes.length * 4];
  }
  mRect.set(0, 0, getWidth(), getHeight());
  for (int i = 0; i < mBytes.length - 1; i++) {
   mPoints[i * 4] = mRect.width() * i / (mBytes.length - 1);
   mPoints[i * 4 + 1] = mRect.height() / 2
     + ((byte) (mBytes[i] + 128)) * (mRect.height() / 2) / 128;
   mPoints[i * 4 + 2] = mRect.width() * (i + 1) / (mBytes.length - 1);
   mPoints[i * 4 + 3] = mRect.height() / 2
     + ((byte) (mBytes[i + 1] + 128)) * (mRect.height() / 2)
     / 128;
  }
  canvas.drawLines(mPoints, mForePaint);
 }

}

Add <com.example.androidaudiovisualizer.VisualizerView> to layout file, activity_main.xml.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.androidaudiovisualizer.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <com.example.androidaudiovisualizer.VisualizerView
        android:id="@+id/myvisualizerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

MainActivity.java
package com.example.androidaudiovisualizer;

import android.support.v7.app.ActionBarActivity;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.audiofx.Visualizer;
import android.os.Bundle;

/*
 * Copy test.mp3 to /res/raw/ folder
 * 
 * needed in AndroidManifest.xml
 * android:minSdkVersion="9"
 * uses-permission of "android.permission.RECORD_AUDIO"
 * 
 * reference: Android demo example -
 * ApiDemos > Media > AudioTx
 */

public class MainActivity extends ActionBarActivity {

 VisualizerView mVisualizerView;

 private MediaPlayer mMediaPlayer;
 private Visualizer mVisualizer;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  mVisualizerView = (VisualizerView) findViewById(R.id.myvisualizerview);

  initAudio();
 }

 @Override
 protected void onPause() {
  super.onPause();
  if (isFinishing() && mMediaPlayer != null) {
   mVisualizer.release();
   mMediaPlayer.release();
   mMediaPlayer = null;
  }
 }

 private void initAudio() {
  setVolumeControlStream(AudioManager.STREAM_MUSIC);
  mMediaPlayer = MediaPlayer.create(this, R.raw.test);

  setupVisualizerFxAndUI();
  // Make sure the visualizer is enabled only when you actually want to
  // receive data, and
  // when it makes sense to receive data.
  mVisualizer.setEnabled(true);
  // When the stream ends, we don't need to collect any more data. We
  // don't do this in
  // setupVisualizerFxAndUI because we likely want to have more,
  // non-Visualizer related code
  // in this callback.
  mMediaPlayer
    .setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
     public void onCompletion(MediaPlayer mediaPlayer) {
      mVisualizer.setEnabled(false);
     }
    });
  mMediaPlayer.start();

 }

 private void setupVisualizerFxAndUI() {

  // Create the Visualizer object and attach it to our media player.
  mVisualizer = new Visualizer(mMediaPlayer.getAudioSessionId());
  mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);
  mVisualizer.setDataCaptureListener(
    new Visualizer.OnDataCaptureListener() {
     public void onWaveFormDataCapture(Visualizer visualizer,
       byte[] bytes, int samplingRate) {
      mVisualizerView.updateVisualizer(bytes);
     }

     public void onFftDataCapture(Visualizer visualizer,
       byte[] bytes, int samplingRate) {
     }
    }, Visualizer.getMaxCaptureRate() / 2, true, false);
 }

}


Next example:
Visible DTMF Piano: Visualizer + ToneGenerator

Monday, May 5, 2014

Implement time bar for MediaPlayer, also introduce bug of MediaPlayer.seekTo()

Continuous from last post of MediaPlay MP3 Player, a SeekBar is added to show the current playing position.

Also user can seek to a specified time by moving the SeekBar, by calling seekTo() of MediaPlayer. But the seekTo() method work in Nexus One (Android 2.3.6), not work on Nexus 7 1st generation (Android 4.4.2). It seem to be a bug!


Modify fragment_main.xml to add a SeekBar.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.androidmp3player.MainActivity$PlaceholderFragment" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <Button
        android:id="@+id/start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start" />
    <Button
        android:id="@+id/pause"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Pause" />
    <Button
        android:id="@+id/stop"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Stop" />
    <Button
        android:id="@+id/seekto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Seek To Beginning" />
    <SeekBar 
        android:id="@+id/time"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progress="0"/>
    <TextView
        android:id="@+id/state"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/duration"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/position"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>


MainActivity.java
package com.example.androidmp3player;

import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.Fragment;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnSeekCompleteListener;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  if (savedInstanceState == null) {
   getSupportFragmentManager().beginTransaction()
     .add(R.id.container, new PlaceholderFragment()).commit();
  }
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {

  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  // Handle action bar item clicks here. The action bar will
  // automatically handle clicks on the Home/Up button, so long
  // as you specify a parent activity in AndroidManifest.xml.
  int id = item.getItemId();
  if (id == R.id.action_settings) {
   return true;
  }
  return super.onOptionsItemSelected(item);
 }

 /**
  * A placeholder fragment containing a simple view.
  */
 public static class PlaceholderFragment extends Fragment {

  Button btnStart, btnPause, btnStop, btnSeek;
  TextView textState, textDuration, textPosition;
  SeekBar timeBar;

  MediaPlayer mediaPlayer;

  private int stateMediaPlayer;
  private final int STATE_Idle = 0;
  private final int STATE_Initialized = 1;
  private final int STATE_Preparing = 2;
  private final int STATE_Prepared = 3;
  private final int STATE_Started = 4;
  private final int STATE_Paused = 5;
  private final int STATE_Stopped = 6;
  private final int STATE_PlaybackCompleted = 7;
  private final int STATE_End = 8;
  private final int STATE_Error = 9;
  
  PlayerTimeTask playerTimeTask;
  
  public PlaceholderFragment() {
  }

  @Override
  public void onCreate(Bundle savedInstanceState) {
   // TODO Auto-generated method stub
   super.onCreate(savedInstanceState);
   initMediaPlayer();
   playerTimeTask = new PlayerTimeTask();
   playerTimeTask.execute();
  }

  @Override
  public void onDestroy() {
   
   playerTimeTask.setRunning(false);

   Toast.makeText(getActivity(), 
    "release mediaPlayer", 
    Toast.LENGTH_LONG).show();
   mediaPlayer.release();
   mediaPlayer = null;
   setPlayerState(STATE_End);
   
   super.onDestroy();
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
   View rootView = inflater.inflate(R.layout.fragment_main, container,
     false);
   btnStart = (Button) rootView.findViewById(R.id.start);
   btnPause = (Button) rootView.findViewById(R.id.pause);
   btnStop = (Button) rootView.findViewById(R.id.stop);
   btnSeek = (Button) rootView.findViewById(R.id.seekto);
   
   btnStart.setOnClickListener(new OnClickListener() {
    
    @Override
    public void onClick(View v) {
     
     if(stateMediaPlayer==STATE_Prepared 
      || stateMediaPlayer==STATE_Started
      || stateMediaPlayer==STATE_Paused
      || stateMediaPlayer==STATE_PlaybackCompleted){
      mediaPlayer.start();
      setPlayerState(STATE_Started);
      
      displayDurationPosition();
     }else{
      Toast.makeText(getActivity(), 
       "Play at Invalid state!", 
       Toast.LENGTH_LONG).show();
     }
    }
   });
   
   btnPause.setOnClickListener(new OnClickListener() {
    
    @Override
    public void onClick(View v) {
     
     if(stateMediaPlayer==STATE_Started
      || stateMediaPlayer==STATE_Paused
      || stateMediaPlayer==STATE_Prepared //simulate a error case
      || stateMediaPlayer==STATE_PlaybackCompleted){
      mediaPlayer.pause();
      setPlayerState(STATE_Paused);
      
      displayDurationPosition();
     }else{
      Toast.makeText(getActivity(), 
       "Pause at Invalid state!", 
       Toast.LENGTH_LONG).show();
     }
    }
   });
   
   btnStop.setOnClickListener(new OnClickListener() {
    
    @Override
    public void onClick(View v) {
     
     if(stateMediaPlayer==STATE_Prepared
      || stateMediaPlayer==STATE_Started
      || stateMediaPlayer==STATE_Stopped
      || stateMediaPlayer==STATE_Paused
      || stateMediaPlayer==STATE_PlaybackCompleted){
      
      //Stop
      mediaPlayer.stop();
      setPlayerState(STATE_Stopped);
      
      //then parepare in background thread
      mediaPlayer.prepareAsync();
      setPlayerState(STATE_Preparing);
      
      displayDurationPosition();
     }else{
      Toast.makeText(getActivity(), 
       "Stop at Invalid state!", 
       Toast.LENGTH_LONG).show();
     }
     
    }
   });
   
   btnSeek.setOnClickListener(new OnClickListener(){

    @Override
    public void onClick(View v) {
     if(stateMediaPlayer==STATE_Prepared
      || stateMediaPlayer==STATE_Started
      || stateMediaPlayer==STATE_Paused
      || stateMediaPlayer==STATE_PlaybackCompleted){
      mediaPlayer.seekTo(0);
      
      displayDurationPosition();
     }else{
      Toast.makeText(getActivity(), 
       "SeekTo at Invalid state!", 
       Toast.LENGTH_LONG).show();
     }
    }});
   
   timeBar = (SeekBar) rootView.findViewById(R.id.time);
   timeBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
    
    int targetPos = 0;
    boolean rqsSeek = false;
    
    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {

     if(rqsSeek){

      if(mediaPlayer!=null){
       if(stateMediaPlayer==STATE_Prepared
        || stateMediaPlayer==STATE_Started
        || stateMediaPlayer==STATE_Paused
        || stateMediaPlayer==STATE_PlaybackCompleted){
        
        mediaPlayer.seekTo(targetPos);
       }
      }
      
      rqsSeek = false;
     }
     
    }
    
    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {}
    
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress,
      boolean fromUser) {
     
     if(fromUser){
      rqsSeek = true;

      if(mediaPlayer!=null){
       float seekToPercentage = (float)progress/100.0f;
       targetPos = (int)(mediaPlayer.getDuration() * seekToPercentage);
      }
     }
     
    }
   });

   textState = (TextView) rootView.findViewById(R.id.state);
   textState.setText(getPlayerState());
   
   textDuration = (TextView) rootView.findViewById(R.id.duration);
   textPosition = (TextView) rootView.findViewById(R.id.position);
   displayDurationPosition();
   
   textDuration.setOnClickListener(new OnClickListener(){

    @Override
    public void onClick(View v) {
     displayDurationPosition();
    }});
   
   textPosition.setOnClickListener(new OnClickListener(){

    @Override
    public void onClick(View v) {
     displayDurationPosition();
    }});
   
   return rootView;
  }
  
  private void displayDurationPosition(){
   textDuration.setText(
     "Duration: " + mediaPlayer.getDuration() + " ms");
   textPosition.setText(
     "Current Position: " + mediaPlayer.getCurrentPosition() + " ms");
  }

  private void initMediaPlayer() {
   Toast.makeText(getActivity(), 
     "initMediaPlayer()", 
     Toast.LENGTH_LONG).show();
   mediaPlayer = MediaPlayer.create(getActivity(), R.raw.vespers);
   setPlayerState(STATE_Prepared);
   
   mediaPlayer.setOnPreparedListener(new OnPreparedListener(){

    @Override
    public void onPrepared(MediaPlayer mp) {
     setPlayerState(STATE_Prepared);
     displayDurationPosition();
    }});
   
   mediaPlayer.setOnCompletionListener(new OnCompletionListener(){

    @Override
    public void onCompletion(MediaPlayer mp) {
     setPlayerState(STATE_PlaybackCompleted);
     displayDurationPosition();
    }});
   
   //Handle Error
   mediaPlayer.setOnErrorListener(new OnErrorListener(){

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
     
     setPlayerState(STATE_Error);
     
     String errorWhat;
     switch(what){
     case MediaPlayer.MEDIA_ERROR_UNKNOWN:
      errorWhat = "MEDIA_ERROR_UNKNOWN";
      break;
     case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
      errorWhat = "MEDIA_ERROR_SERVER_DIED";
      break;
     default:
      errorWhat = "!";
     }
     
     String errorExtra;
     switch(extra){
     case MediaPlayer.MEDIA_ERROR_IO:
      errorExtra = "MEDIA_ERROR_IO";
      break;
     case MediaPlayer.MEDIA_ERROR_MALFORMED:
      errorExtra = "MEDIA_ERROR_MALFORMED";
      break;
     case MediaPlayer.MEDIA_ERROR_UNSUPPORTED:
      errorExtra = "MEDIA_ERROR_UNSUPPORTED";
      break;
     case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
      errorExtra = "MEDIA_ERROR_TIMED_OUT";
      break;
     default:
      errorExtra = "!";
     }

     Toast.makeText(getActivity(), 
      "Error" + "\n"
      + errorWhat + "\n"
      + errorExtra,
      Toast.LENGTH_LONG).show();
     
     //release 
     mp.release();
     initMediaPlayer();
     
     return true;
    }});
   
   mediaPlayer.setOnSeekCompleteListener(new OnSeekCompleteListener() {
    
    @Override
    public void onSeekComplete(MediaPlayer mp) {
     Toast.makeText(getActivity(), 
      "OnSeekComplete: " + mp.getCurrentPosition(), 
      Toast.LENGTH_SHORT).show();

    }
   });
  }
  
  private void setPlayerState(int st){
   stateMediaPlayer = st;
   
   String stringState = getPlayerState();
   if(textState!=null){
    textState.setText(stringState);
   }else{
    Toast.makeText(getActivity(), 
      stringState, Toast.LENGTH_LONG).show();
   }
   
  }
  
  private String getPlayerState(){
   String strSt;
   switch(stateMediaPlayer){
   case STATE_Idle:
    strSt = "Idle";
    break;
   case STATE_Initialized:
    strSt = "Initialized";
    break;
   case STATE_Preparing:
    strSt = "Preparing";
    break;
   case STATE_Prepared:
    strSt = "Prepared";
    break;
   case STATE_Started:
    strSt = "Started";
    break;
   case STATE_Paused:
    strSt = "Paused";
    break;
   case STATE_Stopped:
    strSt = "Stopped";
    break;
   case STATE_PlaybackCompleted:
    strSt = "PlaybackCompleted";
    break;
   case STATE_End:
    strSt = "End";
    break;
   case STATE_Error:
    strSt = "Error";
    break;
   default:
    strSt = "unknown...";
   }
   return strSt;
  }
  
  public class PlayerTimeTask extends AsyncTask<Void, Void, Void> {

   boolean running;
   
   public PlayerTimeTask() {
    running = true;
   }
   
   public void setRunning(boolean r){
    running = r;
   }

   @Override
   protected Void doInBackground(Void... params) {
    while(running){
     SystemClock.sleep(250);
     publishProgress();
    }
    return null;
   }

   @Override
   protected void onProgressUpdate(Void... values) {
    if(timeBar!=null){

     if(mediaPlayer!=null){
       
      if(stateMediaPlayer == STATE_Prepared
       || stateMediaPlayer == STATE_Started
       || stateMediaPlayer == STATE_Paused
       || stateMediaPlayer == STATE_Stopped
       || stateMediaPlayer == STATE_PlaybackCompleted){
       int cur = mediaPlayer.getCurrentPosition();
       int dur = mediaPlayer.getDuration();
       int timePercentage = 100 * cur/dur;
       timeBar.setProgress(timePercentage);
      }
      
      textPosition.setText(
        "Current Position: " 
        + mediaPlayer.getCurrentPosition() + " ms");
     }

    }
   }


  }
 }
 
}


download filesDownload the files, not include mp3.

Downlaod and try the APK.

Sunday, May 4, 2014

Re-set On..Listener after mediaPlayer.release and re-create MediaPlayer

It's a BIG bug in last exercise Implement OnErrorListener for MP3 Player using MediaPlayer: after we release the old mediaPlayer, and create again, the original OnPreparedListener(), OnCompletionListener() and OnErrorListener() are not associate with the new mediaPlayer; and will not be called. So we should move all code of setOnPreparedListener(), setOnCompletionListener() and setOnErrorListener() to initMediaPlayer(); to update the Listeners after new mediaPlayer created.

MainActivity.java
package com.example.androidmp3player;

import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.Fragment;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  if (savedInstanceState == null) {
   getSupportFragmentManager().beginTransaction()
     .add(R.id.container, new PlaceholderFragment()).commit();
  }
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {

  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  // Handle action bar item clicks here. The action bar will
  // automatically handle clicks on the Home/Up button, so long
  // as you specify a parent activity in AndroidManifest.xml.
  int id = item.getItemId();
  if (id == R.id.action_settings) {
   return true;
  }
  return super.onOptionsItemSelected(item);
 }

 /**
  * A placeholder fragment containing a simple view.
  */
 public static class PlaceholderFragment extends Fragment {

  Button btnStart, btnPause, btnStop, btnSeek;
  TextView textState, textDuration, textPosition;

  MediaPlayer mediaPlayer;

  private int stateMediaPlayer;
  private final int STATE_Idle = 0;
  private final int STATE_Initialized = 1;
  private final int STATE_Preparing = 2;
  private final int STATE_Prepared = 3;
  private final int STATE_Started = 4;
  private final int STATE_Paused = 5;
  private final int STATE_Stopped = 6;
  private final int STATE_PlaybackCompleted = 7;
  private final int STATE_End = 8;
  private final int STATE_Error = 9;
  
  public PlaceholderFragment() {
  }

  @Override
  public void onCreate(Bundle savedInstanceState) {
   // TODO Auto-generated method stub
   super.onCreate(savedInstanceState);
   initMediaPlayer();
  }

  @Override
  public void onDestroy() {

   Toast.makeText(getActivity(), 
    "release mediaPlayer", 
    Toast.LENGTH_LONG).show();
   mediaPlayer.release();
   mediaPlayer = null;
   setPlayerState(STATE_End);
   
   super.onDestroy();
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
   View rootView = inflater.inflate(R.layout.fragment_main, container,
     false);
   btnStart = (Button) rootView.findViewById(R.id.start);
   btnPause = (Button) rootView.findViewById(R.id.pause);
   btnStop = (Button) rootView.findViewById(R.id.stop);
   btnSeek = (Button) rootView.findViewById(R.id.seekto);
   
   btnStart.setOnClickListener(new OnClickListener() {
    
    @Override
    public void onClick(View v) {
     
     if(stateMediaPlayer==STATE_Prepared 
      || stateMediaPlayer==STATE_Started
      || stateMediaPlayer==STATE_Paused
      || stateMediaPlayer==STATE_PlaybackCompleted){
      mediaPlayer.start();
      setPlayerState(STATE_Started);
      
      displayDurationPosition();
     }else{
      Toast.makeText(getActivity(), 
       "Play at Invalid state!", 
       Toast.LENGTH_LONG).show();
     }
    }
   });
   
   btnPause.setOnClickListener(new OnClickListener() {
    
    @Override
    public void onClick(View v) {
     
     if(stateMediaPlayer==STATE_Started
      || stateMediaPlayer==STATE_Paused
      || stateMediaPlayer==STATE_Prepared //simulate a error case
      || stateMediaPlayer==STATE_PlaybackCompleted){
      mediaPlayer.pause();
      setPlayerState(STATE_Paused);
      
      displayDurationPosition();
     }else{
      Toast.makeText(getActivity(), 
       "Pause at Invalid state!", 
       Toast.LENGTH_LONG).show();
     }
    }
   });
   
   btnStop.setOnClickListener(new OnClickListener() {
    
    @Override
    public void onClick(View v) {
     
     if(stateMediaPlayer==STATE_Prepared
      || stateMediaPlayer==STATE_Started
      || stateMediaPlayer==STATE_Stopped
      || stateMediaPlayer==STATE_Paused
      || stateMediaPlayer==STATE_PlaybackCompleted){
      
      //Stop
      mediaPlayer.stop();
      setPlayerState(STATE_Stopped);
      
      //then parepare in background thread
      mediaPlayer.prepareAsync();
      setPlayerState(STATE_Preparing);
      
      displayDurationPosition();
     }else{
      Toast.makeText(getActivity(), 
       "Stop at Invalid state!", 
       Toast.LENGTH_LONG).show();
     }
     
    }
   });
   
   btnSeek.setOnClickListener(new OnClickListener(){

    @Override
    public void onClick(View v) {
     if(stateMediaPlayer==STATE_Prepared
      || stateMediaPlayer==STATE_Started
      || stateMediaPlayer==STATE_Paused
      || stateMediaPlayer==STATE_PlaybackCompleted){
      mediaPlayer.seekTo(0);
      
      displayDurationPosition();
     }else{
      Toast.makeText(getActivity(), 
       "SeekTo at Invalid state!", 
       Toast.LENGTH_LONG).show();
     }
    }});

   textState = (TextView) rootView.findViewById(R.id.state);
   textState.setText(getPlayerState());
   
   textDuration = (TextView) rootView.findViewById(R.id.duration);
   textPosition = (TextView) rootView.findViewById(R.id.position);
   displayDurationPosition();
   
   textDuration.setOnClickListener(new OnClickListener(){

    @Override
    public void onClick(View v) {
     displayDurationPosition();
    }});
   
   textPosition.setOnClickListener(new OnClickListener(){

    @Override
    public void onClick(View v) {
     displayDurationPosition();
    }});
   
   return rootView;
  }
  
  private void displayDurationPosition(){
   textDuration.setText(
     "Duration: " + mediaPlayer.getDuration() + " ms");
   textPosition.setText(
     "Current Position: " + mediaPlayer.getCurrentPosition() + " ms");
  }

  private void initMediaPlayer() {
   Toast.makeText(getActivity(), 
     "initMediaPlayer()", 
     Toast.LENGTH_LONG).show();
   mediaPlayer = MediaPlayer.create(getActivity(), R.raw.vespers);
   setPlayerState(STATE_Prepared);
   
   mediaPlayer.setOnPreparedListener(new OnPreparedListener(){

    @Override
    public void onPrepared(MediaPlayer mp) {
     setPlayerState(STATE_Prepared);
     displayDurationPosition();
    }});
   
   mediaPlayer.setOnCompletionListener(new OnCompletionListener(){

    @Override
    public void onCompletion(MediaPlayer mp) {
     setPlayerState(STATE_PlaybackCompleted);
     displayDurationPosition();
    }});
   
   //Handle Error
   mediaPlayer.setOnErrorListener(new OnErrorListener(){

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
     
     setPlayerState(STATE_Error);
     
     String errorWhat;
     switch(what){
     case MediaPlayer.MEDIA_ERROR_UNKNOWN:
      errorWhat = "MEDIA_ERROR_UNKNOWN";
      break;
     case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
      errorWhat = "MEDIA_ERROR_SERVER_DIED";
      break;
     default:
      errorWhat = "!";
     }
     
     String errorExtra;
     switch(extra){
     case MediaPlayer.MEDIA_ERROR_IO:
      errorExtra = "MEDIA_ERROR_IO";
      break;
     case MediaPlayer.MEDIA_ERROR_MALFORMED:
      errorExtra = "MEDIA_ERROR_MALFORMED";
      break;
     case MediaPlayer.MEDIA_ERROR_UNSUPPORTED:
      errorExtra = "MEDIA_ERROR_UNSUPPORTED";
      break;
     case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
      errorExtra = "MEDIA_ERROR_TIMED_OUT";
      break;
     default:
      errorExtra = "!";
     }

     Toast.makeText(getActivity(), 
      "Error" + "\n"
      + errorWhat + "\n"
      + errorExtra,
      Toast.LENGTH_LONG).show();
     
     //release 
     mp.release();
     initMediaPlayer();
     
     return true;
    }});
  }
  
  private void setPlayerState(int st){
   stateMediaPlayer = st;
   
   String stringState = getPlayerState();
   if(textState!=null){
    textState.setText(stringState);
   }else{
    Toast.makeText(getActivity(), 
      stringState, Toast.LENGTH_LONG).show();
   }
   
  }
  
  private String getPlayerState(){
   String strSt;
   switch(stateMediaPlayer){
   case STATE_Idle:
    strSt = "Idle";
    break;
   case STATE_Initialized:
    strSt = "Initialized";
    break;
   case STATE_Preparing:
    strSt = "Preparing";
    break;
   case STATE_Prepared:
    strSt = "Prepared";
    break;
   case STATE_Started:
    strSt = "Started";
    break;
   case STATE_Paused:
    strSt = "Paused";
    break;
   case STATE_Stopped:
    strSt = "Stopped";
    break;
   case STATE_PlaybackCompleted:
    strSt = "PlaybackCompleted";
    break;
   case STATE_End:
    strSt = "End";
    break;
   case STATE_Error:
    strSt = "Error";
    break;
   default:
    strSt = "unknown...";
   }
   return strSt;
  }
 }

}


download filesDownload the files, without mp3.

Next:
Implement time bar for MediaPlayer, also introduce bug of MediaPlayer.seekTo()

Implement OnErrorListener for MP3 Player using MediaPlayer

The former post show how to Implement Android MP3 Player using MediaPlayer, without handle error case. To detect error for MediaPlayer, we can implement our OnErrorListener, and add it to MediaPlayer by calling setOnErrorListener().

Please note that this exercise show how to implement and add OnErrorListener, not how to solve the error.


To simpulate error in our exercise, modify the OnClickListener of btnPause, to accept if (stateMediaPlayer==STATE_Prepared), its a invalide case. When user click on the Pause button when the MediaPlayer is in STATE_Prepared, error will occur. Without OnErrorListener, OnCompletionListener will be called, many error message will be dispalyed in LogCat, and the MP3 cannot be play anymore.

Modify MainActivity.java in the former exercise to implement OnErrorListener. When error occur, release the old MediaPlay and instantiate a new one by calling initMediaPlayer().

package com.example.androidmp3player;

import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.Fragment;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  if (savedInstanceState == null) {
   getSupportFragmentManager().beginTransaction()
     .add(R.id.container, new PlaceholderFragment()).commit();
  }
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {

  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  // Handle action bar item clicks here. The action bar will
  // automatically handle clicks on the Home/Up button, so long
  // as you specify a parent activity in AndroidManifest.xml.
  int id = item.getItemId();
  if (id == R.id.action_settings) {
   return true;
  }
  return super.onOptionsItemSelected(item);
 }

 /**
  * A placeholder fragment containing a simple view.
  */
 public static class PlaceholderFragment extends Fragment {

  Button btnStart, btnPause, btnStop, btnSeek;
  TextView textState, textDuration, textPosition;

  MediaPlayer mediaPlayer;

  private int stateMediaPlayer;
  private final int STATE_Idle = 0;
  private final int STATE_Initialized = 1;
  private final int STATE_Preparing = 2;
  private final int STATE_Prepared = 3;
  private final int STATE_Started = 4;
  private final int STATE_Paused = 5;
  private final int STATE_Stopped = 6;
  private final int STATE_PlaybackCompleted = 7;
  private final int STATE_End = 8;
  private final int STATE_Error = 9;
  
  public PlaceholderFragment() {
  }

  @Override
  public void onCreate(Bundle savedInstanceState) {
   // TODO Auto-generated method stub
   super.onCreate(savedInstanceState);
   initMediaPlayer();
  }

  @Override
  public void onDestroy() {

   Toast.makeText(getActivity(), 
    "release mediaPlayer", 
    Toast.LENGTH_LONG).show();
   mediaPlayer.release();
   mediaPlayer = null;
   setPlayerState(STATE_End);
   
   super.onDestroy();
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
   View rootView = inflater.inflate(R.layout.fragment_main, container,
     false);
   btnStart = (Button) rootView.findViewById(R.id.start);
   btnPause = (Button) rootView.findViewById(R.id.pause);
   btnStop = (Button) rootView.findViewById(R.id.stop);
   btnSeek = (Button) rootView.findViewById(R.id.seekto);
   
   btnStart.setOnClickListener(new OnClickListener() {
    
    @Override
    public void onClick(View v) {
     
     if(stateMediaPlayer==STATE_Prepared 
      || stateMediaPlayer==STATE_Started
      || stateMediaPlayer==STATE_Paused
      || stateMediaPlayer==STATE_PlaybackCompleted){
      mediaPlayer.start();
      setPlayerState(STATE_Started);
      
      displayDurationPosition();
     }else{
      Toast.makeText(getActivity(), 
       "Play at Invalid state!", 
       Toast.LENGTH_LONG).show();
     }
    }
   });
   
   btnPause.setOnClickListener(new OnClickListener() {
    
    @Override
    public void onClick(View v) {
     
     if(stateMediaPlayer==STATE_Started
      || stateMediaPlayer==STATE_Paused
      || stateMediaPlayer==STATE_Prepared //simulate a error case
      || stateMediaPlayer==STATE_PlaybackCompleted){
      mediaPlayer.pause();
      setPlayerState(STATE_Paused);
      
      displayDurationPosition();
     }else{
      Toast.makeText(getActivity(), 
       "Pause at Invalid state!", 
       Toast.LENGTH_LONG).show();
     }
    }
   });
   
   btnStop.setOnClickListener(new OnClickListener() {
    
    @Override
    public void onClick(View v) {
     
     if(stateMediaPlayer==STATE_Prepared
      || stateMediaPlayer==STATE_Started
      || stateMediaPlayer==STATE_Stopped
      || stateMediaPlayer==STATE_Paused
      || stateMediaPlayer==STATE_PlaybackCompleted){
      
      //Stop
      mediaPlayer.stop();
      setPlayerState(STATE_Stopped);
      
      //then parepare in background thread
      mediaPlayer.prepareAsync();
      setPlayerState(STATE_Preparing);
      
      displayDurationPosition();
     }else{
      Toast.makeText(getActivity(), 
       "Stop at Invalid state!", 
       Toast.LENGTH_LONG).show();
     }
     
    }
   });
   
   btnSeek.setOnClickListener(new OnClickListener(){

    @Override
    public void onClick(View v) {
     if(stateMediaPlayer==STATE_Prepared
      || stateMediaPlayer==STATE_Started
      || stateMediaPlayer==STATE_Paused
      || stateMediaPlayer==STATE_PlaybackCompleted){
      mediaPlayer.seekTo(0);
      
      displayDurationPosition();
     }else{
      Toast.makeText(getActivity(), 
       "SeekTo at Invalid state!", 
       Toast.LENGTH_LONG).show();
     }
    }});
   
   mediaPlayer.setOnPreparedListener(new OnPreparedListener(){

    @Override
    public void onPrepared(MediaPlayer mp) {
     setPlayerState(STATE_Prepared);
     displayDurationPosition();
    }});
   
   mediaPlayer.setOnCompletionListener(new OnCompletionListener(){

    @Override
    public void onCompletion(MediaPlayer mp) {
     setPlayerState(STATE_PlaybackCompleted);
     displayDurationPosition();
    }});

   //Handle Error
   mediaPlayer.setOnErrorListener(new OnErrorListener(){

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
     
     setPlayerState(STATE_Error);
     
     String errorWhat;
     switch(what){
     case MediaPlayer.MEDIA_ERROR_UNKNOWN:
      errorWhat = "MEDIA_ERROR_UNKNOWN";
      break;
     case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
      errorWhat = "MEDIA_ERROR_SERVER_DIED";
      break;
     default:
      errorWhat = "!";
     }
     
     String errorExtra;
     switch(extra){
     case MediaPlayer.MEDIA_ERROR_IO:
      errorExtra = "MEDIA_ERROR_IO";
      break;
     case MediaPlayer.MEDIA_ERROR_MALFORMED:
      errorExtra = "MEDIA_ERROR_MALFORMED";
      break;
     case MediaPlayer.MEDIA_ERROR_UNSUPPORTED:
      errorExtra = "MEDIA_ERROR_UNSUPPORTED";
      break;
     case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
      errorExtra = "MEDIA_ERROR_TIMED_OUT";
      break;
     default:
      errorExtra = "!";
     }

     Toast.makeText(getActivity(), 
      "Error" + "\n"
      + errorWhat + "\n"
      + errorExtra,
      Toast.LENGTH_LONG).show();
     
     //release 
     mp.release();
     initMediaPlayer();
     
     return true;
    }});
   
   textState = (TextView) rootView.findViewById(R.id.state);
   textState.setText(getPlayerState());
   
   textDuration = (TextView) rootView.findViewById(R.id.duration);
   textPosition = (TextView) rootView.findViewById(R.id.position);
   displayDurationPosition();
   
   textDuration.setOnClickListener(new OnClickListener(){

    @Override
    public void onClick(View v) {
     displayDurationPosition();
    }});
   
   textPosition.setOnClickListener(new OnClickListener(){

    @Override
    public void onClick(View v) {
     displayDurationPosition();
    }});
   
   return rootView;
  }
  
  private void displayDurationPosition(){
   textDuration.setText(
     "Duration: " + mediaPlayer.getDuration() + " ms");
   textPosition.setText(
     "Current Position: " + mediaPlayer.getCurrentPosition() + " ms");
  }

  private void initMediaPlayer() {
   Toast.makeText(getActivity(), 
     "initMediaPlayer()", 
     Toast.LENGTH_LONG).show();
   mediaPlayer = MediaPlayer.create(getActivity(), R.raw.vespers);
   setPlayerState(STATE_Prepared);
  }
  
  private void setPlayerState(int st){
   stateMediaPlayer = st;
   
   String stringState = getPlayerState();
   if(textState!=null){
    textState.setText(stringState);
   }else{
    Toast.makeText(getActivity(), 
      stringState, Toast.LENGTH_LONG).show();
   }
   
  }
  
  private String getPlayerState(){
   String strSt;
   switch(stateMediaPlayer){
   case STATE_Idle:
    strSt = "Idle";
    break;
   case STATE_Initialized:
    strSt = "Initialized";
    break;
   case STATE_Preparing:
    strSt = "Preparing";
    break;
   case STATE_Prepared:
    strSt = "Prepared";
    break;
   case STATE_Started:
    strSt = "Started";
    break;
   case STATE_Paused:
    strSt = "Paused";
    break;
   case STATE_Stopped:
    strSt = "Stopped";
    break;
   case STATE_PlaybackCompleted:
    strSt = "PlaybackCompleted";
    break;
   case STATE_End:
    strSt = "End";
    break;
   case STATE_Error:
    strSt = "Error";
    break;
   default:
    strSt = "unknown...";
   }
   return strSt;
  }
 }

}


Keep using the layout files in last exercise.

download filesDownload the files, without mp3 file.

Remark: It's a BIG bug here, read next post: Re-set On..Listener after mediaPlayer.release and re-create MediaPlayer.

Thursday, May 1, 2014

Implement Android MP3 Player using MediaPlayer

MediaPlayer class can be used to control playback of audio/video files and streams. It is a example to implement MP3 Player using MediaPlayer. Please note that you have to keep follow the State Diagram, otherwise IllegalStateException will be thrown.


Create a new Android Project in Eclipse, using the auto-generated code extend from ActionBarActivity.

The mp3 file is stored in /res/raw/vespers.mp3. Filename match with the following code in initMediaPlayer().

mediaPlayer = MediaPlayer.create(getActivity(), R.raw.vespers);

MainActivity.java
package com.example.androidmp3player;

import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.Fragment;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  if (savedInstanceState == null) {
   getSupportFragmentManager().beginTransaction()
     .add(R.id.container, new PlaceholderFragment()).commit();
  }
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {

  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  // Handle action bar item clicks here. The action bar will
  // automatically handle clicks on the Home/Up button, so long
  // as you specify a parent activity in AndroidManifest.xml.
  int id = item.getItemId();
  if (id == R.id.action_settings) {
   return true;
  }
  return super.onOptionsItemSelected(item);
 }

 /**
  * A placeholder fragment containing a simple view.
  */
 public static class PlaceholderFragment extends Fragment {

  Button btnStart, btnPause, btnStop, btnSeek;
  TextView textState, textDuration, textPosition;

  MediaPlayer mediaPlayer;

  private int stateMediaPlayer;
  private final int STATE_Idle = 0;
  private final int STATE_Initialized = 1;
  private final int STATE_Preparing = 2;
  private final int STATE_Prepared = 3;
  private final int STATE_Started = 4;
  private final int STATE_Paused = 5;
  private final int STATE_Stopped = 6;
  private final int STATE_PlaybackCompleted = 7;
  private final int STATE_End = 8;
  private final int STATE_Error = 9;
  
  public PlaceholderFragment() {
  }

  @Override
  public void onCreate(Bundle savedInstanceState) {
   // TODO Auto-generated method stub
   super.onCreate(savedInstanceState);
   initMediaPlayer();
  }

  @Override
  public void onDestroy() {

   Toast.makeText(getActivity(), 
    "release mediaPlayer", 
    Toast.LENGTH_LONG).show();
   mediaPlayer.release();
   mediaPlayer = null;
   setPlayerState(STATE_End);
   
   super.onDestroy();
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
   View rootView = inflater.inflate(R.layout.fragment_main, container,
     false);
   btnStart = (Button) rootView.findViewById(R.id.start);
   btnPause = (Button) rootView.findViewById(R.id.pause);
   btnStop = (Button) rootView.findViewById(R.id.stop);
   btnSeek = (Button) rootView.findViewById(R.id.seekto);
   
   btnStart.setOnClickListener(new OnClickListener() {
    
    @Override
    public void onClick(View v) {
     
     if(stateMediaPlayer==STATE_Prepared 
      || stateMediaPlayer==STATE_Started
      || stateMediaPlayer==STATE_Paused
      || stateMediaPlayer==STATE_PlaybackCompleted){
      mediaPlayer.start();
      setPlayerState(STATE_Started);
      
      displayDurationPosition();
     }else{
      Toast.makeText(getActivity(), 
       "Play at Invalid state!", 
       Toast.LENGTH_LONG).show();
     }
    }
   });
   
   btnPause.setOnClickListener(new OnClickListener() {
    
    @Override
    public void onClick(View v) {
     
     if(stateMediaPlayer==STATE_Started
      || stateMediaPlayer==STATE_Paused
      || stateMediaPlayer==STATE_PlaybackCompleted){
      mediaPlayer.pause();
      setPlayerState(STATE_Paused);
      
      displayDurationPosition();
     }else{
      Toast.makeText(getActivity(), 
       "Pause at Invalid state!", 
       Toast.LENGTH_LONG).show();
     }
    }
   });
   
   btnStop.setOnClickListener(new OnClickListener() {
    
    @Override
    public void onClick(View v) {
     
     if(stateMediaPlayer==STATE_Prepared
      || stateMediaPlayer==STATE_Started
      || stateMediaPlayer==STATE_Stopped
      || stateMediaPlayer==STATE_Paused
      || stateMediaPlayer==STATE_PlaybackCompleted){
      
      //Stop
      mediaPlayer.stop();
      setPlayerState(STATE_Stopped);
      
      //then parepare in background thread
      mediaPlayer.prepareAsync();
      setPlayerState(STATE_Preparing);
      
      displayDurationPosition();
     }else{
      Toast.makeText(getActivity(), 
       "Stop at Invalid state!", 
       Toast.LENGTH_LONG).show();
     }
     
    }
   });
   
   btnSeek.setOnClickListener(new OnClickListener(){

    @Override
    public void onClick(View v) {
     if(stateMediaPlayer==STATE_Prepared
      || stateMediaPlayer==STATE_Started
      || stateMediaPlayer==STATE_Paused
      || stateMediaPlayer==STATE_PlaybackCompleted){
      mediaPlayer.seekTo(0);
      
      displayDurationPosition();
     }else{
      Toast.makeText(getActivity(), 
       "SeekTo at Invalid state!", 
       Toast.LENGTH_LONG).show();
     }
    }});
   
   mediaPlayer.setOnPreparedListener(new OnPreparedListener(){

    @Override
    public void onPrepared(MediaPlayer mp) {
     setPlayerState(STATE_Prepared);
     displayDurationPosition();
    }});
   
   mediaPlayer.setOnCompletionListener(new OnCompletionListener(){

    @Override
    public void onCompletion(MediaPlayer mp) {
     setPlayerState(STATE_PlaybackCompleted);
     displayDurationPosition();
    }});

   textState = (TextView) rootView.findViewById(R.id.state);
   textState.setText(getPlayerState());
   
   textDuration = (TextView) rootView.findViewById(R.id.duration);
   textPosition = (TextView) rootView.findViewById(R.id.position);
   displayDurationPosition();
   
   textDuration.setOnClickListener(new OnClickListener(){

    @Override
    public void onClick(View v) {
     displayDurationPosition();
    }});
   
   textPosition.setOnClickListener(new OnClickListener(){

    @Override
    public void onClick(View v) {
     displayDurationPosition();
    }});
   
   return rootView;
  }
  
  private void displayDurationPosition(){
   textDuration.setText(
     "Duration: " + mediaPlayer.getDuration() + " ms");
   textPosition.setText(
     "Current Position: " + mediaPlayer.getCurrentPosition() + " ms");
  }

  private void initMediaPlayer() {
   Toast.makeText(getActivity(), 
     "initMediaPlayer()", 
     Toast.LENGTH_LONG).show();
   mediaPlayer = MediaPlayer.create(getActivity(), R.raw.vespers);
   setPlayerState(STATE_Prepared);
  }
  
  private void setPlayerState(int st){
   stateMediaPlayer = st;
   
   String stringState = getPlayerState();
   if(textState!=null){
    textState.setText(stringState);
   }else{
    Toast.makeText(getActivity(), 
      stringState, Toast.LENGTH_LONG).show();
   }
   
  }
  
  private String getPlayerState(){
   String strSt;
   switch(stateMediaPlayer){
   case STATE_Idle:
    strSt = "Idle";
    break;
   case STATE_Initialized:
    strSt = "Initialized";
    break;
   case STATE_Preparing:
    strSt = "Preparing";
    break;
   case STATE_Prepared:
    strSt = "Prepared";
    break;
   case STATE_Started:
    strSt = "Started";
    break;
   case STATE_Paused:
    strSt = "Paused";
    break;
   case STATE_Stopped:
    strSt = "Stopped";
    break;
   case STATE_PlaybackCompleted:
    strSt = "PlaybackCompleted";
    break;
   case STATE_End:
    strSt = "End";
    break;
   case STATE_Error:
    strSt = "Error";
    break;
   default:
    strSt = "unknown...";
   }
   return strSt;
  }
 }

}

fragment_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.androidmp3player.MainActivity$PlaceholderFragment" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <Button
        android:id="@+id/start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start" />
    <Button
        android:id="@+id/pause"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Pause" />
    <Button
        android:id="@+id/stop"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Stop" />
    <Button
        android:id="@+id/seekto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Seek To Beginning" />
    <TextView
        android:id="@+id/state"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/duration"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/position"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

Auto generated activity_main.xml.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.androidmp3player.MainActivity"
    tools:ignore="MergeRootFrame" />


download filesDownload the files (not include the mp3 file).

Next:
Implement OnErrorListener.
Re-set On..Listener after mediaPlayer.release and re-create MediaPlayer
Implement time bar for MediaPlayer, also introduce bug of MediaPlayer.seekTo()