Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player...

29
Part of course work at Android Level 2 Download programs and view details from http://ctb.suven.net Music Player using Services The Android platform provides resources for handling media playback, which your apps can use to create an interface between the user and their music files. In this tutorial series, we will create a basic music player application for Android. The app will present a list of songs on the user device, so that the user can select songs to play. The app will also present controls for interacting with playback and will continue playing when the user moves away from the app, with a notification displayed while playback elapses. We will study this project by dividing it into 3 modules. By going through this document you’ll be able to create your own music player. Module 1: Project Setup Building the music player will involve using the ContentResolver class to retrieve tracks on the device, the MediaPlayer class to play audio and the MediaController class to control playback. We will also use a Service instance to play audio when the user is not directly interacting with the app. You should be able to complete this series if you're an intermediate Android developer, so if you've already built a few apps, then this series shouldn't be a problem for you. Here is a preview of the final app: In this module, we will create the app and query the user device for audio files using the ContentResolver and Cursor classes. In the next part, we will use an Adapter instance to present the songs in a list view, starting playback when the user taps an item from the list. In the final installment of this series, we'll use the MediaController class to give the user control over playback, implement functions to skip forward and

Transcript of Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player...

Page 1: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

Music Player using Services

The Android platform provides resources for handling media playback, which your apps can use

to create an interface between the user and their music files. In this tutorial series, we will create a basic

music player application for Android. The app will present a list of songs on the user device, so that the

user can select songs to play. The app will also present controls for interacting with playback and will

continue playing when the user moves away from the app, with a notification displayed while playback

elapses.

We will study this project by dividing it into 3 modules. By going through this document you’ll be

able to create your own music player.

Module 1:Project Setup

Building the music player will involve using the ContentResolver class to retrieve tracks on the device,

the MediaPlayer class to play audio and the MediaController class to control playback. We will also use

a Service instance to play audio when the user is not directly interacting with the app. You should be

able to complete this series if you're an intermediate Android developer, so if you've already built a few apps, then this series shouldn't be a problem for you. Here is a preview of the final app:

In this module, we will create the app and query the user device for audio files using

the ContentResolver and Cursor classes. In the next part, we will use an Adapter instance to present the songs

in a list view, starting playback when the user taps an item from the list. In the final installment of this series, we'll

use the MediaController class to give the user control over playback, implement functions to skip forward and

Page 2: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

back, and include a shuffle function. After this series, we will explore other aspects of media playback that can

enhance the app, such as handling audio focus, presenting media files in different ways, and playing streaming

media.

Page 3: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

1. Create and Configure a New Project

Step 1

Create a new Android project. If you are using Eclipse, then let the IDE (Integrated Development Environment)

create a main Activity class and layout file for you. For some of the code we use in the series, you will need a

minimum API level of 16, so you will need to take additional steps to support older versions. Once your project is

created, open the project's Manifest file. Inside the manifest element, add the following permission:

1 <uses-permissionandroid:name="android.permission.WAKE_LOCK"/>

We will use this permission to let music playback continue when the user's device becomes idle. Your

Manifest should already contain an element for your main Activity class. Add the following attributes to

the activity element to set the screenOrientation and launchMode :

1

2

3

4

5

<activity

android:name="com.example.musicplayer.MainActivity"

android:label="@string/app_name"

android:launchMode="singleTop"

android:screenOrientation="portrait">

We will stick to portrait orientation for simplicity. The launchMode will aid the process of navigating back to the

app after moving away from it. We will display a notification indicating the song currently being played, tapping

the notification will take the user back to the app. We are also going to use a Service class for music playback. Add

the following line to the project's Manifest inside the application element and after the activity element:

1 <serviceandroid:name="com.example.musicplayer.MusicService"/>

Alter the package name to suit your own and change the class name if you wish.

Step 2

Open the project's main layout file.The layout includes a ListView in which we will present the list of songs.

Page 4: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

We are going to include two menu items for toggling the shuffle function and for exiting the app. Open your

main menu file (res/menu/main.xml) and replace its contents with the following:

<menuxmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/action_shuffle" android:icon="@drawable/rand" android:orderInCategory="1" android:showAsAction="always" android:title="Shuffle"/>

<item android:id="@+id/action_end" android:icon="@drawable/end" android:orderInCategory="2" android:showAsAction="always" android:title="End"/> </menu>

If you prefer, you can store the title strings in the res/values/strings.xml file. The two items refer to drawable

files. Create your own or use these two images to start with:

We will also use an icon to display in the playback notification. Create one now or use the one below:

The code will refer to the images using the names rand, end, and play so make sure that you use the same file

names. Copy the images to your project's drawable folder(s). We will implement the actions later.

2. Query the Device for Songs

Step 1

Let's query the user's device for audio files. First, add a new class to your project, naming it Song . We will use this

class to model the data for a single audio file. Inside the class declaration, add three instance variables for the data

we want to store for each track:

Page 5: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

privatelongid;

privateString title;

privateString artist;

Next, add a constructor method in which we instantiate the instance variables:

publicSong(longsongID, String songTitle, String songArtist) {

id=songID;

title=songTitle;

artist=songArtist;

}

Finally, add get methods for the instance variables:

publiclonggetID(){returnid;}

publicString getTitle(){returntitle;}

publicString getArtist(){returnartist;}

If you plan to use more track information, then you are free to add additional instance variables to the class.

Step 2

Open the main Activity class and add the following imports:

importjava.util.ArrayList; importjava.util.Collections; importjava.util.Comparator; importandroid.net.Uri; importandroid.content.ContentResolver; importandroid.database.Cursor; importandroid.widget.ListView;

Declare the following instance variables before the onCreate method:

privateArrayList<Song> songList; privateListView songView;

We will store the songs in a list and display them in the ListView instance in the main layout. In onCreate , after

setting the content view, retrieve the ListView instance using the ID we gave it in the main layout:

Page 6: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

songView = (ListView)findViewById(R.id.song_list);

Instantiate the list as shown below:

songList = newArrayList<Song>();

Next, in the main Activity class declaration, after the existing methods, create a helper method to retrieve the

audio file information:

publicvoidgetSongList() { //retrieve song info }

Inside this method, create a ContentResolver instance, retrieve the URI for external music files, and create

a Cursor instance using the ContentResolver instance to query the music files as shown below:

ContentResolver musicResolver = getContentResolver();

Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;

Cursor musicCursor = musicResolver.query(musicUri, null, null, null, null);

Now we can iterate over the results, first checking that we have valid data:

if(musicCursor!=null&& musicCursor.moveToFirst()){ //get columns inttitleColumn = musicCursor.getColumnIndex (android.provider.MediaStore.Audio.Media.TITLE); intidColumn = musicCursor.getColumnIndex (android.provider.MediaStore.Audio.Media._ID); intartistColumn = musicCursor.getColumnIndex (android.provider.MediaStore.Audio.Media.ARTIST); //add songs to list do{ longthisId = musicCursor.getLong(idColumn); String thisTitle = musicCursor.getString(titleColumn); String thisArtist = musicCursor.getString(artistColumn); songList.add(newSong(thisId, thisTitle, thisArtist)); } while(musicCursor.moveToNext()); }

We first retrieve the column indexes for the data items that we are interested in for each song, then we use these to

create a new Song object and add it to the list, before continuing to loop through the results.

Back in onCreate , after the code we added, call this new method:

getSongList();

3. Display the Songs

Page 7: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

Step 1

Now we can display the list of songs in the user interface. In the onCreate method, after calling the helper method

we created a moment ago, let's sort the data so that the songs are presented alphabetically:

Collections.sort(songList, newComparator<Song>(){ publicintcompare(Song a, Song b){ returna.getTitle().compareTo(b.getTitle()); } });

We use the title variable in the Song class, using the get methods we added, to implement a compare method,

sorting the songs by title.

Step 2

Let's define a layout to represent each song in the list. Add a new file to your project's res/layout folder, naming

it song.xml and entering the following:

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="songPicked" android:orientation="vertical" android:padding="5dp"> <TextView android:id="@+id/song_title" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="#FFFFFF99" android:textSize="20sp" android:textStyle="bold"/> <TextView android:id="@+id/song_artist" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="#FFFFFF99" android:textSize="18sp"/> </LinearLayout>

Feel free to amend the layout to suit your preferences. Each song in the list will be represented by title and artist

text strings, so we will use the TextViews to display this data. Notice that the LinearLayout opening tag lists

an onClick attribute. We will use this method in the main Activity class to respond to user taps on the songs in

the list, playing the song represented by the list item that was tapped.

Page 8: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

Step 3

We will use an Adapter to map the songs to the list view. Add a new class to your app, naming it SongAdapter or

another name of your choice. When creating the class, give it the superclass android.widget.BaseAdapter . Eclipse

should insert the following outline:

publicclassSongAdapter extendsBaseAdapter {

@Override

publicintgetCount() {

// TODO Auto-generated method stub

return0;

}

@Override

publicObject getItem(intarg0) {

// TODO Auto-generated method stub

returnnull;

}

@Override

publiclonggetItemId(intarg0) {

// TODO Auto-generated method stub

return0;

}

@Override

publicView getView(intarg0, View arg1, ViewGroup arg2) {

// TODO Auto-generated method stub

returnnull;

}

}

You'll need to add the following imports:

importjava.util.ArrayList; importandroid.content.Context; importandroid.view.LayoutInflater; importandroid.widget.LinearLayout; importandroid.widget.TextView;

Inside the class declaration, declare the following instance variables:

privateArrayList<Song> songs; privateLayoutInflater songInf;

We'll pass the song list from the main Activity class and use the LayoutInflater to map the title and artist strings

to the TextViews in the song layout we created.

Page 9: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

After the instance variables, give the adapter a constructor method to instantiate them:

publicSongAdapter(Context c, ArrayList<Song> theSongs){ songs=theSongs; songInf=LayoutInflater.from(c); }

Alter the content of the getCount method to return the size of the list:

@Override publicintgetCount() { returnsongs.size(); }

You can leave the getItem and getItemId methods untouched. Update the implementation of

the getView method as shown below:

@Override publicView getView(intposition, View convertView, ViewGroup parent) { //map to song layout LinearLayout songLay = (LinearLayout)songInf.inflate (R.layout.song, parent, false); //get title and artist views TextView songView = (TextView)songLay.findViewById(R.id.song_title); TextView artistView = (TextView)songLay.findViewById(R.id.song_artist); //get song using position Song currSong = songs.get(position); //get title and artist strings songView.setText(currSong.getTitle()); artistView.setText(currSong.getArtist()); //set position as tag songLay.setTag(position); returnsongLay; }

We set the title and artist text by retrieving the correct Song instance from the list using the position index,

mapping these strings to the views we added to the song layout file. We also set the position as the view tag, which will let us play the correct song when the user clicks an item in the list. Remember that the song.xml layout file

included an onClick attribute. We will use the method listed there to retrieve the tag in the Activity .

Step 3

Back in the main Activity class, in the onCreate method after sorting the list, create a new instance of

the Adapter class and set it on the ListView :

SongAdapter songAdt = newSongAdapter(this, songList); songView.setAdapter(songAdt);

Page 10: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

When you run the app, it should present the list of songs on the device, clicking them will cause the app to throw an

exception at the moment, but we will implement the click handler in the next module.

Module 2:Song Playback

In the first module, we created the app and prepared the user interface for playback. We presented the list of songs on the user device and specified a method to execute when the user makes a selection. In this module, we

will implement a Service class to execute music playback continuously, even when the user is not directly

interacting with the application.

We will need the app to bind to the music playing Service in order to interact with playback, so you will

learn some of the basic aspects of the Service life cycle in this module if you haven't explored them before.

In the final module, we'll add user control over the playback and we'll also make sure the app will continue to function in various application states. Later, we will follow the series up with additional enhancements that you may wish to add, such as audio focus control, video and streaming media playback, and alternate ways of presenting the media files.

1. Create a Service

Step 1

Add a new class to your app, naming it MusicService or another name of your choice. Make sure it matches the

name you listed in the Manifest. When creating the class in Eclipse, choose android.app.Service as its superclass.

Eclipse should enter an outline:

publicclassMusicService extendsService { @Override publicIBinder onBind(Intent arg0) { // TODO Auto-generated method stub returnnull; } }

Extend the opening line of the class declaration to implement some interfaces we will use for music playback:

publicclassMusicService extendsService implements MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener {

Page 11: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

Eclipse will display an error over the class name. Hover over the error and chooseAdd unimplemented methods.

We will add code to the methods in a few moments. The interfaces we are implementing will aid the process of

interacting with the MediaPlayer class.

Your class will also need the following additional imports:

importjava.util.ArrayList; importandroid.content.ContentUris; importandroid.media.AudioManager; importandroid.media.MediaPlayer; importandroid.net.Uri; importandroid.os.Binder; importandroid.os.PowerManager; importandroid.util.Log;

Step 2

Add the following instance variables to the new Service class:

//media player privateMediaPlayer player; //song list privateArrayList<Song> songs; //current position privateintsongPosn;

We will pass the list of songs into the Service class, playing from it using the MediaPlayer class and keeping track

of the position of the current song using the songPosn instance variable. Now, implement the onCreate method

for the Service :

publicvoidonCreate()

{ //create the service }

Inside onCreate , call the superclass method, instantiating the position and MediaPlayer instance

variables:

//create the service super.onCreate(); //initialize position songPosn=0; //create player player = newMediaPlayer();

Page 12: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

Next, let's add a method to initialize the MediaPlayer class, after the onCreate method:

publicvoidinitMusicPlayer()

{ //set player properties }

Inside this method, we configure the music player by setting some of its properties as shown below:

player.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK); player.setAudioStreamType(AudioManager.STREAM_MUSIC);

The wake lock will let playback continue when the device becomes idle and we set the stream type to music. Set the

class as listener for (1) when the MediaPlayer instance is prepared, (2) when a song has completed playback, and

when (3) an error is thrown:

player.setOnPreparedListener(this); player.setOnCompletionListener(this); player.setOnErrorListener(this);

Notice that these correspond to the interfaces we implemented. We will be adding code to

the onPrepared , onCompletion , and onError methods to respond to these events. Back in onCreate ,

invoke initMusicPlayer :

initMusicPlayer();

Step 3

It's time to add a method to the Service class to pass the list of songs from the Activity :

publicvoidsetList(ArrayList<Song> theSongs)

{ songs=theSongs; }

We will call this method later in the tutorial. This will form part of the interaction between

the Activity and Service classes, for which we also need a Binder instance. Add the following snippet to

the Service class after the setList method:

publicclassMusicBinder extendsBinder { MusicService getService() { returnMusicService.this; } }

Page 13: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

We will also access this from the Activity class.

2. Start the Service

Step 1

Back in your app's main Activity class, you will need to add the following additional imports:

importandroid.os.IBinder; importandroid.content.ComponentName; importandroid.content.Context; importandroid.content.Intent; importandroid.content.ServiceConnection; importandroid.view.MenuItem; importandroid.view.View;

And you'll also need to declare three new instance variables:

privateMusicService musicSrv; privateIntent playIntent; privatebooleanmusicBound=false;

We are going to play the music in the Service class, but control it from the Activity class, where the application's

user interface operates. To accomplish this, we will have to bind to the Service class. The above instance variables

represent the Service class and Intent , as well as a flag to keep track of whether the Activity class is bound to

the Service class or not. Add the following to your Activity class, after the onCreate method:

//connect to the service privateServiceConnection musicConnection = newServiceConnection(){ @Override publicvoidonServiceConnected(ComponentName name, IBinder service) { MusicBinder binder = (MusicBinder)service; //get service musicSrv = binder.getService(); //pass list musicSrv.setList(songList); musicBound = true; } @Override

Page 14: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

publicvoidonServiceDisconnected(ComponentName name) { musicBound = false; } };

The callback methods will inform the class when the Activity instance has successfully connected to

the Service instance. When that happens, we get a reference to the Service instance so that the Activity can

interact with it. It starts by calling the method to pass the song list. We set the boolean flag to keep track of the

binding status. You will need to import the Binder class we added to the Service class at the top of

your Activity class:

importcom.example.musicplayer.MusicService.MusicBinder;

Don't forget to alter the package and class names to suit your own if necessary.

Step 2

We will want to start the Service instance when the Activity instance starts, so override the onStart method:

@Override protectedvoidonStart() { super.onStart(); if(playIntent==null){ playIntent = newIntent(this, MusicService.class); bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE); startService(playIntent); } }

When the Activity instance starts, we create the Intent object if it doesn't exist yet, bind to it, and start it. Alter

the code if you chose a different name for the Service class. Notice that we use the connection object we created so

that when the connection to the bound Service instance is made, we pass the song list. We will also be able to

interact with the Service instance in order to control playback later.

Return to your Service class to complete this binding process. Add an instance variable representing the

inner Binder class we added:

privatefinalIBinder musicBind = newMusicBinder();

Now amend the onBind method to return this object:

@Override

Page 15: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

publicIBinder onBind(Intent intent) { returnmusicBind; }

Add the onUnbind method to release resources when the Service instance is unbound:

@Override publicbooleanonUnbind(Intent intent){ player.stop(); player.release(); returnfalse; }

This will execute when the user exits the app, at which point we will stop the service.

3. Begin Playback

Step 1

Let's now set the app up to play a track. In your Service class, add the following method:

publicvoidplaySong()

{ //play a song }

Inside the method, start by resetting the MediaPlayer since we will also use this code when the user is playing

subsequent songs:

player.reset();

Next, get the song from the list, extract the ID for it using its Song object, and model this as a URI:

//get song Song playSong = songs.get(songPosn); //get id longcurrSong = playSong.getID(); //set uri Uri trackUri = ContentUris.withAppendedId( android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, currSong);

We can now try setting this URI as the data source for the MediaPlayer instance, but an exception may be thrown

if an error pops up so we use a try/catch block:

Page 16: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

try{ player.setDataSource(getApplicationContext(), trackUri); } catch(Exception e){ Log.e("MUSIC SERVICE", "Error setting data source", e); }

After the catch block, complete the playSong method by calling the asynchronous method of

the MediaPlayer to prepare it:

player.prepareAsync();

Step 2

When the MediaPlayer is prepared, the onPrepared method will be executed. Eclipse should have inserted it in

your Service class. Inside this method, start the playback:

@Override publicvoidonPrepared(MediaPlayer mp) { //start playback mp.start(); }

In order for the user to select songs, we also need a method in the Service class to set the current song. Add it

now:

publicvoidsetSong(intsongIndex)

{ songPosn=songIndex; }

We will call this when the user picks a song from the list.

Step 3

Remember that we added an onClick attribute to the layout for each item in the song list. Add that method to the

main Activity class:

publicvoidsongPicked(View view)

{ musicSrv.setSong(Integer.parseInt(view.getTag().toString())); musicSrv.playSong(); }

Page 17: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

We set the song position as the tag for each item in the list view when we defined the Adapter class. We retrieve it

here and pass it to the Service instance before calling the method to start the playback.

Before you run your app, implement the end button we added to the main menu. In your main Activity class, add

the method to respond to menu item selection:

@Override publicbooleanonOptionsItemSelected(MenuItem item) { //menu item selected }

Inside the method, add a switch statement for the actions:

switch(item.getItemId()) { caseR.id.action_shuffle: //shuffle break; caseR.id.action_end: stopService(playIntent); musicSrv=null; System.exit(0); break; } returnsuper.onOptionsItemSelected(item);

We will implement the shuffle function in the next module. For the end button, we stop the Service instance and

exit the app. Pressing the back button will not exit the app, since we will assume that the user wants playback to

continue unless they select the end button. Use the same process if the the app is destroyed, overriding the

activity's onDestroy method:

@Override protectedvoidonDestroy() { stopService(playIntent); musicSrv=null; super.onDestroy(); }

When you run the app at this point, you will be able to play songs by selecting them from the list and you can also

exit the app using the end button.

Page 18: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

Module 2:User Controls

The music player control functionality will be implemented using the MediaController class, in which

a SeekBar instance displays the progress of playback as well as letting the user skip to particular locations in a

track. We will use the Notification and PendingIntent classes to display the title of the currently playing track

and let the user navigate back to the app.

After this series we will also explore related functionality you may wish to use to enhance the music player app.

This will include video playback, streaming media, managing audio focus, and presenting media data in different

ways.

1. Create a Controller

Step 1

Open your main Activity class and add the following import statement:

importandroid.widget.MediaController.MediaPlayerControl;

Extend the opening line of the class declaration as follows, so that we can use the Activity class to provide

playback control:

publicclassMainActivity extendsActivity implementsMediaPlayerControl {

Hover over the class name and select Add unimplemented methods. Eclipse will add various methods for

playback control, which we will tailor as we go along.

Step 2

The MediaController class presents a standard widget with play/pause, rewind, fast-forward, and skip

(previous/next) buttons in it. The widget also contains a seek bar, which updates as the song plays and contains

text indicating the duration of the song and the player's current position. So that we can configure the details of the

control, we will implement a class to extend it. Add a new class to your project, naming it MusicController. In

Eclipse, choose android.widget.MediaController as the superclass when creating it.

Give the class the following content:

Page 19: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

publicclassMusicController extendsMediaController { publicMusicController(Context c){ super(c); } publicvoidhide(){} }

You can tailor the MediaController class in various ways. All we want to do is stop it from automatically hiding

after three seconds by overriding the hide method.

Tip: You may need to tweak the theme your app uses in order to ensure that the media controller text is clearly

visible.

Step 3

Back in your main Activity class, add a new instance variable:

privateMusicController controller;

We will be setting the controller up more than once in the life cycle of the app, so let's do it in a helper method. Add

the following code snippet to your Activity class:

privatevoidsetController(){ //set the controller up }

Inside the method, instantiate the controller:

controller = newMusicController(this);

You can configure various aspects of the MediaController instance. For example, we will need to determine what

will happen when the user presses the previous/next buttons. After instantiating the controller set these click

listeners:

controller.setPrevNextListeners(newView.OnClickListener() { @Override publicvoidonClick(View v) { playNext(); } }, newView.OnClickListener() { @Override publicvoidonClick(View v) { playPrev();

Page 20: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

} });

We will implement playNext and playPrev a bit later, so just ignore the errors for now. Still inside

the setController method, set the controller to work on media playback in the app, with its anchor view referring

to the list we included in the layout:

controller.setMediaPlayer(this); controller.setAnchorView(findViewById(R.id.song_list)); controller.setEnabled(true);

Back in onCreate , call the method:setController();

We will also call it elsewhere in the class later.

2. Implement Playback Control

Step 1

Remember that the media playback is happening in the Service class, but that the user interface comes from

the Activity class. In the previous tutorial, we bound the Activity instance to the Service instance, so that we

could control playback from the user interface. The methods in our Activity class that we added to implement

the MediaPlayerControl interface will be called when the user attempts to control playback. We will need

the Service class to act on this control, so open your Service class now to add a few more methods to it:

publicintgetPosn(){ returnplayer.getCurrentPosition(); } publicintgetDur(){ returnplayer.getDuration(); } publicbooleanisPng(){ returnplayer.isPlaying(); } publicvoidpausePlayer(){ player.pause(); } publicvoidseek(intposn){

Page 21: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

player.seekTo(posn); } publicvoidgo(){ player.start(); }

These methods all apply to standard playback control functions that the user will expect.

Page 22: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

Step 2

Now let's add methods to the Service class for skipping to the next and previous tracks. Start with the previous

function:

publicvoidplayPrev(){ songPosn--; if(songPosn&lt;0) songPosn=songs.size()-1; playSong(); }

We decrement the song index variable, check that we haven't gone outside the range of the list, and call

the playSong method we added. Now add the method to skip to the next track:

//skip to next publicvoidplayNext(){ songPosn++; if(songPosn&gt;=songs.size()) songPosn=0; playSong(); }

This is analogous to the method for playing the previous track at the moment, but we will amend this method later

to implement the shuffle functionality.

Step 3

Now switch back to your Activity class so that we can make use of these methods. First add the methods we

called when we set the controller up:

//play next privatevoidplayNext(){ musicSrv.playNext(); controller.show(0); } //play previous privatevoidplayPrev(){ musicSrv.playPrev(); controller.show(0); }

We call the methods we added to the Service class. We will be adding more code to these later to take care of

particular situations. Now let's turn to the MediaPlayerControl interface methods, which will be called by the

system during playback and when the user interacts with the controls. These methods should already be in

your Activity class, so we will just be altering their implementation.

Page 23: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

Start with the canPause method, setting it to true:

@Override publicbooleancanPause() { returntrue; }

Now do the same for the canSeekBackward and canSeekForward methods:

@Override publicbooleancanSeekBackward() { returntrue; } @Override publicbooleancanSeekForward() { returntrue; }

You can leave the getAudioSessionId and getBufferPercentage methods as they are. Amend

the getCurrentPosition method as follows:

@Override publicintgetCurrentPosition() { if(musicSrv!=null&amp;&amp; musicBound &amp;&amp; musicSrv.isPng()) returnmusicSrv.getPosn(); elsereturn0; }

The conditional tests are to avoid various exceptions that may occur when using

the MediaPlayer and MediaController classes. If you attempt to enhance the app in any way, you will likely find

that you need to take such steps since the media playback classes throw lots of exceptions. Notice that we call

the getPosn method of the Service class.

Amend the getDuration method similarly:

@Override publicintgetDuration() { if(musicSrv!=null&amp;&amp; musicBound &amp;&amp; musicSrv.isPng()) returnmusicSrv.getDur(); elsereturn0; }

Alter the isPlaying method by invoking the isPng method of our Service class:

@Override publicbooleanisPlaying() { if(musicSrv!=null&amp;&amp; musicBound) returnmusicSrv.isPng();

Page 24: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

returnfalse; }

Do the same for the pause , seekTo and start methods:

@Override publicvoidpause() { musicSrv.pausePlayer(); } @Override publicvoidseekTo(intpos) { musicSrv.seek(pos); } @Override publicvoidstart() { musicSrv.go(); }

3. Handle Navigation Back Into the App

Step 1

Remember that we are going to continue playback even when the user navigates away from the app. In order to

facilitate this, we will display a notification showing the title of the track being played. Clicking the notification will

take the user back into the app. Switch back to your Service class and add the following additional imports:

importjava.util.Random; importandroid.app.Notification; importandroid.app.PendingIntent;

Now move to the onPrepared method, in which we currently simply start the playback. After the call

to player.start() , add the following code:

Intent notIntent = newIntent(this, MainActivity.class); notIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); PendingIntent pendInt = PendingIntent.getActivity(this, 0, notIntent, PendingIntent.FLAG_UPDATE_CURRENT); Notification.Builder builder = newNotification.Builder(this);

Page 25: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

builder.setContentIntent(pendInt) .setSmallIcon(R.drawable.play) .setTicker(songTitle) .setOngoing(true) .setContentTitle(&quot;Playing&quot;) .setContentText(songTitle); Notification not = builder.build(); startForeground(NOTIFY_ID, not);

We will add the missing variables next. The PendingIntent class will take the user back to the main Activity class

when they select the notification. Add variables for the song title and notification ID at the top of the class:

privateString songTitle=&quot;&quot;; privatestaticfinalintNOTIFY_ID=1;

Now we need to set the song title, in the playSong method, after the line in which we retrieve the song from the

list ( Song playSong = songs.get(songPosn); ):

songTitle=playSong.getTitle();

Since we have called setForeground on the notification, we need to make sure we stop it when

the Service instance is destroyed. Override the following method:

@Override publicvoidonDestroy() { stopForeground(true); }

4. Shuffle Playback

Step 1

Remember that we added a shuffle button, so let's implement that now. First add new instance variables to

the Service class:

privatebooleanshuffle=false; privateRandom rand;

Instantiate the random number generator in onCreate :

Page 26: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

rand=newRandom();

Now add a method to set the shuffle flag:

publicvoidsetShuffle(){ if(shuffle) shuffle=false; elseshuffle=true; }

We will simply toggle the shuffle setting on and off. We will check this flag when the user either skips to the next

track or when a track ends and the next one begins. Amend the playNext method as follows:

publicvoidplayNext(){ if(shuffle){ intnewSong = songPosn; while(newSong==songPosn){ newSong=rand.nextInt(songs.size()); } songPosn=newSong; } else{ songPosn++; if(songPosn&gt;=songs.size()) songPosn=0; } playSong(); }

If the shuffle flag is on, we choose a new song from the list at random, making sure we don't repeat the last song

played. You could enhance this functionality by using a queue of songs and preventing any song from being

repeated until all songs have been played.

Step 2

Now we can let the user select the shuffle function. Back in your main Activity class in

the onOptionsItemSelected method, amend the section for the shuffle action to call the new method we added to

the Service class:

caseR.id.action_shuffle: musicSrv.setShuffle(); break;

Now the user will be able to use the menu item to toggle the shuffling functionality.

5. Tidy Up

Page 27: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

Step 1

We are almost done, but still need to add a few bits of processing to take care of certain changes, such as

the user leaving the app or pausing playback. In yourActivity class, add a couple more instance variables:

privatebooleanpaused=false, playbackPaused=false;

We will use these to cope with the user returning to the app after leaving it and interacting with the controls when

playback itself is paused. Override onPause to set one of these flags:

@Override

protectedvoidonPause(){

super.onPause();

paused=true;

}

Now override onResume :

@Override protectedvoidonResume(){ super.onResume(); if(paused){ setController(); paused=false; } }

This will ensure that the controller displays when the user returns to the app. Override onStop to hide it:

@Override protectedvoidonStop() { controller.hide(); super.onStop(); }

Step 2

If the user interacts with the controls while playback is paused, the MediaPlayer object may behave unpredictably.

To cope with this, we will set and use the playbackPaused flag. First amend

the playNext and playPrev methods:

privatevoidplayNext(){

Page 28: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

musicSrv.playNext(); if(playbackPaused){ setController(); playbackPaused=false; } controller.show(0); } privatevoidplayPrev(){ musicSrv.playPrev(); if(playbackPaused){ setController(); playbackPaused=false; } controller.show(0); }

We reset the controller and update the playbackPaused flag when playback has been paused. Now make similar

changes to the playSong method:

publicvoidsongPicked(View view){ musicSrv.setSong(Integer.parseInt(view.getTag().toString())); musicSrv.playSong(); if(playbackPaused){ setController(); playbackPaused=false; } controller.show(0); }

Now set playbackPaused to true in the pause method:

@Override publicvoidpause() { playbackPaused=true; musicSrv.pausePlayer(); }

As you work with the MediaPlayer and MediaController classes, you will find that this type of processing is a

necessary requirement to avoid errors. For example, you will sometimes find that the controller's seek bar does

not update until the user interacts with it. These resources behave differently on different API levels, so thorough

testing and tweaking is essential if you plan on releasing your app to the public. The app we are creating in this

project is really only a foundation.

Step 3

Let's take some final steps to make the app behave consistently. Back in the Service class, amend

the onError method:

@Override

Page 29: Music Player using Services - ctb.suvenconsultants.com Player using Services.pdfmusic player application for Android. The app will present a list of songs on the user device, so that

Part of course work at Android Level 2

Download programs and view details from http://ctb.suven.net

publicbooleanonError(MediaPlayer mp, intwhat, intextra) { mp.reset(); returnfalse; }

We simply reset the player, but you may of course wish to enhance this approach.

The onCompletion method will fire when a track ends, including cases where the user has chosen a new track or

skipped to the next/previous tracks as well as when the track reaches the end of its playback. In the latter case, we

want to continue playback by playing the next track. To do this we need to check the state of playback. Amend

your onCompletion method:

@Override publicvoidonCompletion(MediaPlayer mp) { if(player.getCurrentPosition()&gt;0){ mp.reset(); playNext(); } }

We call the playNext method if the current track has reached its end.

That is the basic app complete! However, you may well need to carry out additional enhancements to make it

function reliably across user devices and API levels. The controls should appear whenever you interact with the

app.

Time Period: 5 days, 8 hrs per day, total of 40 hrs.