Sunday, February 26, 2012

MediaPlayer Application (week no 8)

We have added a simple User Interface for the MediaPlayer application.
The UI includes a TextView for the name of the application, another TextView for the name of the audio file and 4 buttons for opening, playing, pausing and stopping the playback of the file.
We have also included a seek bar in the UI, seek bar which should show the progress of the playback and also let the user seek trough the audio file.
Below there is a screenshot of the application ran on an AVD (target Android 2.2 SDK version 8)


Nothing too fancy until this point. ;)
In order to be able to use the elements we have added in the UI in our java classes we have had to add IDs to all elements in the interface and also add the onClickListener methods for the buttons.
For the Play, Pause and Stop button the story is pretty much the same, when pressing the Play button the Media element should start the playback (in our case it is only effective to press the Play button after we have pressed the Pause button to pause the playback), the Pause button to temporarily pause the playback and the Stop button to stop playing the file. The only exception here is that when we stop the playback of the file we should also release the resources the Media Element was using to play the file.

public void onPlay(View view) {
if (mMediaPlayer != null) {
mMediaPlayer.start();
}
}

public void onPause(View view) {
if (mMediaPlayer != null) {
mMediaPlayer.pause();
}
}

public void onStop(View view) {

mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;

}

When we start the application the first thing we must do in order to play a file is to select the file we want to play. In our case unfortunately we could not figure out how exactly to fetch the files from the internal memory and the SD card of the AVD, even if we have tried doing so with Uris and also by pushing files to the mnt/sdcard folder of the AVD. Instead we play a file located in the res/raw folder of the application, folder which we have created and which is supposed to include raw media elements, but for the moment we have added encoded files for a better quality of the playback.
In order to play a MediaPlayer element we must first set the DataSource for it by calling one of the setDataSource methods presented on the element. Calling this method can result in the main thread trowing illegal state, illegal argument and IO exceptions.
After we set the data source Android requires that we prepare the MediaPlayer element for playback by calling the prepare() methods.
All that is left to do at this moment is to start the playback of the file by calling the MediaPlayer.start() method.


public void onOpen(View view) {

if (mMediaPlayer == null) {
mMediaPlayer = new MediaPlayer();
}

AssetFileDescriptor afd = getApplicationContext().getResources()
.openRawResourceFd(R.raw.fever);
seekBar = (SeekBar) findViewById(R.id.seekBar);
mediaTitle = (TextView) findViewById(R.id.titleTextView);

try {
mMediaPlayer.setDataSource(afd.getFileDescriptor(),
afd.getStartOffset(), afd.getLength());
afd.close();
mMediaPlayer.prepare();
mediaTitle.setText("Title: fever");
seekBar.setMax(mMediaPlayer.getDuration());
seekBar.setProgress(0);
progressThread.start();
mMediaPlayer.start();

} catch (IllegalArgumentException e) {
...
} catch (IllegalStateException e) {
...
} catch (IOException e) {
...
}

}

As it can be seen in the code above there are also some settings we make for the seek bar we have placed in the UI.
We set the maximum length of the bar to the length of the MediaPlayer element and we also set the shown progress to 0.
Just before we start the playback of the file we also start a Thread (the progressThread) which updates the seek bar. Here is the definition of this thread:


Thread progressThread = new Thread() {
@Override
public void run() {
int currentPosition = 0;
int total = mMediaPlayer.getDuration();
seekBar.setIndeterminate(false);

while (mMediaPlayer != null && currentPosition < total) {
try {
currentPosition = mMediaPlayer.getCurrentPosition();
Thread.sleep(1000);
} catch (InterruptedException e) {
return;
} catch (Exception e) {
return;
}
seekBar.setProgress(currentPosition);
}
}

};



At this point if the user opens a file the seek bar will be updated automatically every 1 second with the progress in the playback of the file. But all this could have been done using just a progress bar. Instead we also want the user to be able to seek to various parts of the file. To do so our activity class has to implement the SeekBar.OnSeekBarChangeListener. By acting in this manner we also get to implement the methods on the OnSeekBarChangeListener interface, from which the most noticeable is the onProgressChanged method:


public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {

if (fromUser && mMediaPlayer.isPlaying()) {
              mMediaPlayer.seekTo(progress);
}
}

The boolean fromUser parameter helps us identify if the event has occurred due to a action from the user or due to the progress thread we have defined earlier.


Unfortunately this last step is not working for our application due to unknown reasons. Not even some hours spent on Google and on the Android documentation could not help us in this manner since we have fallowed all the steps required and still no results were produced.

The full project can be downloaded from the link below:

MediaPlayer Application Project


We can not say that developing this simple application was hard or easy, but what we can say is that is was time consuming work, most of it being spent on researching various methods which could have helped us with the seek bar and also with the use of internal / sdcard memory of the device.


Monday, February 13, 2012

Mobile Application Development MOB I1 (week no 7)

Mobile Applications Development - MOB I1

First Week

Group members:
Gabriel - Florentin Hirjoi, student no: 126645
Claudiu - Lucian Manea, student no: 130935
Georgiana Barbu, student no: 127811

Teacher e-mail address:
fx@cs.au.dk