In this tutorial we will learn how to make a simple music player with play, pause, next, previous controls with controlling music from notification and Lock-screen. Audio files present in SD card will be played.
Project Hierarchy |
public static
ArrayList<MediaItem> listOfSongs(Context context){
Uri
uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor
c = context.getContentResolver().query(uri, null,
MediaStore.Audio.Media.IS_MUSIC + " != 0", null, null);
ArrayList<MediaItem>
listOfSongs = new ArrayList<MediaItem>();
c.moveToFirst();
while(c.moveToNext()){
MediaItem
songData = new MediaItem();
String
title = c.getString(c.getColumnIndex(MediaStore.Audio.Media.TITLE));
String
artist = c.getString(c.getColumnIndex(MediaStore.Audio.Media.ARTIST));
String
album = c.getString(c.getColumnIndex(MediaStore.Audio.Media.ALBUM));
long duration =
c.getLong(c.getColumnIndex(MediaStore.Audio.Media.DURATION));
String
data = c.getString(c.getColumnIndex(MediaStore.Audio.Media.DATA));
long albumId =
c.getLong(c.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
String
composer = c.getString(c.getColumnIndex(MediaStore.Audio.Media.COMPOSER));
songData.setTitle(title);
songData.setAlbum(album);
songData.setArtist(artist);
songData.setDuration(duration);
songData.setPath(data);
songData.setAlbumId(albumId);
songData.setComposer(composer);
listOfSongs.add(songData);
}
c.close();
Log.d("SIZE", "SIZE:
" + listOfSongs.size());
return listOfSongs;
}
|
2) Get AlbumImage-
public static Bitmap
getAlbumart(Context context,Long album_id){
Bitmap
bm = null;
BitmapFactory.Options
options = new BitmapFactory.Options();
try{
final Uri sArtworkUri
= Uri.parse("content://media/external/audio/albumart");
Uri uri = ContentUris.withAppendedId(sArtworkUri,
album_id);
ParcelFileDescriptor pfd =
context.getContentResolver().openFileDescriptor(uri, "r");
if (pfd != null){
FileDescriptor fd =
pfd.getFileDescriptor();
bm = BitmapFactory.decodeFileDescriptor(fd,
null, options);
pfd = null;
fd = null;
}
} catch(Error ee){}
catch (Exception e)
{}
return bm;
}
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
3) Media Player Controls-
mp.reset();
mp.setDataSource(songPath);
mp.prepare();
mp.start();
mp.getCurrentPosition();
mp.getDuration();
mp.pause();
mp.stop();
|
4) For playing song after killing the application we have to start a notification in foreground from service otherwise the system stops song. And we will require the custom notification so that we can control our music player from notification. See here how to make custom notification build and how we receive when it broadcast. Custom big notification in supported from API 16+(JELLY BEAN).
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />int NOTIFICATION_ID = 1111;
public static final String NOTIFY_PREVIOUS = "com.tutorialsface.audioplayer.previous";
public static final String NOTIFY_DELETE = "com.tutorialsface.audioplayer.delete";
public static final String NOTIFY_PAUSE = "com.tutorialsface.audioplayer.pause";
public static final String NOTIFY_PLAY = "com.tutorialsface.audioplayer.play";
public static final String NOTIFY_NEXT = "com.tutorialsface.audioplayer.next";
boolean currentVersionSupportBigNotification = currentVersionSupportBigNotification();
public static boolean
currentVersionSupportBigNotification() {
int sdkVersion =
android.os.Build.VERSION.SDK_INT;
if(sdkVersion
>= android.os.Build.VERSION_CODES.JELLY_BEAN){
return true;
}
return false;
}
@SuppressLint("NewApi")
private void notification() {
String
songName = PlayerConstants.SONGS_LIST.get(PlayerConstants.SONG_NUMBER).getTitle();
String
albumName = PlayerConstants.SONGS_LIST.get(PlayerConstants.SONG_NUMBER).getAlbum();
RemoteViews
simpleContentView = new RemoteViews(getApplicationContext().getPackageName(),R.layout.custom_notification);
RemoteViews
expandedView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.big_notification);
Notification
notification = new NotificationCompat.Builder(getApplicationContext())
.setSmallIcon(R.drawable.ic_music)
.setContentTitle(songName).build();
setListeners(simpleContentView);
setListeners(expandedView);
notification.contentView =
simpleContentView;
if(currentVersionSupportBigNotification){
notification.bigContentView = expandedView;
}
try{
long albumId =
PlayerConstants.SONGS_LIST.get(PlayerConstants.SONG_NUMBER).getAlbumId();
Bitmap
albumArt = UtilFunctions.getAlbumart(getApplicationContext(), albumId);
if(albumArt != null){
notification.contentView.setImageViewBitmap(R.id.imageViewAlbumArt, albumArt);
if(currentVersionSupportBigNotification){
notification.bigContentView.setImageViewBitmap(R.id.imageViewAlbumArt, albumArt);
}
}else{
notification.contentView.setImageViewResource(R.id.imageViewAlbumArt, R.drawable.default_album_art);
if(currentVersionSupportBigNotification){
notification.bigContentView.setImageViewResource(R.id.imageViewAlbumArt, R.drawable.default_album_art);
}
}
}catch(Exception e){
e.printStackTrace();
}
if(PlayerConstants.SONG_PAUSED){
notification.contentView.setViewVisibility(R.id.btnPause, View.GONE);
notification.contentView.setViewVisibility(R.id.btnPlay, View.VISIBLE);
if(currentVersionSupportBigNotification){
notification.bigContentView.setViewVisibility(R.id.btnPause, View.GONE);
notification.bigContentView.setViewVisibility(R.id.btnPlay, View.VISIBLE);
}
}else{
notification.contentView.setViewVisibility(R.id.btnPause, View.VISIBLE);
notification.contentView.setViewVisibility(R.id.btnPlay, View.GONE);
if(currentVersionSupportBigNotification){
notification.bigContentView.setViewVisibility(R.id.btnPause, View.VISIBLE);
notification.bigContentView.setViewVisibility(R.id.btnPlay, View.GONE);
}
}
notification.contentView.setTextViewText(R.id.textSongName, songName);
notification.contentView.setTextViewText(R.id.textAlbumName, albumName);
if(currentVersionSupportBigNotification){
notification.bigContentView.setTextViewText(R.id.textSongName, songName);
notification.bigContentView.setTextViewText(R.id.textAlbumName, albumName);
}
notification.flags |=
Notification.FLAG_ONGOING_EVENT;
startForeground(NOTIFICATION_ID, notification);
}
public void
setListeners(RemoteViews view) {
Intent
previous = new Intent(NOTIFY_PREVIOUS);
Intent
delete = new Intent(NOTIFY_DELETE);
Intent
pause = new Intent(NOTIFY_PAUSE);
Intent
next = new Intent(NOTIFY_NEXT);
Intent
play = new Intent(NOTIFY_PLAY);
PendingIntent
pPrevious = PendingIntent.getBroadcast(getApplicationContext(), 0,
previous, PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.btnPrevious, pPrevious);
PendingIntent
pDelete = PendingIntent.getBroadcast(getApplicationContext(), 0, delete,
PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.btnDelete, pDelete);
PendingIntent
pPause = PendingIntent.getBroadcast(getApplicationContext(), 0, pause,
PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.btnPause, pPause);
PendingIntent
pNext = PendingIntent.getBroadcast(getApplicationContext(), 0, next,
PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.btnNext, pNext);
PendingIntent
pPlay = PendingIntent.getBroadcast(getApplicationContext(), 0, play,
PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.btnPlay, pPlay);
}
|
5) Lock screen controls are available from API 14+(ICS) and we will require
i) AudioManager
ii) ComponentName
iii) RemoteControlClient
iv) Set IntentFilter action of your broadcastReceiver in Manifest-
<action android:name="android.intent.action.MEDIA_BUTTON"
/>
i)implements
AudioManager.OnAudioFocusChangeListenerFirstly register RemoteControlClient-
private ComponentName remoteComponentName;
private
RemoteControlClient remoteControlClient;
AudioManager audioManager;
Bitmap mDummyAlbumArt;
@SuppressLint("NewApi")
private void
RegisterRemoteClient(){
remoteComponentName = new
ComponentName(getApplicationContext(), new
NotificationBroadcast().ComponentName());
try {
if(remoteControlClient == null) {
audioManager.registerMediaButtonEventReceiver(remoteComponentName);
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
mediaButtonIntent.setComponent(remoteComponentName);
PendingIntent mediaPendingIntent =
PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0);
remoteControlClient = new
RemoteControlClient(mediaPendingIntent);
audioManager.registerRemoteControlClient(remoteControlClient);
}
remoteControlClient.setTransportControlFlags(
RemoteControlClient.FLAG_KEY_MEDIA_PLAY |
RemoteControlClient.FLAG_KEY_MEDIA_PAUSE |
RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE |
RemoteControlClient.FLAG_KEY_MEDIA_STOP |
RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS |
RemoteControlClient.FLAG_KEY_MEDIA_NEXT);
}catch(Exception ex) {
}
}
|
6) For updating Lock-Screen UI we will call-
@SuppressLint("NewApi")
private void
UpdateMetadata(MediaItem data){
if (remoteControlClient == null)
return;
MetadataEditor
metadataEditor = remoteControlClient.editMetadata(true);
metadataEditor.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM,
data.getAlbum());
metadataEditor.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST,
data.getArtist());
metadataEditor.putString(MediaMetadataRetriever.METADATA_KEY_TITLE,
data.getTitle());
mDummyAlbumArt =
UtilFunctions.getAlbumart(getApplicationContext(), data.getAlbumId());
if(mDummyAlbumArt == null){
mDummyAlbumArt =
BitmapFactory.decodeResource(getResources(), R.drawable.default_album_art);
}
metadataEditor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, mDummyAlbumArt);
metadataEditor.apply();
audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
}
|
7)If song is playing set PlayBack state as PLAYSTATE_PLAYING and when song is paused set it to PLAYSTATE_PAUSED-
remoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING);
remoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_PAUSED);
|
Now all components are clear we will use Handler for interaction between Service and Activity.
For updating Song progress bar we will use timer as-
private
static Timer timer;
timer = new
Timer();
timer.scheduleAtFixedRate(new
MainTask(), 0, 100);
private class MainTask extends TimerTask{
public void run(){
handler.sendEmptyMessage(0);
}
}
private final Handler handler = new Handler(){
@Override
public void
handleMessage(Message msg){
if(mp != null){
int progress = (mp.getCurrentPosition()*100)
/ mp.getDuration();
Integer
i[] = new Integer[3];
i[0]
= mp.getCurrentPosition();
i[1]
= mp.getDuration();
i[2]
= progress;
try{
PlayerConstants.PROGRESSBAR_HANDLER.sendMessage(PlayerConstants.PROGRESSBAR_HANDLER.obtainMessage(0,
i));
}catch(Exception e){}
}
}
};
|
A) com.tutorialsface.audioplayer.util package files
MediaItem.java -
package
com.tutorialsface.audioplayer.util;
public class MediaItem {
String
title;
String
artist;
String
album;
String
path;
long duration;
long albumId;
String
composer;
@Override
public String
toString() {
return title;
}
public String
getTitle() {
return title;
}
public void setTitle(String
title) {
this.title = title;
}
public String
getArtist() {
return artist;
}
public void
setArtist(String artist) {
this.artist = artist;
}
public String
getAlbum() {
return album;
}
public void setAlbum(String
album) {
this.album = album;
}
public String
getPath() {
return path;
}
public void setPath(String
path) {
this.path = path;
}
public long getDuration() {
return duration;
}
public void setDuration(long duration) {
this.duration = duration;
}
public long getAlbumId() {
return albumId;
}
public void setAlbumId(long albumId) {
this.albumId = albumId;
}
public String
getComposer() {
return composer;
}
public void
setComposer(String composer) {
this.composer = composer;
}
}
|
PlayerConstants.java -
package
com.tutorialsface.audioplayer.util;
import
java.util.ArrayList;
import
android.os.Handler;
public class PlayerConstants
{
//List of
Songs
public static
ArrayList<MediaItem> SONGS_LIST = new
ArrayList<MediaItem>();
//song number
which is playing right now from SONGS_LIST
public static int SONG_NUMBER = 0;
//song is
playing or paused
public static boolean SONG_PAUSED = true;
//song changed
(next, previous)
public static boolean SONG_CHANGED = false;
//handler for
song changed(next, previous) defined in service(SongService)
public static Handler SONG_CHANGE_HANDLER;
//handler for
song play/pause defined in service(SongService)
public static Handler PLAY_PAUSE_HANDLER;
//handler for
showing song progress defined in Activities(MainActivity, AudioPlayerActivity)
public static Handler PROGRESSBAR_HANDLER;
}
|
UtilFunctions.java -
package
com.tutorialsface.audioplayer.util;
import
java.io.FileDescriptor;
import
java.util.ArrayList;
import
com.tutorialsface.audioplayer.R;
import
android.app.ActivityManager;
import
android.app.ActivityManager.RunningServiceInfo;
import
android.content.ContentUris;
import
android.content.Context;
import
android.database.Cursor;
import
android.graphics.Bitmap;
import
android.graphics.BitmapFactory;
import
android.net.Uri;
import
android.os.ParcelFileDescriptor;
import
android.provider.MediaStore;
import
android.util.Log;
public class UtilFunctions {
static String LOG_CLASS = "UtilFunctions";
/**
* Check if service is
running or not
* @param serviceName
* @param context
* @return
*/
public static boolean
isServiceRunning(String serviceName, Context context) {
ActivityManager
manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for(RunningServiceInfo
service : manager.getRunningServices(Integer.MAX_VALUE)) {
if(serviceName.equals(service.service.getClassName()))
{
return true;
}
}
return false;
}
/**
* Read the songs present
in external storage
* @param context
* @return
*/
public static
ArrayList<MediaItem> listOfSongs(Context context){
Uri
uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor
c = context.getContentResolver().query(uri, null,
MediaStore.Audio.Media.IS_MUSIC + " != 0", null, null);
ArrayList<MediaItem>
listOfSongs = new ArrayList<MediaItem>();
c.moveToFirst();
while(c.moveToNext()){
MediaItem
songData = new MediaItem();
String
title = c.getString(c.getColumnIndex(MediaStore.Audio.Media.TITLE));
String
artist = c.getString(c.getColumnIndex(MediaStore.Audio.Media.ARTIST));
String
album = c.getString(c.getColumnIndex(MediaStore.Audio.Media.ALBUM));
long duration =
c.getLong(c.getColumnIndex(MediaStore.Audio.Media.DURATION));
String
data = c.getString(c.getColumnIndex(MediaStore.Audio.Media.DATA));
long albumId =
c.getLong(c.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
String
composer = c.getString(c.getColumnIndex(MediaStore.Audio.Media.COMPOSER));
songData.setTitle(title);
songData.setAlbum(album);
songData.setArtist(artist);
songData.setDuration(duration);
songData.setPath(data);
songData.setAlbumId(albumId);
songData.setComposer(composer);
listOfSongs.add(songData);
}
c.close();
Log.d("SIZE", "SIZE:
" + listOfSongs.size());
return listOfSongs;
}
/**
* Get the album image
from albumId
* @param context
* @param album_id
* @param resize
* @return
*/
public static Bitmap
getAlbumart(Context context,Long album_id){
Bitmap
bm = null;
BitmapFactory.Options
options = new BitmapFactory.Options();
try{
final Uri sArtworkUri
= Uri.parse("content://media/external/audio/albumart");
Uri uri = ContentUris.withAppendedId(sArtworkUri,
album_id);
ParcelFileDescriptor pfd =
context.getContentResolver().openFileDescriptor(uri, "r");
if (pfd != null){
FileDescriptor fd =
pfd.getFileDescriptor();
bm = BitmapFactory.decodeFileDescriptor(fd,
null, options);
pfd = null;
fd = null;
}
} catch(Error ee){}
catch (Exception e)
{}
return bm;
}
/**
* @param context
* @return
*/
public static Bitmap
getDefaultAlbumArt(Context context){
Bitmap
bm = null;
BitmapFactory.Options
options = new BitmapFactory.Options();
try{
bm =
BitmapFactory.decodeResource(context.getResources(), R.drawable.default_album_art, options);
} catch(Error ee){}
catch (Exception e)
{}
return bm;
}
/**
* Convert milliseconds
into time hh:mm:ss
* @param milliseconds
* @return time in
String
*/
public static String
getDuration(long milliseconds) {
long sec =
(milliseconds / 1000) % 60;
long min =
(milliseconds / (60 * 1000))%60;
long hour = milliseconds
/ (60 * 60 * 1000);
String
s = (sec < 10) ? "0" + sec : "" + sec;
String
m = (min < 10) ? "0" + min : "" + min;
String
h = "" + hour;
String
time = "";
if(hour > 0) {
time
= h + ":" + m + ":" + s;
}
else {
time
= m + ":" + s;
}
return time;
}
public static boolean
currentVersionSupportBigNotification() {
int sdkVersion =
android.os.Build.VERSION.SDK_INT;
if(sdkVersion
>= android.os.Build.VERSION_CODES.JELLY_BEAN){
return true;
}
return false;
}
public static boolean
currentVersionSupportLockScreenControls() {
int sdkVersion =
android.os.Build.VERSION.SDK_INT;
if(sdkVersion
>= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH){
return true;
}
return false;
}
}
|
B) com.tutorialsface.audioplayer package files
MainActivity.java -
package
com.tutorialsface.audioplayer;
import
android.app.Activity;
import
android.content.Context;
import
android.content.Intent;
import
android.graphics.Bitmap;
import
android.graphics.PorterDuff.Mode;
import
android.graphics.drawable.BitmapDrawable;
import
android.os.Bundle;
import
android.os.Handler;
import
android.os.Message;
import
android.util.Log;
import
android.view.View;
import
android.view.View.OnClickListener;
import
android.widget.AdapterView;
import
android.widget.Button;
import
android.widget.ImageView;
import
android.widget.LinearLayout;
import
android.widget.ListView;
import
android.widget.ProgressBar;
import
android.widget.TextView;
import
com.tutorialsface.audioplayer.adapter.CustomAdapter;
import
com.tutorialsface.audioplayer.controls.Controls;
import
com.tutorialsface.audioplayer.service.SongService;
import
com.tutorialsface.audioplayer.util.MediaItem;
import
com.tutorialsface.audioplayer.util.PlayerConstants;
import
com.tutorialsface.audioplayer.util.UtilFunctions;
public class MainActivity extends Activity {
String
LOG_CLASS = "MainActivity";
CustomAdapter
customAdapter = null;
static TextView playingSong;
Button
btnPlayer;
static Button btnPause, btnPlay, btnNext, btnPrevious;
Button
btnStop;
LinearLayout
mediaLayout;
static LinearLayout linearLayoutPlayingSong;
ListView
mediaListView;
ProgressBar
progressBar;
TextView
textBufferDuration, textDuration;
static ImageView imageViewAlbumArt;
static Context context;
@Override
protected void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
getActionBar().hide();
setContentView(R.layout.activity_main);
context = MainActivity.this;
init();
}
private void init() {
getViews();
setListeners();
playingSong.setSelected(true);
progressBar.getProgressDrawable().setColorFilter(getResources().getColor(R.color.white), Mode.SRC_IN);
if(PlayerConstants.SONGS_LIST.size() <=
0){
PlayerConstants.SONGS_LIST =
UtilFunctions.listOfSongs(getApplicationContext());
}
setListItems();
}
private void setListItems()
{
customAdapter = new CustomAdapter(this,R.layout.custom_list,
PlayerConstants.SONGS_LIST);
mediaListView.setAdapter(customAdapter);
mediaListView.setFastScrollEnabled(true);
}
private void getViews() {
playingSong = (TextView)
findViewById(R.id.textNowPlaying);
btnPlayer = (Button)
findViewById(R.id.btnMusicPlayer);
mediaListView = (ListView) findViewById(R.id.listViewMusic);
mediaLayout =
(LinearLayout) findViewById(R.id.linearLayoutMusicList);
btnPause = (Button)
findViewById(R.id.btnPause);
btnPlay = (Button)
findViewById(R.id.btnPlay);
linearLayoutPlayingSong =
(LinearLayout) findViewById(R.id.linearLayoutPlayingSong);
progressBar = (ProgressBar)
findViewById(R.id.progressBar);
btnStop = (Button)
findViewById(R.id.btnStop);
textBufferDuration = (TextView)
findViewById(R.id.textBufferDuration);
textDuration = (TextView)
findViewById(R.id.textDuration);
imageViewAlbumArt = (ImageView)
findViewById(R.id.imageViewAlbumArt);
btnNext = (Button)
findViewById(R.id.btnNext);
btnPrevious = (Button)
findViewById(R.id.btnPrevious);
}
private void setListeners()
{
mediaListView.setOnItemClickListener(new
AdapterView.OnItemClickListener(){
@Override
public void
onItemClick(AdapterView<?> parent, View item, int position, long id){
Log.d("TAG", "TAG
Tapped INOUT(IN)");
PlayerConstants.SONG_PAUSED = false;
PlayerConstants.SONG_NUMBER = position;
boolean
isServiceRunning = UtilFunctions.isServiceRunning(SongService.class.getName(),
getApplicationContext());
if
(!isServiceRunning) {
Intent
i = new Intent(getApplicationContext(),SongService.class);
startService(i);
}
else {
PlayerConstants.SONG_CHANGE_HANDLER.sendMessage(PlayerConstants.SONG_CHANGE_HANDLER.obtainMessage());
}
updateUI();
changeButton();
Log.d("TAG", "TAG
Tapped INOUT(OUT)");
}
});
btnPlayer.setOnClickListener(new
OnClickListener() {
@Override
public void onClick(View v)
{
Intent
i = new Intent(MainActivity.this,AudioPlayerActivity.class);
startActivity(i);
}
});
btnPlay.setOnClickListener(new
OnClickListener() {
@Override
public void onClick(View v)
{
Controls.playControl(getApplicationContext());
}
});
btnPause.setOnClickListener(new
OnClickListener() {
@Override
public void onClick(View v)
{
Controls.pauseControl(getApplicationContext());
}
});
btnNext.setOnClickListener(new
OnClickListener() {
@Override
public void onClick(View v)
{
Controls.nextControl(getApplicationContext());
}
});
btnPrevious.setOnClickListener(new
OnClickListener() {
@Override
public void onClick(View v)
{
Controls.previousControl(getApplicationContext());
}
});
btnStop.setOnClickListener(new
OnClickListener() {
@Override
public void onClick(View v)
{
Intent
i = new Intent(getApplicationContext(), SongService.class);
stopService(i);
linearLayoutPlayingSong.setVisibility(View.GONE);
}
});
imageViewAlbumArt.setOnClickListener(new
OnClickListener() {
@Override
public void onClick(View v)
{
Intent
i = new Intent(MainActivity.this,AudioPlayerActivity.class);
startActivity(i);
}
});
}
@Override
protected void onResume() {
super.onResume();
try{
boolean
isServiceRunning = UtilFunctions.isServiceRunning(SongService.class.getName(),
getApplicationContext());
if
(isServiceRunning) {
updateUI();
}else{
linearLayoutPlayingSong.setVisibility(View.GONE);
}
changeButton();
PlayerConstants.PROGRESSBAR_HANDLER = new Handler(){
@Override
public void
handleMessage(Message msg){
Integer i[] = (Integer[])msg.obj;
textBufferDuration.setText(UtilFunctions.getDuration(i[0]));
textDuration.setText(UtilFunctions.getDuration(i[1]));
progressBar.setProgress(i[2]);
}
};
}catch(Exception e){}
}
public static void updateUI() {
try{
MediaItem
data = PlayerConstants.SONGS_LIST.get(PlayerConstants.SONG_NUMBER);
playingSong.setText(data.getTitle()
+ "
" + data.getArtist() + "-" +
data.getAlbum());
Bitmap
albumArt = UtilFunctions.getAlbumart(context,
data.getAlbumId());
if(albumArt != null){
imageViewAlbumArt.setBackgroundDrawable(new BitmapDrawable(albumArt));
}else{
imageViewAlbumArt.setBackgroundDrawable(new BitmapDrawable (UtilFunctions.getDefaultAlbumArt(context)));
}
linearLayoutPlayingSong.setVisibility(View.VISIBLE);
}catch(Exception e){}
}
public static void changeButton()
{
if(PlayerConstants.SONG_PAUSED){
btnPause.setVisibility(View.GONE);
btnPlay.setVisibility(View.VISIBLE);
}else{
btnPause.setVisibility(View.VISIBLE);
btnPlay.setVisibility(View.GONE);
}
}
public static void changeUI(){
updateUI();
changeButton();
}
}
|
AudioPlayerActivity.java -
import
android.app.Activity;
import android.content.Context;
import
android.graphics.Bitmap;
import
android.graphics.PorterDuff.Mode;
import
android.graphics.drawable.BitmapDrawable;
import
android.os.Bundle;
import
android.os.Handler;
import
android.os.Message;
import
android.view.View;
import
android.view.View.OnClickListener;
import
android.widget.Button;
import
android.widget.LinearLayout;
import
android.widget.ProgressBar;
import
android.widget.TextView;
import
com.tutorialsface.audioplayer.controls.Controls;
import
com.tutorialsface.audioplayer.service.SongService;
import
com.tutorialsface.audioplayer.util.PlayerConstants;
import
com.tutorialsface.audioplayer.util.UtilFunctions;
public class
AudioPlayerActivity extends Activity {
Button
btnBack;
static Button btnPause;
Button
btnNext;
static Button btnPlay;
static TextView textNowPlaying;
static TextView textAlbumArtist;
static TextView textComposer;
static LinearLayout linearLayoutPlayer;
ProgressBar
progressBar;
static Context context;
TextView
textBufferDuration, textDuration;
@Override
protected void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
getActionBar().hide();
setContentView(R.layout.audio_player);
context = this;
init();
}
private void init() {
getViews();
setListeners();
progressBar.getProgressDrawable().setColorFilter(getResources().getColor(R.color.white), Mode.SRC_IN);
PlayerConstants.PROGRESSBAR_HANDLER = new Handler(){
@Override
public void
handleMessage(Message msg){
Integer i[] = (Integer[])msg.obj;
textBufferDuration.setText(UtilFunctions.getDuration(i[0]));
textDuration.setText(UtilFunctions.getDuration(i[1]));
progressBar.setProgress(i[2]);
}
};
}
private void setListeners()
{
btnBack.setOnClickListener(new
OnClickListener() {
@Override
public void onClick(View v)
{
Controls.previousControl(getApplicationContext());
}
});
btnPause.setOnClickListener(new
OnClickListener() {
@Override
public void onClick(View v)
{
Controls.pauseControl(getApplicationContext());
}
});
btnPlay.setOnClickListener(new
OnClickListener() {
@Override
public void onClick(View v)
{
Controls.playControl(getApplicationContext());
}
});
btnNext.setOnClickListener(new
OnClickListener() {
@Override
public void onClick(View v)
{
Controls.nextControl(getApplicationContext());
}
});
}
public static void changeUI(){
updateUI();
changeButton();
}
private void getViews() {
btnBack = (Button)
findViewById(R.id.btnBack);
btnPause = (Button)
findViewById(R.id.btnPause);
btnNext = (Button)
findViewById(R.id.btnNext);
btnPlay = (Button)
findViewById(R.id.btnPlay);
textNowPlaying = (TextView)
findViewById(R.id.textNowPlaying);
linearLayoutPlayer =
(LinearLayout) findViewById(R.id.linearLayoutPlayer);
textAlbumArtist = (TextView)
findViewById(R.id.textAlbumArtist);
textComposer = (TextView)
findViewById(R.id.textComposer);
progressBar = (ProgressBar)
findViewById(R.id.progressBar);
textBufferDuration = (TextView)
findViewById(R.id.textBufferDuration);
textDuration = (TextView)
findViewById(R.id.textDuration);
textNowPlaying.setSelected(true);
textAlbumArtist.setSelected(true);
}
@Override
protected void onResume() {
super.onResume();
boolean
isServiceRunning = UtilFunctions.isServiceRunning(SongService.class.getName(),
getApplicationContext());
if
(isServiceRunning) {
updateUI();
}
changeButton();
}
public static void changeButton()
{
if(PlayerConstants.SONG_PAUSED){
btnPause.setVisibility(View.GONE);
btnPlay.setVisibility(View.VISIBLE);
}else{
btnPause.setVisibility(View.VISIBLE);
btnPlay.setVisibility(View.GONE);
}
}
private static void updateUI() {
try{
String
songName = PlayerConstants.SONGS_LIST.get(PlayerConstants.SONG_NUMBER).getTitle();
String
artist = PlayerConstants.SONGS_LIST.get(PlayerConstants.SONG_NUMBER).getArtist();
String
album = PlayerConstants.SONGS_LIST.get(PlayerConstants.SONG_NUMBER).getAlbum();
String
composer = PlayerConstants.SONGS_LIST.get(PlayerConstants.SONG_NUMBER).getComposer();
textNowPlaying.setText(songName);
textAlbumArtist.setText(artist
+ "
- " + album);
if(composer != null &&
composer.length() > 0){
textComposer.setVisibility(View.VISIBLE);
textComposer.setText(composer);
}else{
textComposer.setVisibility(View.GONE);
}
}catch(Exception e){
e.printStackTrace();
}
try{
long albumId =
PlayerConstants.SONGS_LIST.get(PlayerConstants.SONG_NUMBER).getAlbumId();
Bitmap
albumArt = UtilFunctions.getAlbumart(context, albumId);
if(albumArt != null){
linearLayoutPlayer.setBackgroundDrawable(new BitmapDrawable(albumArt));
}else{
linearLayoutPlayer.setBackgroundDrawable(new BitmapDrawable (UtilFunctions.getDefaultAlbumArt(context)));
}
}catch(Exception e){
e.printStackTrace();
}
}
}
|
C) com.tutorialsface.audioplayer.controls package files
AudioPlayerActivity.java -
package
com.tutorialsface.audioplayer.controls;
import
android.content.Context;
import
com.tutorialsface.audioplayer.R;
import
com.tutorialsface.audioplayer.service.SongService;
import
com.tutorialsface.audioplayer.util.PlayerConstants;
import
com.tutorialsface.audioplayer.util.UtilFunctions;
public class Controls {
static String LOG_CLASS = "Controls";
public static void
playControl(Context context) {
sendMessage(context.getResources().getString(R.string.play));
}
public static void
pauseControl(Context context) {
sendMessage(context.getResources().getString(R.string.pause));
}
public static void
nextControl(Context context) {
boolean
isServiceRunning = UtilFunctions.isServiceRunning(SongService.class.getName(),
context);
if
(!isServiceRunning)
return;
if(PlayerConstants.SONGS_LIST.size() > 0
){
if(PlayerConstants.SONG_NUMBER <
(PlayerConstants.SONGS_LIST.size()-1)){
PlayerConstants.SONG_NUMBER++;
PlayerConstants.SONG_CHANGE_HANDLER.sendMessage(PlayerConstants.SONG_CHANGE_HANDLER.obtainMessage());
}else{
PlayerConstants.SONG_NUMBER = 0;
PlayerConstants.SONG_CHANGE_HANDLER.sendMessage(PlayerConstants.SONG_CHANGE_HANDLER.obtainMessage());
}
}
PlayerConstants.SONG_PAUSED = false;
}
public static void
previousControl(Context context) {
boolean
isServiceRunning = UtilFunctions.isServiceRunning(SongService.class.getName(),
context);
if
(!isServiceRunning)
return;
if(PlayerConstants.SONGS_LIST.size() > 0
){
if(PlayerConstants.SONG_NUMBER > 0){
PlayerConstants.SONG_NUMBER--;
PlayerConstants.SONG_CHANGE_HANDLER.sendMessage(PlayerConstants.SONG_CHANGE_HANDLER.obtainMessage());
}else{
PlayerConstants.SONG_NUMBER =
PlayerConstants.SONGS_LIST.size() - 1;
PlayerConstants.SONG_CHANGE_HANDLER.sendMessage(PlayerConstants.SONG_CHANGE_HANDLER.obtainMessage());
}
}
PlayerConstants.SONG_PAUSED = false;
}
private static void
sendMessage(String message) {
try{
PlayerConstants.PLAY_PAUSE_HANDLER.sendMessage(PlayerConstants.PLAY_PAUSE_HANDLER.obtainMessage(0,
message));
}catch(Exception e){}
}
}
|
D) com.tutorialsface.audioplayer.adapter package files
CustomAdapter.java -
package
com.tutorialsface.audioplayer.adapter;
import
java.util.ArrayList;
import
android.content.Context;
import
android.view.LayoutInflater;
import
android.view.View;
import
android.view.ViewGroup;
import
android.widget.ArrayAdapter;
import
android.widget.TextView;
import
com.tutorialsface.audioplayer.R;
import
com.tutorialsface.audioplayer.util.MediaItem;
import
com.tutorialsface.audioplayer.util.UtilFunctions;
public class CustomAdapter extends
ArrayAdapter<MediaItem>{
ArrayList<MediaItem>
listOfSongs;
Context
context;
LayoutInflater
inflator;
public
CustomAdapter(Context context, int resource, ArrayList<MediaItem> listOfSongs) {
super(context,
resource, listOfSongs);
this.listOfSongs = listOfSongs;
this.context = context;
inflator =
LayoutInflater.from(context);
}
private class ViewHolder{
TextView
textViewSongName, textViewArtist, textViewDuration;
}
ViewHolder
holder;
@Override
public View getView(int position, View
convertView, ViewGroup parent) {
View
myView = convertView;
if(convertView == null){
myView
= inflator.inflate(R.layout.custom_list, parent, false);
holder = new ViewHolder();
holder.textViewSongName = (TextView)
myView.findViewById(R.id.textViewSongName);
holder.textViewArtist = (TextView)
myView.findViewById(R.id.textViewArtist);
holder.textViewDuration = (TextView)
myView.findViewById(R.id.textViewDuration);
myView.setTag(holder);
}else{
holder =
(ViewHolder)myView.getTag();
}
MediaItem
detail = listOfSongs.get(position);
holder.textViewSongName.setText(detail.toString());
holder.textViewArtist.setText(detail.getAlbum()
+ "
- " + detail.getArtist());
holder.textViewDuration.setText(UtilFunctions.getDuration(detail.getDuration()));
return myView;
}
}
|
E) com.tutorialsface.audioplayer.receiver package files
NotificationBroadcast.java -
package
com.tutorialsface.audioplayer.receiver;
import
android.content.BroadcastReceiver;
import
android.content.Context;
import
android.content.Intent;
import
android.util.Log;
import
android.view.KeyEvent;
import
com.tutorialsface.audioplayer.MainActivity;
import
com.tutorialsface.audioplayer.controls.Controls;
import
com.tutorialsface.audioplayer.service.SongService;
import
com.tutorialsface.audioplayer.util.PlayerConstants;
public class
NotificationBroadcast extends BroadcastReceiver {
@Override
public void
onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_MEDIA_BUTTON)) {
KeyEvent keyEvent = (KeyEvent)
intent.getExtras().get(Intent.EXTRA_KEY_EVENT);
if
(keyEvent.getAction() != KeyEvent.ACTION_DOWN)
return;
switch (keyEvent.getKeyCode())
{
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
if(!PlayerConstants.SONG_PAUSED){
Controls.pauseControl(context);
}else{
Controls.playControl(context);
}
break;
case KeyEvent.KEYCODE_MEDIA_PLAY:
break;
case KeyEvent.KEYCODE_MEDIA_PAUSE:
break;
case KeyEvent.KEYCODE_MEDIA_STOP:
break;
case KeyEvent.KEYCODE_MEDIA_NEXT:
Log.d("TAG", "TAG: KEYCODE_MEDIA_NEXT");
Controls.nextControl(context);
break;
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
Log.d("TAG", "TAG: KEYCODE_MEDIA_PREVIOUS");
Controls.previousControl(context);
break;
}
} else{
if
(intent.getAction().equals(SongService.NOTIFY_PLAY)) {
Controls.playControl(context);
}
else if
(intent.getAction().equals(SongService.NOTIFY_PAUSE)) {
Controls.pauseControl(context);
}
else if
(intent.getAction().equals(SongService.NOTIFY_NEXT)) {
Controls.nextControl(context);
}
else if
(intent.getAction().equals(SongService.NOTIFY_DELETE)) {
Intent
i = new Intent(context, SongService.class);
context.stopService(i);
Intent
in = new Intent(context, MainActivity.class);
in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(in);
}else if
(intent.getAction().equals(SongService.NOTIFY_PREVIOUS)) {
Controls.previousControl(context);
}
}
}
public String
ComponentName() {
return this.getClass().getName();
}
}
|
F) com.tutorialsface.audioplayer.service package files
SongService.java -
package
com.tutorialsface.audioplayer.service;
import
java.io.IOException;
import
java.util.Timer;
import
java.util.TimerTask;
import
android.annotation.SuppressLint;
import android.app.Notification;
import
android.app.PendingIntent;
import
android.app.Service;
import
android.content.ComponentName;
import
android.content.Intent;
import
android.graphics.Bitmap;
import
android.graphics.BitmapFactory;
import
android.media.AudioManager;
import
android.media.MediaMetadataRetriever;
import
android.media.MediaPlayer;
import
android.media.MediaPlayer.OnCompletionListener;
import
android.media.RemoteControlClient;
import
android.media.RemoteControlClient.MetadataEditor;
import
android.os.Handler;
import
android.os.Handler.Callback;
import
android.os.IBinder;
import
android.os.Message;
import
android.support.v4.app.NotificationCompat;
import
android.util.Log;
import
android.view.View;
import
android.widget.RemoteViews;
import
com.tutorialsface.audioplayer.AudioPlayerActivity;
import
com.tutorialsface.audioplayer.MainActivity;
import
com.tutorialsface.audioplayer.R;
import
com.tutorialsface.audioplayer.controls.Controls;
import
com.tutorialsface.audioplayer.receiver.NotificationBroadcast;
import com.tutorialsface.audioplayer.util.MediaItem;
import
com.tutorialsface.audioplayer.util.PlayerConstants;
import
com.tutorialsface.audioplayer.util.UtilFunctions;
public class SongService extends Service implements
AudioManager.OnAudioFocusChangeListener{
String
LOG_CLASS = "SongService";
private MediaPlayer mp;
int NOTIFICATION_ID = 1111;
public static final String NOTIFY_PREVIOUS = "com.tutorialsface.audioplayer.previous";
public static final String NOTIFY_DELETE = "com.tutorialsface.audioplayer.delete";
public static final String NOTIFY_PAUSE = "com.tutorialsface.audioplayer.pause";
public static final String NOTIFY_PLAY = "com.tutorialsface.audioplayer.play";
public static final String NOTIFY_NEXT = "com.tutorialsface.audioplayer.next";
private ComponentName remoteComponentName;
private
RemoteControlClient remoteControlClient;
AudioManager
audioManager;
Bitmap
mDummyAlbumArt;
private static Timer timer;
private static boolean currentVersionSupportBigNotification = false;
private static boolean currentVersionSupportLockScreenControls = false;
@Override
public IBinder
onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
mp = new MediaPlayer();
audioManager =
(AudioManager) getSystemService(AUDIO_SERVICE);
currentVersionSupportBigNotification =
UtilFunctions.currentVersionSupportBigNotification();
currentVersionSupportLockScreenControls =
UtilFunctions.currentVersionSupportLockScreenControls();
timer = new Timer();
mp.setOnCompletionListener(new
OnCompletionListener() {
@Override
public void
onCompletion(MediaPlayer mp) {
Controls.nextControl(getApplicationContext());
}
});
super.onCreate();
}
/**
* Send message from
timer
* @author jonty.ankit
*/
private class MainTask extends TimerTask{
public void run(){
handler.sendEmptyMessage(0);
}
}
private final Handler handler = new Handler(){
@Override
public void
handleMessage(Message msg){
if(mp != null){
int progress = (mp.getCurrentPosition()*100)
/ mp.getDuration();
Integer
i[] = new Integer[3];
i[0]
= mp.getCurrentPosition();
i[1]
= mp.getDuration();
i[2]
= progress;
try{
PlayerConstants.PROGRESSBAR_HANDLER.sendMessage(PlayerConstants.PROGRESSBAR_HANDLER.obtainMessage(0,
i));
}catch(Exception e){}
}
}
};
@SuppressLint("NewApi")
@Override
public int
onStartCommand(Intent intent, int flags, int startId) {
try {
if(PlayerConstants.SONGS_LIST.size() <=
0){
PlayerConstants.SONGS_LIST =
UtilFunctions.listOfSongs(getApplicationContext());
}
MediaItem
data = PlayerConstants.SONGS_LIST.get(PlayerConstants.SONG_NUMBER);
if(currentVersionSupportLockScreenControls){
RegisterRemoteClient();
}
String
songPath = data.getPath();
playSong(songPath,
data);
newNotification();
PlayerConstants.SONG_CHANGE_HANDLER = new Handler(new Callback() {
@Override
public boolean
handleMessage(Message msg) {
MediaItem
data = PlayerConstants.SONGS_LIST.get(PlayerConstants.SONG_NUMBER);
String
songPath = data.getPath();
newNotification();
try{
playSong(songPath,
data);
MainActivity.changeUI();
AudioPlayerActivity.changeUI();
}catch(Exception e){
e.printStackTrace();
}
return false;
}
});
PlayerConstants.PLAY_PAUSE_HANDLER = new Handler(new Callback() {
@Override
public boolean
handleMessage(Message msg) {
String
message = (String)msg.obj;
if(mp == null)
return false;
if(message.equalsIgnoreCase(getResources().getString(R.string.play))){
PlayerConstants.SONG_PAUSED = false;
if(currentVersionSupportLockScreenControls){
remoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING);
}
mp.start();
}else if(message.equalsIgnoreCase(getResources().getString(R.string.pause))){
PlayerConstants.SONG_PAUSED = true;
if(currentVersionSupportLockScreenControls){
remoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_PAUSED);
}
mp.pause();
}
newNotification();
try{
MainActivity.changeButton();
AudioPlayerActivity.changeButton();
}catch(Exception e){}
Log.d("TAG", "TAG
Pressed: " + message);
return false;
}
});
}
catch (Exception e) {
e.printStackTrace();
}
return START_STICKY;
}
/**
* Notification
* Custom Bignotification
is available from API 16
*/
@SuppressLint("NewApi")
private void
newNotification() {
String
songName = PlayerConstants.SONGS_LIST.get(PlayerConstants.SONG_NUMBER).getTitle();
String
albumName = PlayerConstants.SONGS_LIST.get(PlayerConstants.SONG_NUMBER).getAlbum();
RemoteViews
simpleContentView = new RemoteViews(getApplicationContext().getPackageName(),R.layout.custom_notification);
RemoteViews
expandedView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.big_notification);
Notification
notification = new NotificationCompat.Builder(getApplicationContext())
.setSmallIcon(R.drawable.ic_music)
.setContentTitle(songName).build();
setListeners(simpleContentView);
setListeners(expandedView);
notification.contentView =
simpleContentView;
if(currentVersionSupportBigNotification){
notification.bigContentView = expandedView;
}
try{
long albumId =
PlayerConstants.SONGS_LIST.get(PlayerConstants.SONG_NUMBER).getAlbumId();
Bitmap
albumArt = UtilFunctions.getAlbumart(getApplicationContext(), albumId);
if(albumArt != null){
notification.contentView.setImageViewBitmap(R.id.imageViewAlbumArt, albumArt);
if(currentVersionSupportBigNotification){
notification.bigContentView.setImageViewBitmap(R.id.imageViewAlbumArt, albumArt);
}
}else{
notification.contentView.setImageViewResource(R.id.imageViewAlbumArt, R.drawable.default_album_art);
if(currentVersionSupportBigNotification){
notification.bigContentView.setImageViewResource(R.id.imageViewAlbumArt, R.drawable.default_album_art);
}
}
}catch(Exception e){
e.printStackTrace();
}
if(PlayerConstants.SONG_PAUSED){
notification.contentView.setViewVisibility(R.id.btnPause, View.GONE);
notification.contentView.setViewVisibility(R.id.btnPlay, View.VISIBLE);
if(currentVersionSupportBigNotification){
notification.bigContentView.setViewVisibility(R.id.btnPause, View.GONE);
notification.bigContentView.setViewVisibility(R.id.btnPlay, View.VISIBLE);
}
}else{
notification.contentView.setViewVisibility(R.id.btnPause, View.VISIBLE);
notification.contentView.setViewVisibility(R.id.btnPlay, View.GONE);
if(currentVersionSupportBigNotification){
notification.bigContentView.setViewVisibility(R.id.btnPause, View.VISIBLE);
notification.bigContentView.setViewVisibility(R.id.btnPlay, View.GONE);
}
}
notification.contentView.setTextViewText(R.id.textSongName, songName);
notification.contentView.setTextViewText(R.id.textAlbumName, albumName);
if(currentVersionSupportBigNotification){
notification.bigContentView.setTextViewText(R.id.textSongName, songName);
notification.bigContentView.setTextViewText(R.id.textAlbumName, albumName);
}
notification.flags |=
Notification.FLAG_ONGOING_EVENT;
startForeground(NOTIFICATION_ID, notification);
}
/**
* Notification click
listeners
* @param view
*/
public void
setListeners(RemoteViews view) {
Intent
previous = new Intent(NOTIFY_PREVIOUS);
Intent
delete = new Intent(NOTIFY_DELETE);
Intent
pause = new Intent(NOTIFY_PAUSE);
Intent
next = new Intent(NOTIFY_NEXT);
Intent
play = new Intent(NOTIFY_PLAY);
PendingIntent
pPrevious = PendingIntent.getBroadcast(getApplicationContext(), 0,
previous, PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.btnPrevious, pPrevious);
PendingIntent
pDelete = PendingIntent.getBroadcast(getApplicationContext(), 0, delete,
PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.btnDelete, pDelete);
PendingIntent
pPause = PendingIntent.getBroadcast(getApplicationContext(), 0, pause,
PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.btnPause, pPause);
PendingIntent
pNext = PendingIntent.getBroadcast(getApplicationContext(), 0, next,
PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.btnNext, pNext);
PendingIntent
pPlay = PendingIntent.getBroadcast(getApplicationContext(), 0, play,
PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.btnPlay, pPlay);
}
@Override
public void onDestroy() {
if(mp != null){
mp.stop();
mp = null;
}
super.onDestroy();
}
/**
* Play song, Update Lockscreen
fields
* @param songPath
* @param data
*/
@SuppressLint("NewApi")
private void playSong(String
songPath, MediaItem data) {
try {
if(currentVersionSupportLockScreenControls){
UpdateMetadata(data);
remoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING);
}
mp.reset();
mp.setDataSource(songPath);
mp.prepare();
mp.start();
timer.scheduleAtFixedRate(new MainTask(), 0,
100);
}
catch (IOException e)
{
e.printStackTrace();
}
}
@SuppressLint("NewApi")
private void
RegisterRemoteClient(){
remoteComponentName = new
ComponentName(getApplicationContext(), new
NotificationBroadcast().ComponentName());
try {
if(remoteControlClient == null) {
audioManager.registerMediaButtonEventReceiver(remoteComponentName);
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
mediaButtonIntent.setComponent(remoteComponentName);
PendingIntent mediaPendingIntent =
PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0);
remoteControlClient = new
RemoteControlClient(mediaPendingIntent);
audioManager.registerRemoteControlClient(remoteControlClient);
}
remoteControlClient.setTransportControlFlags(
RemoteControlClient.FLAG_KEY_MEDIA_PLAY |
RemoteControlClient.FLAG_KEY_MEDIA_PAUSE |
RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE |
RemoteControlClient.FLAG_KEY_MEDIA_STOP |
RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS |
RemoteControlClient.FLAG_KEY_MEDIA_NEXT);
}catch(Exception ex) {
}
}
@SuppressLint("NewApi")
private void
UpdateMetadata(MediaItem data){
if (remoteControlClient == null)
return;
MetadataEditor
metadataEditor = remoteControlClient.editMetadata(true);
metadataEditor.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM,
data.getAlbum());
metadataEditor.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST,
data.getArtist());
metadataEditor.putString(MediaMetadataRetriever.METADATA_KEY_TITLE,
data.getTitle());
mDummyAlbumArt =
UtilFunctions.getAlbumart(getApplicationContext(), data.getAlbumId());
if(mDummyAlbumArt == null){
mDummyAlbumArt =
BitmapFactory.decodeResource(getResources(), R.drawable.default_album_art);
}
metadataEditor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, mDummyAlbumArt);
metadataEditor.apply();
audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
}
@Override
public void onAudioFocusChange(int focusChange) {}
}
|
UI xml
activity_main.xml
<?xml version="1.0"
encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linearLayoutMusicList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:background="@drawable/default_album_art_thumb"
android:orientation="vertical" >
<ListView
android:id="@+id/listViewMusic"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:background="@android:color/transparent"
/>
<LinearLayout
android:id="@+id/linearLayoutPlayingSong"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/orange"
android:gravity="center"
android:orientation="vertical"
>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@android:color/darker_gray"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:orientation="horizontal"
>
<ImageView
android:id="@+id/imageViewAlbumArt"
android:layout_width="@dimen/small_image_art_width"
android:layout_height="@dimen/small_image_art_width"
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="@+id/textNowPlaying"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="marquee"
android:gravity="center_horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
android:text="@string/empty_text"
android:textColor="@color/white"
android:textSize="15dp"
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="horizontal"
>
<Button
android:id="@+id/btnPrevious"
android:layout_width="@dimen/small_button_width"
android:layout_height="@dimen/small_button_width"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/ic_action_previous" />
<Button
android:id="@+id/btnPlay"
android:layout_width="@dimen/small_button_width"
android:layout_height="@dimen/small_button_width"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/ic_action_play"
android:visibility="gone" />
<Button
android:id="@+id/btnPause"
android:layout_width="@dimen/small_button_width"
android:layout_height="@dimen/small_button_width"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/ic_action_pause" />
<Button
android:id="@+id/btnStop"
android:layout_width="@dimen/small_button_width"
android:layout_height="@dimen/small_button_width"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/ic_action_stop" />
<Button
android:id="@+id/btnNext"
android:layout_width="@dimen/small_button_width"
android:layout_height="@dimen/small_button_width"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/ic_action_next" />
<Button
android:id="@+id/btnMusicPlayer"
android:layout_width="@dimen/small_button_width"
android:layout_height="@dimen/small_button_width"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/ic_music" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:orientation="horizontal"
>
<TextView
android:id="@+id/textBufferDuration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="@color/white" />
<TextView
android:id="@+id/textDuration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:textColor="@color/white" />
</LinearLayout>
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="1dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
|
audio_player.xml
<?xml version="1.0"
encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linearLayoutPlayer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/default_album_art"
android:gravity="center"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#70000000"
android:gravity="center"
android:orientation="vertical"
>
<TextView
android:id="@+id/textNowPlaying"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:gravity="center_horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:paddingLeft="5dp"
android:paddingTop="20dp"
android:singleLine="true"
android:text="@string/idle"
android:textColor="@color/white"
android:textSize="30dp"
/>
<TextView
android:id="@+id/textAlbumArtist"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:gravity="center_horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:paddingLeft="5dp"
android:singleLine="true"
android:textColor="@color/white"
android:textSize="15dp"
/>
<TextView
android:id="@+id/textComposer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:paddingLeft="5dp"
android:textColor="@color/white"
android:textSize="15dp"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:orientation="horizontal"
>
<TextView
android:id="@+id/textBufferDuration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="@color/white"
/>
<TextView
android:id="@+id/textDuration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:textColor="@color/white"
/>
</LinearLayout>
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@android:color/darker_gray"
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center|bottom"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:background="@color/orange"
android:gravity="center"
android:orientation="horizontal"
>
<Button
android:id="@+id/btnBack"
android:layout_width="@dimen/button_width"
android:layout_height="@dimen/button_width"
android:layout_margin="10dp"
android:background="@drawable/ic_action_previous"
/>
<View
android:layout_width="1dp"
android:layout_height="@dimen/button_width"
android:background="@android:color/darker_gray"
/>
<Button
android:id="@+id/btnPause"
android:layout_width="@dimen/button_width"
android:layout_height="@dimen/button_width"
android:layout_margin="10dp"
android:background="@drawable/ic_action_pause"
android:visibility="gone"
/>
<Button
android:id="@+id/btnPlay"
android:layout_width="@dimen/button_width"
android:layout_height="@dimen/button_width"
android:layout_margin="10dp"
android:background="@drawable/ic_action_play"
/>
<View
android:layout_width="1dp"
android:layout_height="@dimen/button_width"
android:background="@android:color/darker_gray"
/>
<Button
android:id="@+id/btnNext"
android:layout_width="@dimen/button_width"
android:layout_height="@dimen/button_width"
android:layout_margin="10dp"
android:background="@drawable/ic_action_next"
/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
|
custom_list.xml
<?xml version="1.0"
encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="5dp" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:orientation="vertical"
>
<TextView
android:id="@+id/textViewSongName"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:singleLine="true"
android:textColor="@android:color/white"
android:textSize="22dp"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView
android:id="@+id/textViewArtist"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:layout_weight="1"
android:textColor="@android:color/white"
android:textSize="15dp"
/>
<TextView
android:id="@+id/textViewDuration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:layout_marginLeft="10dp"
android:textSize="12dp"
/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
|
Notification xml
custom_notification.xml
<?xml version="1.0"
encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:orientation="horizontal"
>
<ImageView
android:id="@+id/imageViewAlbumArt"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/ic_launcher" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical"
android:padding="5dp"
>
<TextView
android:id="@+id/textSongName"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:selectAllOnFocus="true"
android:singleLine="true"
android:textColor="@android:color/white"
android:textSize="20dp"
/>
<TextView
android:id="@+id/textAlbumName"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:gravity="center_vertical"
android:marqueeRepeatLimit="marquee_forever"
android:selectAllOnFocus="true"
android:singleLine="true"
android:textColor="#C0C0C0"
android:textSize="15dp"
/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:gravity="center"
android:orientation="horizontal"
>
<Button
android:id="@+id/btnPause"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_margin="5dp"
android:background="@drawable/ic_action_pause"
/>
<Button
android:id="@+id/btnPlay"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_margin="5dp"
android:background="@drawable/ic_action_play"
android:visibility="gone"
/>
<Button
android:id="@+id/btnNext"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_margin="5dp"
android:background="@drawable/ic_action_next"
/>
</LinearLayout>
<Button
android:id="@+id/btnDelete"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_marginLeft="5dp"
android:background="@drawable/ic_action_remove"
/>
</LinearLayout>
</LinearLayout>
|
big_notification.xml
<?xml version="1.0"
encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
>
<ImageView
android:id="@+id/imageViewAlbumArt"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/ic_launcher" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:padding="5dp"
>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView
android:id="@+id/textSongName"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
android:singleLine="true"
android:textColor="@android:color/white"
android:textSize="20dp"/>
<Button
android:id="@+id/btnDelete"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_marginLeft="5dp"
android:background="@drawable/ic_action_remove"
/>
</LinearLayout>
<TextView
android:id="@+id/textAlbumName"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:singleLine="true"
android:textColor="#C0C0C0"
android:textSize="15dp"
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:divider="@drawable/mydivider"
android:dividerPadding="12.0dip"
android:gravity="center"
android:orientation="horizontal"
android:showDividers="middle"
>
<Button
android:id="@+id/btnPrevious"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_margin="5dp"
android:background="@drawable/ic_action_previous"
/>
<Button
android:id="@+id/btnPause"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_margin="5dp"
android:background="@drawable/ic_action_pause"
/>
<Button
android:id="@+id/btnPlay"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_margin="5dp"
android:background="@drawable/ic_action_play"
android:visibility="gone"
/>
<Button
android:id="@+id/btnNext"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_margin="5dp"
android:background="@drawable/ic_action_next"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
|
strings.xml
<resources>
<string name="app_name">Music Player</string>
<string name="back">Back</string>
<string name="pause">Pause</string>
<string name="play">Play</string>
<string name="player">Audio Player</string>
<string name="next">Next</string>
<string name="open_playlist">Open Playlist</string>
<string name="idle">Idle</string>
<string name="empty_text">Select song from below
to play</string>
<string name="player_button">Album Art Screen</string>
<color name="orange">#ff3d00</color>
<color name="white">#ffffff</color>
<color name="opaque">#70000000</color>
<dimen name="button_width">32dp</dimen>
<dimen name="small_button_width">28dp</dimen>
<dimen name="small_image_art_width">85dp</dimen>
</resources>
|
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tutorialsface.audioplayer"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="19"
/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.tutorialsface.audioplayer.MainActivity"
android:launchMode="singleTask"
android:screenOrientation="portrait"
>
<intent-filter>
<action android:name="android.intent.action.MAIN"
/>
<category android:name="android.intent.category.LAUNCHER"
/>
</intent-filter>
</activity>
<activity
android:name="com.tutorialsface.audioplayer.AudioPlayerActivity"
android:excludeFromRecents="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
>
</activity>
<service
android:name="com.tutorialsface.audioplayer.service.SongService"
android:exported="true"
android:enabled="true"/>
<receiver android:name="com.tutorialsface.audioplayer.receiver.NotificationBroadcast" >
<intent-filter>
<action android:name="com.tutorialsface.audioplayer.delete"
/>
<action android:name="com.tutorialsface.audioplayer.pause"
/>
<action android:name="com.tutorialsface.audioplayer.next"
/>
<action android:name="com.tutorialsface.audioplayer.play"
/>
<action android:name="com.tutorialsface.audioplayer.previous"
/>
<action android:name="android.intent.action.MEDIA_BUTTON"
/>
</intent-filter>
</receiver>
</application>
</manifest>
|
This comment has been removed by the author.
ReplyDeleteHI, I am using 'rtsp' streaming and getting a issue i.e. Player is getting stuck for some time on RemoteControlClient and NotificationUpdate.
ReplyDeleteHi, Brilliant tutorial, Thank you.
ReplyDeleteI am wondering how I could go about updating the list of files.
What I am trying to do is download a file, and have the application update the list.
So far, I have the app calling the "PlayerConstants.SONGS_LIST = utilFunctions.listOfSongs(getActivity().getApplicationContext());", but this does not return new items (only returns the same items again), UNLESS the device is restarted.
How can I have the list update without first restarting the device and relaunching the app?
Thank you.
Just after posting, I found that I need to call MediaScanner to rescan the library.
DeleteAnyone with similar problem, read here: http://stackoverflow.com/questions/2170214/image-saved-to-sdcard-doesnt-appear-in-androids-gallery-app
Sorry about this.
hey thanx for this gr8 tutorial... i would love some help though on how to organise the music according to artists and albums
ReplyDeletehttps://www.dropbox.com/s/jgjd94xqdicr221/LibMedia.java?dl=0
DeleteHey Kumar. thanx for the help. was wondering if you mind helping me with your sample code for the whole player. Pleaasee be my hero, and thanx in advance.
Deleteor just the LogUtils class. thank you very much
DeleteYou can email it to my email brianmigel@gmail.com
DeleteHey Ankit thank you for the help but was still wondering if you could help me with the LogUtils class and the custom adapter classes. thank you again in advance
Deletehow to get the songs from online ie)like gaana
DeleteGaana have its own API. You can try Rdio.
DeleteThis comment has been removed by the author.
ReplyDeleteawesome
ReplyDeletehi, can I use it from API 8 ?!!
ReplyDeleteHey...It's a great tutorial but how can I retrieve album art from mediastore other than a path....I have SongAdapter class.. PLEASE HELP ME....
ReplyDeletethat was nice tuts
ReplyDeleteVery nice player with all functionality. but one issue is when you play music first time and then pause music and lock your phone screen or sleep mode for 20-25 minutes and then song play from notification, songs are not played as well as your application is crashing.
ReplyDeleteNice Player. But how to add seekbar to seek the current playing song ?
ReplyDeletehiii jaimin you can solve this problem than help me how to solve it ?
DeleteThis comment has been removed by the author.
ReplyDeletehow to set Seekbar, change current plying song move to seekbar ?
ReplyDeletehow to set Seekbar, change current plying song move to seekbar ?
ReplyDeleteHi Ankit,
ReplyDeleteVery nice player with all functionality. but one issue is when you play music first time and then pause music and lock your phone screen or sleep mode for 20-25 minutes and then song play from notification, songs are not played as well as your application is crashing.
How can I control the progress Bar manually ?
ReplyDeleteHi Ankit
ReplyDeletevery nice tutorial
How to update the progressbar when user seek it to the different position?
Please reply...
Hi Ankit
ReplyDeletevery nice tutorial
How to run the Service on a new thread
hi ankit ...
ReplyDeletethanx for this tutorial it help me alot.
there is any video player tutorial which access all the video from sd card and also have custom media controller for full screen..???
Hey Ankit How I Apply Forward And Backword Control To Your This Media Player.......
ReplyDeleteHi, it's awesome tutorial, Thank you.
ReplyDeletehey!great tutorial.. But could you help me how we display the controllers for apps other than music player like a remote control on the lock screen. Thanks!
ReplyDeletehow to play http url in your music player?
ReplyDeleteCan i get code ?
ReplyDeleteHi Ankit ...
ReplyDeleteIts a grate tutorial,can you please help with streaming the music.
I tried to implement it works fine for first song when i click next song its getting error like"Attempt to call getDuration without a valid mediaplayer" can you please help me with this?
i also getting this error but its not working for me at first song
DeleteHow can I control the progress Bar manually ?
ReplyDeleteUser can change manually and song will play at that position
please Update me ASAP
Thanks in Advance
This comment has been removed by the author.
Deletei think by using this code you cannot apply it because i also have this problem for applying the media player has to be prepared, but in this case the music is playing every second. then how can u apply seek bar if the music is not fully upload
DeleteThis comment has been removed by the author.
ReplyDeletei want to set seekbar progress can any one help me
ReplyDeleteHello All, Yuneeb Arshad
ReplyDeleteI have found the solution for handling seekbar by using mediaplayer.seek method.it will directly adjust the position of seekbar and media also.you just need to write onSeekbarChangeLitener for that in which it contains mediaplayer.seek method.
i have apply this with lot of research but getting error would you like to demonstrate me how it will be done
Deletehow to set Seekbar instead of progressbar
Deletechange current plying song move to seekbar
how to set Seekbar instead of progressbar
ReplyDeletechange current plying song move to seekbar ?
great its working
ReplyDeletehello . thanks for your toturial. it is great and very usefull. but...
ReplyDeletenotification not showning and firing events in android 8...
can you help me?
Please update this code to implement a seekbar instead of progress bar. It also needs shuffle and repeat ToggleButtons. Thank you.
ReplyDeletehi, it is great tutorial but it is not supported on android oreo version please help me..
ReplyDeletethanks for the tips and information..i really appreciate it.. locksmith Leeds
ReplyDeleteLove to read it,Waiting For More new Update and I Already Read your Recent Post its Great Thanks. Artists That Sing and Produce
ReplyDeleteOffering Royalty Free Music for Twitch, Youtube, Facebook Gaming and more. A wide variety of music from Lo-Fi, EDM, Tabletop Gaming Music and so much more! royalty free music
ReplyDeleteThat is really nice to hear. thank you for the update and good luck. bursalagu
ReplyDeleteVery interesting blog. Alot of blogs I see these days don't really provide anything that I'm interested in, but I'm most definately interested in this one. Just thought that I would post and let you know. Talvin Singh
ReplyDeleteI’m going to read this. I’ll be sure to come back. thanks for sharing. and also This article gives the light in which we can observe the reality. this is very nice one and gives indepth information. thanks for this nice article... lil dicky wife
ReplyDeleteGenerally, DVD is the next generation of CD. First of all, DVD differs from CD by its significantly larger capacity. While CD disk can only contain between 650 and 800 megabytes, DVD is able to hold anywhere between 1 and 17 gigabytes, depending on disk type. This storage increase is achieved by reducing laser wavelength. But DVD capacity would never reach more than 4.7 gigabytes if it wasn't possible to make DVD disks double-layered or double-sided. wonnie dual player reviews
ReplyDeletegstar George GStar is an American entrepreneur, rapper, singer-songwriter, and fashion designer. He is known for becoming a self-made millionaire
ReplyDeleteYou have a real ability for writing unique content. I like how you think and the way you represent your views in this article. I agree with your way of thinking. Thank you for sharing. DJ klubille
ReplyDeleteFantastic blog! Do you have any tips and hints for aspiring writers? I’m planning to start my own website soon but I’m a little lost on everything. Would you propose starting with a free platform like WordPress or go for a paid option? There are so many options out there that I’m completely overwhelmed .. Any suggestions? Many thanks! Musica de fondo para videos
ReplyDeleteHey There. I found your blog using msn. This is a very well written article. I’ll be sure to bookmark it and come back to read more of your useful info. Thanks for the post. I’ll definitely return. dj para boda barcelona
ReplyDeleteHello, this weekend is good for me, since this time i am reading this enormous informative article here at my home. Royalty Free Music
ReplyDeleteHouse music is a form of electronic dance music. It originated in what one might call post-disco America. House is a relative of disco music. Some may say that house evolved from disco music. It was also influenced by soul and funk. https://hellorad.io/marketing-strategies/music-marketing-plan-planning-for-a-successful-music-release/
ReplyDeleteThis comment has been removed by the author.
ReplyDeletecontrôleurs DJ Thanks for a very interesting blog. What else may I get that kind of info written in such a perfect approach? I’ve a undertaking that I am simply now operating on, and I have been at the look out for such info.
ReplyDeleteAwesome and interesting article. Great things you've always shared with us. Thanks. Just continue composing this kind of post. btclod
ReplyDeleteWell-Written article. It will be supportive to anyone who utilizes it, including me. Keep doing what you are doing – can't pause to read more posts. Thanks for the precious help. Drop Dead Divine Productions
ReplyDeleteI have read your blog it is very helpful for me. I want to say thanks to you. I have bookmark your site for future updates. London Locksmith
ReplyDeleteFriend, this web site might be fabolous, i just like it. הפצת אלבום
ReplyDeletewonderful! This post guides me a way to enjoy life with music easier! apk.care
ReplyDeleteNice post! This is a very nice blog that I will definitively come back to more times this year! Thanks for informative post. shadoe music
ReplyDeleteYour article is very helpful, by chance I really need this information
ReplyDeletedrakorid
shio togel 2021
Every detail that goes into your corporate event has to be just right, and your event entertainment is no different. You wouldn't dream of holding your corporate event at the local Pizza Hut or you wouldn't expect your attendees to sit at picnic benches to hear your keynote speaker. While these things would be appropriate for a family get together or a company picnic, a corporate event is another matter entirely. Boomplay Music
ReplyDeleteOh God, thank you a thousands times for this tips. I always want to use YouTube, but dont know how to play on lockscreen. I will follow your guide and let's see the results. APK Download
ReplyDeletesound great, i like your list song lol. Thank for sharing useful tips Apkdownload
ReplyDeletePretty good post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your blog posts. Any way I'll be subscribing to your feed and I hope you post again soon. Big thanks for the useful info
ReplyDeleteEmergency Locksmith London
Daisy Limousine provides the best black car service in the tri-state area. We can provide limo service or airport service in New Jersey, New York, Rhode Island, Massachusetts, Pennsylvania, and Connecticut. Our on-time ground transportation service will drive you pretty much from A to B anywhere in the North East of America. Give us a call or book a ride online at your convenience
ReplyDeleteLondon Locksmith
I really loved reading your blog. It was very well authored and easy to understand. Unlike other blogs I have read which are really not that good.Thanks alot! spotify music promotion
ReplyDeleteI found your this post while searching for some related information on blog search...Its a good post..keep posting and update the information. shadoe
ReplyDeleteHow music licensing works. Why it's important and why you need to ensure you license music correctly for your digital content. ایپک موزیک
ReplyDeleteVery good topic, similar texts are I do not know if they are as good as your work out. indian visa passport requirements
ReplyDeleteAdvantage enterprisingly prime quality things - you can see the worth in them all inside: Importer voiture Angleterre Brexit 2021
ReplyDeleteHi, I find reading this article a joy. It is extremely helpful and interesting and very much looking forward to reading more of your work.. Fakaza Music
ReplyDeleteHow music licensing works. Why it's important and why you need to ensure you license music correctly for your digital content. Studio
ReplyDeletepuppies and dogs are very cute, i always love to play with them during my spare time** 먹튀검증업체
ReplyDeleteI have a similar interest this is my page read everything carefully and let me know what you think. mp3 downloader
ReplyDeleteLove to read it,Waiting For More new Update and I Already Read your Recent Post its Great Thanks. Fakaza
ReplyDeleteI am happy to find this post very useful for me, as it contains lot of information. I always prefer to read the quality content and this thing I found in you post. Thanks for sharing. Messianic Music
ReplyDeleteYou know your projects stand out of the herd. There is something special about them. It seems to me all of them are really brilliant! buy spotify monthly listeners
ReplyDeleteI am jovial you take pride in what you write. It makes you stand way out from many other writers that can not push high-quality content like you. soundcloud vs spotify
ReplyDeleteThis content is written very well. Your use of formatting when making your points makes your observations very clear and easy to understand. Thank you. buy spotify followers
ReplyDeleteYou should participate in a contest for probably the greatest blogs on the web. I will recommend this site! Joker99
ReplyDeleteGood Morning, I just stopped by to visit your website and thought I’d say thanks for having me. Rap news
ReplyDeleteCreate a music gallery. Come up with ideas for how to present your new compositions at a music exhibit.Mystery music It should look and feel much like an art exhibit, but be adapted for music.
ReplyDeleteHey friend, it is very well written article, thank you for the valuable and useful information you provide in this post. Keep up the good work! FYI, please check these art, drawing tips and drawing secrets related articles:
ReplyDeleteLittle Singham Drawing
Doodle Art
How To Draw Little Singham
Draw Little Singham Step by Step
Easy Sketches
You can also contact me at arthackers0172@gmail.com for link exchange, article exchange or for advertisement.
Thanks a lot
Dhruv
Howdy are using WordPress for your blog platform? I’m new to the blog world but I’m trying to get started and set up my own. Do you require any html coding expertise to make your own blog? Any help would be really appreciated! 가입시 꽁머니 사이트
ReplyDeletewe would usually buy our bedroom sets from the local retailer which also offers free delivery* is vivo chinese company
ReplyDeleteGood post! I have a random question for you. How do you get your blog indexed by bing? I have a related web blog. check this site
ReplyDeleteGood post! I have a random question for you. How do you get your blog indexed by bing? I have a related web blog. 스포츠중계
ReplyDeleteWhat a fantastic post you have made. I just stopped in to tell you I really enjoyed the read and shall be dropping by from time to time from now on. 스포츠중계
ReplyDeleteI just added your RSS Feed on my RSS reader, it is so nice to read your blog.;:`;* steroids online
ReplyDeleteJust admiring your work and wondering how you managed this blog so well. It’s so remarkable that I can't afford to not go through this valuable information whenever I surf the internet!
ReplyDeleteradio promotion
Thank you, I’ve just been searching for information about this topic for a while and yours is the greatest I’ve discovered till now. But, what in regards to the conclusion? Are you sure concerning the supply? buy steroids
ReplyDeleteThe most comprehensive and very well thought out write up I have found on this subject on the net. Keep on writing, I will keep on coming by to read your new content. This is my fourth time coming by your blog. คาสิโนออนไลน์
ReplyDeleteWe are a group of volunteers and starting a new scheme in our community. Your web site provided us with valuable info to work on. You’ve done an impressive job and our whole community will be thankful to you. สล็อตออนไลน์
ReplyDeleteWe are a group of volunteers and starting a new scheme in our community. Your web site provided us with valuable info to work on. You’ve done an impressive job and our whole community will be thankful to you. 프리서버
ReplyDeleteOh my goodness! a tremendous article dude. Thanks Nevertheless I am experiencing concern with ur rss . Don?t know why Unable to subscribe to it. Is there anybody getting similar rss drawback? Anybody who knows kindly respond. Thnkx check here
ReplyDeleteThanks for writing valuable post regarding the subject. I’m a fan of your site. Keep up the great work. Professional SEO services
ReplyDeletebrass door handles are very elegant looking that is why we always use them at home** mega888
ReplyDeleteRead carefully the complete short article. There is certainly some definitely insightful data here. thanks. “The soul is the captain and ruler of the life of morals.” by Sallust.. steroids for sale
ReplyDeleteI am typically to blogging i truly appreciate your site content. This article has truly peaks my interest. I am about to bookmark your internet site and maintain checking for brand spanking new information. wavesense.info
ReplyDeleteI went over this web site and I conceive you have a lot of great info , saved to my bookmarks (:. somatropin hgh for sale
ReplyDeletecick here โกงเงิน gta v
ReplyDeleteMerely wanted to present you a shout on the valley of the sun, great information. Much appreciated. Great post! Nice one for share. Sign making company
ReplyDeleteI have been exploring for a little for any high quality articles or weblog posts on this kind of space . Exploring in Yahoo I ultimately stumbled upon this site. Studying this information So i’m happy to exhibit that I’ve a very just right uncanny feeling I discovered just what I needed. I so much definitely will make sure to don’t forget this web site and provides it a glance on a constant. hgh online
ReplyDeleteThanks for the blog loaded with so many information. Stopping by your blog helped me to get what I was looking for. with my hoe remix
ReplyDeleteI am usually to blogging i actually appreciate your articles. This content has really peaks my interest. Let me bookmark your web blog and maintain checking for brand new data. steroids for sale
ReplyDeleteWhats up, I’ve been ranking the crap out of “cb auto profits”. where to buy steroids
ReplyDeletehi. I see that you’re most likely involved in creating quality backlinks and stuff. I’m merchandising scrapebox auto approve link lists. Do you wish to trade ? best mattress 2021
ReplyDeleteI have to say i am very impressed with the way you efficiently site and your posts are so informative. You have really have managed to catch the attention of many it seems, keep it up! visit
ReplyDeleteI enjoy you because of every one of your work on this web page. Gloria takes pleasure in participating in internet research and it’s easy to understand why. Most people notice all of the compelling medium you create valuable tips and hints via the website and in addition attract contribution from visitors on that theme then our princess is without a doubt discovering so much. Enjoy the rest of the new year. You’re the one performing a wonderful job. buy injectable steroids online with credit card
ReplyDeleteI was curious if you ever considered changing the page layout of your blog? Its very well written; I love what youve got to say. But maybe you could a little more in the way of content so people could connect with it better. Youve got an awful lot of text for only having one or two pictures. Maybe you could space it out better? buy injectable steroids online with credit card
ReplyDeleteYour positions normally include alot of really up to date info. Where do you come up with this? Just declaring you are very inspiring. Thanks again 먹튀검증
ReplyDeleteIt’s any shame you don’t use a donate button! I’d most certainly donate to this unpaid blog! My partner and i suppose right now i’ll settle for bookmarking and also attaching the Rss feed to be able to my own Yahoo consideration. My partner and i seem forward to be able to innovative updates and definately will share this kind of blog page together with my own Fb group: ) 안전카지노
ReplyDeleteThanks for giving your ideas on this blog. Furthermore, a delusion regarding the banking institutions intentions whenever talking about property foreclosure is that the loan company will not have my repayments. There is a degree of time that the bank will take payments in some places. If you are as well deep inside hole, they will commonly call that you pay the actual payment completely. However, i am not saying that they will not take any sort of repayments at all. In the event you and the financial institution can manage to work something out, this foreclosure course of action may cease. However, if you ever continue to miss payments underneath the new system, the property foreclosures process can pick up from where it was left off. 군산출장안마
ReplyDeleteHow music licensing works. Why it's important and why you need to ensure you license music correctly for your digital content. Скачать песни из тик тока
ReplyDeleteWhat i don’t realize is in reality how you’re no longer actually a lot more well-favored than you might be right now. You are so intelligent. You realize thus considerably when it comes to this topic, made me personally consider it from so many varied angles. Its like women and men are not fascinated unless it’s something to do with Lady gaga! Your own stuffs outstanding. At all times deal with it up! 대전출장안마
ReplyDeleteVery excellent information can be found on weblog . Best mattresses
ReplyDeleteImpressive web site, Distinguished feedback that I can tackle. Im moving forward and may apply to my current job as a pet sitter, which is very enjoyable, but I need to additional expand. Regards. EKmixmaster
ReplyDeleteI like this web site because so much utile stuff on here : D. 슬롯머신
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteHeya i'm for the primary time here. I found this바카라사이트
ReplyDeleteboard and I in finding It really
helpful & it helped me out a lot. I'm hoping to provide something back and help others
like you helped me.
Very excellent information can be found on weblog . social media marketing
ReplyDeleteI simply had to say thanks again. I am not sure the things that I could possibly have carried out without these ways shared by you on my area. It was a very daunting dilemma in my view, however , encountering your professional manner you treated that made me to weep for contentment. I am thankful for the help and expect you comprehend what an amazing job that you’re putting in educating many people through a blog. Most likely you haven’t met any of us. https://downloadlagu321.live
ReplyDeleteHello just wanted to give you a quick heads up. The words in your article seem to be running off the screen in Opera. I’m not sure if this is a formatting issue or something to do with browser compatibility but I figured I’d post to let you know. The design and style look great though! Hope you get the issue resolved soon. Cheers สล็อตค่ายpp
ReplyDeleteThanks for making the honest attempt to talk about this. I feel very sturdy about it and wish to read more. If it’s OK, as you gain extra intensive wisdom, may you thoughts adding more articles similar to this one with additional information? It could be extremely helpful and useful for me and my friends. ลิงก์ย้อนกลับของสล็อตคาสิโน
ReplyDeleteI precisely had to thank you very much all over again. I’m not certain what I could possibly have undertaken without the entire tactics discussed by you about this situation. Entirely was a very difficult problem for me, however , seeing a specialized strategy you handled that took me to cry for joy. Now i’m grateful for the service and as well , wish you realize what an amazing job you happen to be carrying out instructing the rest with the aid of your blog. I’m certain you haven’t got to know all of us. evolution gaming
ReplyDeleteYour blog is one of a kind, i love the way you organize the topics.,`:*~ rikmod rikmod.com
ReplyDeleteWhen I originally commented I clicked the -Notify me when new comments are added- checkbox and after this whenever a comment is added I get four emails with the same comment. Could there be however you possibly can get rid of me from that service? Thanks! rigrov rigrov.com
ReplyDeleteAwesome article, it was exceptionally helpful! I simply began in this and I'm becoming more acquainted with it better! Cheers, keep doing awesome! Learn Hindustani Classical Music
ReplyDeleteRecently a Christie's art sale became the highest auction in history. The sale included works by Jackson Pollock, Roy Lichtenstein and Jean-Michel Basquiat, among others and in total generated $495 million. שירים יפים בעברית
ReplyDeleteHi there. Very cool site!! Guy .. Beautiful .. Wonderful .. I will bookmark your website and take the feeds additionally…I am glad to locate so much useful info right here in the article. Thanks for sharing… judi online terpercaya
ReplyDeleteExcellent website you have here, so much cool information!..
ReplyDeletebeat instrumentals
Impressive web site, Distinguished feedback that I can tackle. Im moving forward and may apply to my current job as a pet sitter, which is very enjoyable, but I need to additional expand. Regards. หวยชัดเจน
ReplyDeleteYoure so cool! I dont suppose Ive read anything such as this just before. So nice to locate somebody with some original ideas on this subject. realy we appreciate you starting this up. this web site are some things that is needed on-line, a person with a little originality. beneficial project for bringing new stuff to the world wide web! บาคาร่าออนไลน์
ReplyDeleteI like the way you conduct your posts. Have a nice Thursday! Fsbo
ReplyDeleteHello there, just became alert to your blog through Google, and found that it’s truly informative. I am going to watch out for brussels. I’ll appreciate if you continue this in future. Lots of people will be benefited from your writing. Cheers! 축구중계
ReplyDeletewhoah this weblog is excellent i love studying your posts. Keep up the good work! You recognize, many individuals are looking around for this info, you could help them greatly. ufabet เข้าสู่ระบบ
ReplyDeleteSomeone essentially assist to make severely posts I might state. That is the very first time I frequented your website page and so far? I surprised with the analysis you made to create this particular submit incredible. Magnificent task! VOICE OVER AGENCY
ReplyDeleteThis is a list of some of the world's music genre and their definitions. Apala - Originally derived from the Yoruba people of Nigeria. It is a percussion-based style that developed in the late 1930s, when it was used to wake worshippers after fasting during the Islamic holy month of Ramadan. MUSIC CREATIVE AGENCY
ReplyDeleteThis is a list of some of the world's music genre and their definitions. Apala - Originally derived from the Yoruba people of Nigeria. It is a percussion-based style that developed in the late 1930s, when it was used to wake worshippers after fasting during the Islamic holy month of Ramadan. BUSINESS CONSULTANCY MANCHESTER
ReplyDeleteSocial Media Marketing seems to be the latest buzz word for anyone looking to increase their online presence and sales, but is Social Media Marketing all it is cracked up to be? Social Media Marketing companies are now springing up all over the place these days and they are telling anyone that will listen about how incredibly important social media like Facebook twitter and YouTube are to your business but, for the average small to medium sized business, does Social media marketing really live up to all the hype? SOCIAL MEDIA AGENCY MANCHESTER
ReplyDeleteI am glad for writing to let you know of the great experience my friend’s girl went through reading the blog. She figured out several pieces, most notably how it is like to have a great helping style to get many more smoothly completely grasp several specialized issues. You really did more than visitors’ expectations. Thank you for displaying those good, dependable, explanatory and in addition cool guidance on this topic to Lizeth. slot
ReplyDeleteSuperbly written article, if only all bloggers offered the same content as you, the internet would be a far better place.. Satta king fast
ReplyDeletegreat, happy to heard it good! thanks for bring me useful information
ReplyDeleteVisit my homepage at here
Very efficiently written information. It will be beneficial to anybody who utilizes it, including me. Keep up the good work. For sure i will check out more posts. This site seems to get a good amount of visitors. MUSIC MARKETING AGENCY
ReplyDeleteI wanted to thank you for this great read!! I definitely enjoying every little bit of it I have you bookmarked to check out new stuff you post. nft shifter
ReplyDeleteThe simple fact of the matter is that most people search online before making local small business purchases. If you aren't online, you aren't an option. Even if you are online, if you aren't on the front page of Google for the keywords consumers use to find products and services just like the ones you sell, you'll likely never be found. INSTAGRAM MANAGEMENT AGENCY
ReplyDeleteI am glad for writing to let you know of the great experience my friend’s girl went through reading the blog. She figured out several pieces, most notably how it is like to have a great helping style to get many more smoothly completely grasp several specialized issues. You really did more than visitors’ expectations. Thank you for displaying those good, dependable, explanatory and in addition cool guidance on this topic to Lizeth. 백링크
ReplyDeletehowdy, I am ranking the crap out of “free justin bieber stuff”. judi slot online 889
ReplyDeleteHello there, just became aware of your blog through Google, and found that it is truly informative. I’m going to watch out for brussels. I’ll be grateful if you continue this in future. Numerous people will be benefited from your writing. Cheers! buy backlinks in USA
ReplyDeleteExcellent site. Plenty of useful info here. I’m sending it to several pals ans also sharing in delicious. And obviously, thank you to your effort! สล็อตxo
ReplyDeleteGood web site! I truly love how it is simple on my eyes and the data are well written. I am wondering how I could be notified whenever a new post has been made. I have subscribed to your RSS which must do the trick! Have a nice day! Layanan Komentar Blog
ReplyDeleteI’d must consult you here. Which is not some thing It’s my job to do! I spend time reading an article that may get people to think. Also, many thanks for permitting me to comment! 작업대출사이트
ReplyDeleteThere are a few fascinating points with time in this post but I do not know if I see every one of them center to heart. There may be some validity but Let me take hold opinion until I explore it further. Good write-up , thanks and then we want far more! Included in FeedBurner likewise 롤듀오
ReplyDeleteExcellent site. Plenty of useful info here. I’m sending it to several pals ans also sharing in delicious. And obviously, thank you to your effort! สโบเบ็ท
ReplyDeleteYou created some decent points there. I looked on the internet for that issue and found most individuals will go together with using your internet site. Used Wholesale Shoes
ReplyDeleteSeriously very good contribution, I really depend on up-dates of your stuff. 토토커뮤니티
ReplyDeleteI just added this blog to my google reader, great stuff. Cannot get enough! 링크 빌딩
ReplyDeleteThis is such a great resource that you are providing and you give it away for free. I love seeing blog that understand the value of providing a quality resource for free. yichuangscreen.com/product/advertising-player
ReplyDeleteМузыкальный фестиваль Святого Августина предлагает местным ...Песни 2023
ReplyDeleteПрофессионалы музыкальной индустрии (слева направо): Арлис Олбриттон, Дэйв Брейнард, Люк Пирс, Брейн Трэгер и Мэтт Шей участвуют в панели.
A festive event is coming to an end in Ufa on Sovetskaya Square — the final of the first All-Russian open song contest "Time of Heroes". The names of the winners have just been announced.
ReplyDeleteIn the nomination "Author of words", the 3rd place was awarded to Maxim Popov (Cheboksary), the 2nd place to Alexey Podshivalov (Ivanovo, Ivanovo region), the 1st place to Igor Russians (Kirov, Kirov region) and Sagit Yakupov (Bolsheustikinskoye village of the Mechetlinsky district of the Republic of Bashkortostan). https://sound-library.net/
Vinyl stickers are commonly used for promotional purposes. But they can also be used for informational or decorative services. guide about the vinyl stickers
ReplyDeleteGreat Post and very informative, Thanks for sharing with us! Locked out Leeds
ReplyDeleteThanks for sharing this informative blog with us! Emergency Locksmith Leeds
ReplyDeleteThanks for sharing such an amazing post with us. Lock upgrade Leeds
ReplyDeleteBeautiful post. Thank you so much for sharing a Useful tips. Door lock repair Leeds
ReplyDeleteThanks you so much for sharing such information. Glass replacement Leeds
ReplyDeleteNice post. Thanks for sharing this informative blog with us. Burglary repairs Leeds
ReplyDeleteThis comment has been removed by the author.
ReplyDelete