Step 1: Create a new Module "appNatureSounds"
- min API 8
Step 2: Design UI of your player
<RelativeLayout 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"
tools:context=".MainActivity">
<TextView
android:id="@+id/uiSoundTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Song Title"/>
<LinearLayout
android:id="@+id/controlLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_alignParentBottom="true">
<ImageButton
android:id="@+id/uiFastForward"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="20"
android:layout_marginBottom="14dp"
android:onClick="forward"
android:src="@android:drawable/ic_media_ff"/>
<ImageButton
android:layout_weight="40"
android:id="@+id/uiPlayButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:onClick="play"
android:src="@android:drawable/ic_media_play"/>
<ImageButton
android:layout_weight="20"
android:id="@+id/uiPausePlay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="14dp"
android:onClick="pause"
android:src="@android:drawable/ic_media_pause"/>
<ImageButton
android:layout_weight="20"
android:id="@+id/uiRewind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginLeft="22dp"
android:onClick="rewind"
android:src="@android:drawable/ic_media_rew"/>
</LinearLayout>
<LinearLayout
android:id="@+id/progressLayout"
android:layout_above="@id/controlLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/uiCurrentTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="15"
android:text="@string/zero_time"
android:textAppearance="?android:attr/textAppearanceSmall"/>
<SeekBar
android:id="@+id/uiProgressSeekBar"
android:layout_weight="70"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/uiDuration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:layout_gravity="right"
android:layout_weight="15"
android:text="@string/zero_time"
android:textAppearance="?android:attr/textAppearanceSmall"/>
</LinearLayout>
<ImageView
android:id="@+id/uiPlayerBackground"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/progressLayout"
android:layout_below="@+id/uiSoundTitle"
android:src="@drawable/bg_rainforest"/>
</RelativeLayout>
Step: Add any language specific text
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Nature Sounds</string>
<string name="action_settings">Settings</string>
<string name="zero_time">0:0</string>
</resources>
Step: Record, or find a SHORT royalty-free MP3 you want to play
Step: create a class that will hold the TIME of the song.
package com.chicagoandroid.cit299.naturesounds.appnaturesounds;
import java.text.SimpleDateFormat;
/**
* Wrapper for time mm:ss
* Created by uki on 11/8/14.
*/
public class PlayTime {
long time;
public PlayTime(long value) {
time = value;
}
public void update(int value) {
time = (long) value;
}
public void add(int value) {
time = time + value;
}
public boolean subtract(int value) {
if (time - value > 0) {
time = time - value;
return true;
}
return false;
}
public PlayTime(int value) {
time = (long) value;
}
public int toInt() {
return (int) time;
}
public String toString() {
SimpleDateFormat ft = new SimpleDateFormat("mm:ss");
return ft.format(time);
}
}
Step: MainActivity.OnCreate()
package com.chicagoandroid.cit299.naturesounds.appnaturesounds;
import android.media.MediaPlayer;
import android.os.Handler;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.Menu;
import android.view.View;
import android.widget.*;
/** Nature Sounds app */
public class MainActivity extends ActionBarActivity {
private static int FORWARD_TIME = 5000;
private static int REWIND_TIME = 5000;
private static int DELAY_TIME = 100; // update 10 times per second
private TextView soundTitle, currentTimeLabel, durationTimeLabel;
private ImageView backgroundImage;
private MediaPlayer mediaPlayer;
private PlayTime currentTime = new PlayTime(0);
private PlayTime durationTime = new PlayTime(0);
private Handler threadHandler = new Handler();;
private SeekBar progressSeekBar;
private ImageButton playButton, pauseButton;
private boolean userChangingProgress = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
soundTitle = (TextView) findViewById(R.id.uiSoundTitle);
currentTimeLabel = (TextView) findViewById(R.id.uiCurrentTime);
durationTimeLabel = (TextView) findViewById(R.id.uiDuration);
progressSeekBar = (SeekBar) findViewById(R.id.uiProgressSeekBar);
playButton = (ImageButton) findViewById(R.id.uiPlayButton);
pauseButton = (ImageButton) findViewById(R.id.uiPausePlay);
backgroundImage = (ImageView) findViewById(R.id.uiPlayerBackground);
// set UI values to initial state before play
durationTimeLabel.setText(durationTime.toString());
currentTimeLabel.setText(currentTime.toString());
progressSeekBar.setClickable(false);
pauseButton.setEnabled(false);
// this could be loaded from the database
soundTitle.setText("Rain forest");
mediaPlayer = MediaPlayer.create(this, R.raw.sound_001);
backgroundImage.setImageResource(R.drawable.bg_rainforest);
}
Step: play method
public void play(View view) {
//play sound over and over
mediaPlayer.setLooping(true);
mediaPlayer.start();
toast("Playing sound");
durationTime.update(mediaPlayer.getDuration());
currentTime.update(mediaPlayer.getCurrentPosition());
durationTimeLabel.setText(durationTime.toString());
currentTimeLabel.setText(currentTime.toString());
progressSeekBar.setProgress(currentTime.toInt());
progressSeekBar.setMax(durationTime.toInt());
pauseButton.setEnabled(true);
playButton.setEnabled(false);
threadHandler.postDelayed(SongUpdateThread, DELAY_TIME);
progressSeekBar.setOnSeekBarChangeListener(new SeekBarListener());
}
Step: create SeekBarListener
class SeekBarListener implements OnSeekBarChangeListener {
/**
* Notification that the progress level has changed. Clients can use the fromUser parameter
* to distinguish user-initiated changes from those that occurred programmatically.
*
* @param seekBar The SeekBar whose progress has changed
* @param progress The current progress level. This will be in the range 0..max where max
* was set by {@link android.widget.ProgressBar#setMax(int)}. (The default value for max is 100.)
* @param fromUser True if the progress change was initiated by the user.
*/
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
currentTime.update(progress);
mediaPlayer.seekTo(currentTime.toInt());
}
}
/**
* Notification that the user has started a touch gesture. Clients may want to use this
* to disable advancing the seekbar.
*
* @param seekBar The SeekBar in which the touch gesture began
*/
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
userChangingProgress = true;
}
/**
* Notification that the user has finished a touch gesture. Clients may want to use this
* to re-enable advancing the seekbar.
*
* @param seekBar The SeekBar in which the touch gesture began
*/
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
userChangingProgress = false;
}
}
Step: additional control methods
public void pause(View view) {
toast("Pausing sound");
mediaPlayer.pause();
pauseButton.setEnabled(false);
playButton.setEnabled(true);
}
public void forward(View view) {
int temp = currentTime.toInt();
if ((temp + FORWARD_TIME) <= durationTime.toInt()) {
currentTime.add(FORWARD_TIME);
mediaPlayer.seekTo(currentTime.toInt());
}
else {
toast("Cannot jump forward " + FORWARD_TIME / 1000 + " seconds");
}
}
public void rewind(View view) {
if ((currentTime.toInt() - REWIND_TIME) > 0) {
currentTime.subtract(REWIND_TIME);
mediaPlayer.seekTo(currentTime.toInt());
}
else {
toast("Cannot jump backward " + REWIND_TIME / 1000 + " seconds");
}
}
Step: utility methods
void toast(String text) {
Toast toast = Toast.makeText(getApplicationContext(), text, Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER | Gravity.CENTER, 0, 0);
toast.show();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
Step: Song Update Thread
private Runnable SongUpdateThread = new Runnable() {
public void run() {
if (!userChangingProgress) {
currentTime.update(mediaPlayer.getCurrentPosition());
progressSeekBar.setProgress(currentTime.toInt());
}
currentTimeLabel.setText(currentTime.toString());
// call itself
threadHandler.postDelayed(this, DELAY_TIME);
}
};
res/dimens.xml