Sunday 20 July 2014

Music Player with Notification and Lock Screen Controls


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.


Download Source Code Download

Project Hierarchy
1)  Get the list of Songs present in SD-Card.
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;
}
Add permission in Manifest-
<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.OnAudioFocusChangeListener
Firstly 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>



184 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. HI, I am using 'rtsp' streaming and getting a issue i.e. Player is getting stuck for some time on RemoteControlClient and NotificationUpdate.

    ReplyDelete
  3. Hi, Brilliant tutorial, Thank you.

    I 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.

    ReplyDelete
    Replies
    1. Just after posting, I found that I need to call MediaScanner to rescan the library.

      Anyone with similar problem, read here: http://stackoverflow.com/questions/2170214/image-saved-to-sdcard-doesnt-appear-in-androids-gallery-app

      Sorry about this.

      Delete
  4. hey thanx for this gr8 tutorial... i would love some help though on how to organise the music according to artists and albums

    ReplyDelete
    Replies
    1. https://www.dropbox.com/s/jgjd94xqdicr221/LibMedia.java?dl=0

      Delete
    2. Hey 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.

      Delete
    3. or just the LogUtils class. thank you very much

      Delete
    4. You can email it to my email brianmigel@gmail.com

      Delete
    5. Hey 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

      Delete
    6. how to get the songs from online ie)like gaana

      Delete
    7. Gaana have its own API. You can try Rdio.

      Delete
  5. This comment has been removed by the author.

    ReplyDelete
  6. hi, can I use it from API 8 ?!!

    ReplyDelete
  7. Hey...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....

    ReplyDelete
  8. Very 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.

    ReplyDelete
  9. Nice Player. But how to add seekbar to seek the current playing song ?

    ReplyDelete
    Replies
    1. hiii jaimin you can solve this problem than help me how to solve it ?

      Delete
  10. This comment has been removed by the author.

    ReplyDelete
  11. how to set Seekbar, change current plying song move to seekbar ?

    ReplyDelete
  12. how to set Seekbar, change current plying song move to seekbar ?

    ReplyDelete
  13. Hi Ankit,
    Very 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.

    ReplyDelete
  14. How can I control the progress Bar manually ?

    ReplyDelete
  15. Hi Ankit
    very nice tutorial
    How to update the progressbar when user seek it to the different position?
    Please reply...

    ReplyDelete
  16. Hi Ankit
    very nice tutorial
    How to run the Service on a new thread

    ReplyDelete
  17. hi ankit ...
    thanx 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..???

    ReplyDelete
  18. Hey Ankit How I Apply Forward And Backword Control To Your This Media Player.......

    ReplyDelete
  19. Hi, it's awesome tutorial, Thank you.

    ReplyDelete
  20. hey!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!

    ReplyDelete
  21. how to play http url in your music player?

    ReplyDelete
  22. Hi Ankit ...
    Its 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?

    ReplyDelete
    Replies
    1. i also getting this error but its not working for me at first song

      Delete
  23. How can I control the progress Bar manually ?
    User can change manually and song will play at that position
    please Update me ASAP

    Thanks in Advance

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. i 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

      Delete
  24. This comment has been removed by the author.

    ReplyDelete
  25. i want to set seekbar progress can any one help me

    ReplyDelete
  26. Hello All, Yuneeb Arshad

    I 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.

    ReplyDelete
    Replies
    1. i have apply this with lot of research but getting error would you like to demonstrate me how it will be done

      Delete
    2. how to set Seekbar instead of progressbar
      change current plying song move to seekbar

      Delete
  27. how to set Seekbar instead of progressbar
    change current plying song move to seekbar ?

    ReplyDelete
  28. hello . thanks for your toturial. it is great and very usefull. but...
    notification not showning and firing events in android 8...
    can you help me?

    ReplyDelete
  29. Please update this code to implement a seekbar instead of progress bar. It also needs shuffle and repeat ToggleButtons. Thank you.

    ReplyDelete
  30. hi, it is great tutorial but it is not supported on android oreo version please help me..

    ReplyDelete
  31. thanks for the tips and information..i really appreciate it.. locksmith Leeds

    ReplyDelete
  32. Love to read it,Waiting For More new Update and I Already Read your Recent Post its Great Thanks. Artists That Sing and Produce

    ReplyDelete
  33. Offering 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

    ReplyDelete
  34. That is really nice to hear. thank you for the update and good luck. bursalagu

    ReplyDelete
  35. Very 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

    ReplyDelete
  36. I’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

    ReplyDelete
  37. With this site it is possible to examine my own passions, compose one thing specific. how to chart on itunes

    ReplyDelete
  38. Generally, 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

    ReplyDelete
  39. gstar George GStar is an American entrepreneur, rapper, singer-songwriter, and fashion designer. He is known for becoming a self-made millionaire

    ReplyDelete
  40. You 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

    ReplyDelete
  41. Fantastic 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

    ReplyDelete
  42. Hey 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

    ReplyDelete
  43. Hello, this weekend is good for me, since this time i am reading this enormous informative article here at my home. Royalty Free Music

    ReplyDelete
  44. House 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/

    ReplyDelete
  45. This comment has been removed by the author.

    ReplyDelete
  46. contrô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.

    ReplyDelete
  47. Awesome and interesting article. Great things you've always shared with us. Thanks. Just continue composing this kind of post. btclod

    ReplyDelete
  48. Well-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

    ReplyDelete
  49. I 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

    ReplyDelete
  50. Friend, this web site might be fabolous, i just like it. הפצת אלבום

    ReplyDelete
  51. wonderful! This post guides me a way to enjoy life with music easier! apk.care

    ReplyDelete
  52. Nice post! This is a very nice blog that I will definitively come back to more times this year! Thanks for informative post. shadoe music

    ReplyDelete
  53. Your article is very helpful, by chance I really need this information
    drakorid
    shio togel 2021

    ReplyDelete
  54. 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

    ReplyDelete
  55. Oh 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

    ReplyDelete
  56. sound great, i like your list song lol. Thank for sharing useful tips Apkdownload

    ReplyDelete
  57. Pretty 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
    Emergency Locksmith London

    ReplyDelete
  58. 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
    London Locksmith

    ReplyDelete
  59. 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

    ReplyDelete
  60. I found your this post while searching for some related information on blog search...Its a good post..keep posting and update the information. shadoe

    ReplyDelete
  61. How music licensing works. Why it's important and why you need to ensure you license music correctly for your digital content. ایپک موزیک

    ReplyDelete
  62. Very good topic, similar texts are I do not know if they are as good as your work out. indian visa passport requirements

    ReplyDelete
  63. Advantage enterprisingly prime quality things - you can see the worth in them all inside: Importer voiture Angleterre Brexit 2021

    ReplyDelete
  64. Hi, 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

    ReplyDelete
  65. How music licensing works. Why it's important and why you need to ensure you license music correctly for your digital content. Studio

    ReplyDelete
  66. puppies and dogs are very cute, i always love to play with them during my spare time** 먹튀검증업체

    ReplyDelete
  67. I have a similar interest this is my page read everything carefully and let me know what you think. mp3 downloader

    ReplyDelete
  68. Love to read it,Waiting For More new Update and I Already Read your Recent Post its Great Thanks. Fakaza

    ReplyDelete
  69. I 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

    ReplyDelete
  70. You 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

    ReplyDelete
  71. I 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

    ReplyDelete
  72. This 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

    ReplyDelete
  73. You should participate in a contest for probably the greatest blogs on the web. I will recommend this site! Joker99

    ReplyDelete
  74. Good Morning, I just stopped by to visit your website and thought I’d say thanks for having me. Rap news

    ReplyDelete
  75. Create 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.

    ReplyDelete
  76. Hey 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:

    Little 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

    ReplyDelete
  77. 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! 가입시 꽁머니 사이트

    ReplyDelete
  78. we would usually buy our bedroom sets from the local retailer which also offers free delivery* is vivo chinese company

    ReplyDelete
  79. Good 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

    ReplyDelete
  80. Good post! I have a random question for you. How do you get your blog indexed by bing? I have a related web blog. 스포츠중계

    ReplyDelete
  81. What 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. 스포츠중계

    ReplyDelete
  82. I just added your RSS Feed on my RSS reader, it is so nice to read your blog.;:`;* steroids online

    ReplyDelete
  83. Just 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!
    radio promotion

    ReplyDelete
  84. 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

    ReplyDelete
  85. The 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. คาสิโนออนไลน์

    ReplyDelete
  86. We 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. สล็อตออนไลน์

    ReplyDelete
  87. We 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. 프리서버

    ReplyDelete
  88. Oh 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

    ReplyDelete
  89. Thanks for writing valuable post regarding the subject. I’m a fan of your site. Keep up the great work. Professional SEO services

    ReplyDelete
  90. brass door handles are very elegant looking that is why we always use them at home** mega888

    ReplyDelete
  91. Read 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

    ReplyDelete
  92. I 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

    ReplyDelete
  93. I went over this web site and I conceive you have a lot of great info , saved to my bookmarks (:. somatropin hgh for sale

    ReplyDelete
  94. Merely 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

    ReplyDelete
  95. I 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

    ReplyDelete
  96. Thanks 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

    ReplyDelete
  97. I 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

    ReplyDelete
  98. Whats up, I’ve been ranking the crap out of “cb auto profits”. where to buy steroids

    ReplyDelete
  99. hi. 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

    ReplyDelete
  100. I 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

    ReplyDelete
  101. I 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

    ReplyDelete
  102. I 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

    ReplyDelete
  103. Your 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 먹튀검증

    ReplyDelete
  104. It’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: ) 안전카지노

    ReplyDelete
  105. Thanks 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. 군산출장안마

    ReplyDelete
  106. How music licensing works. Why it's important and why you need to ensure you license music correctly for your digital content. Скачать песни из тик тока

    ReplyDelete
  107. What 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! 대전출장안마

    ReplyDelete
  108. Very excellent information can be found on weblog . Best mattresses

    ReplyDelete
  109. 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. EKmixmaster

    ReplyDelete
  110. I like this web site because so much utile stuff on here : D. 슬롯머신

    ReplyDelete
  111. This comment has been removed by the author.

    ReplyDelete
  112. Heya i'm for the primary time here. I found this바카라사이트
    board 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.

    ReplyDelete
  113. Very excellent information can be found on weblog . social media marketing

    ReplyDelete
  114. I 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

    ReplyDelete
  115. Hello 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

    ReplyDelete
  116. Thanks 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. ลิงก์ย้อนกลับของสล็อตคาสิโน

    ReplyDelete
  117. I 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

    ReplyDelete
  118. I felt very happy while reading this site. This was really very informative site for me. I really liked it. This was really a cordial post. Thanks a lot!. hip hop instrumentals

    ReplyDelete
  119. I really like your take on the issue. I now have a clear idea on what this matter is all about.. beat instrumentals

    ReplyDelete
  120. Your blog is one of a kind, i love the way you organize the topics.,`:*~ rikmod rikmod.com

    ReplyDelete
  121. When 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

    ReplyDelete
  122. Awesome 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

    ReplyDelete
  123. Recently 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. שירים יפים בעברית

    ReplyDelete
  124. Hi 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

    ReplyDelete
  125. Excellent website you have here, so much cool information!..
    beat instrumentals

    ReplyDelete
  126. 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. หวยชัดเจน

    ReplyDelete
  127. Youre 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! บาคาร่าออนไลน์

    ReplyDelete
  128. I am able to advocate generally quality and in some cases in charge points, subsequently notice it: ifvod

    ReplyDelete
  129. I like the way you conduct your posts. Have a nice Thursday! Fsbo

    ReplyDelete
  130. Hello 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! 축구중계

    ReplyDelete
  131. whoah 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 เข้าสู่ระบบ

    ReplyDelete
  132. Someone 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

    ReplyDelete
  133. This 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

    ReplyDelete
  134. This 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

    ReplyDelete
  135. Social 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

    ReplyDelete
  136. I 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

    ReplyDelete
  137. Superbly written article, if only all bloggers offered the same content as you, the internet would be a far better place.. Satta king fast

    ReplyDelete
  138. great, happy to heard it good! thanks for bring me useful information
    Visit my homepage at here

    ReplyDelete
  139. 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

    ReplyDelete
  140. I 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

    ReplyDelete
  141. The 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

    ReplyDelete
  142. I 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. 백링크

    ReplyDelete
  143. howdy, I am ranking the crap out of “free justin bieber stuff”. judi slot online 889

    ReplyDelete
  144. Hello 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

    ReplyDelete
  145. Excellent 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

    ReplyDelete
  146. Good 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

    ReplyDelete
  147. I’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! 작업대출사이트

    ReplyDelete
  148. There 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 롤듀오

    ReplyDelete
  149. Excellent 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! สโบเบ็ท

    ReplyDelete
  150. You 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

    ReplyDelete
  151. Seriously very good contribution, I really depend on up-dates of your stuff. 토토커뮤니티

    ReplyDelete
  152. I just added this blog to my google reader, great stuff. Cannot get enough! 링크 빌딩

    ReplyDelete
  153. This 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
  154. Музыкальный фестиваль Святого Августина предлагает местным ...Песни 2023
    Профессионалы музыкальной индустрии (слева направо): Арлис Олбриттон, Дэйв Брейнард, Люк Пирс, Брейн Трэгер и Мэтт Шей участвуют в панели.

    ReplyDelete
  155. 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.

    In 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/

    ReplyDelete
  156. Vinyl stickers are commonly used for promotional purposes. But they can also be used for informational or decorative services. guide about the vinyl stickers

    ReplyDelete
  157. Great Post and very informative, Thanks for sharing with us! Locked out Leeds

    ReplyDelete
  158. Thanks for sharing this informative blog with us! Emergency Locksmith Leeds

    ReplyDelete
  159. Thanks for sharing such an amazing post with us. Lock upgrade Leeds

    ReplyDelete
  160. Beautiful post. Thank you so much for sharing a Useful tips. Door lock repair Leeds

    ReplyDelete
  161. Nice post. Thanks for sharing this informative blog with us. Burglary repairs Leeds

    ReplyDelete
  162. Ready-to-wear dresses offer convenience and style, catering to various occasions with ease. From casual day outings to formal events, these dresses come in a range of designs, colors, and sizes to suit every preference. With minimal effort required, they provide a quick and fashionable solution for any wardrobe need.

    ReplyDelete
  163. Discover the best serum for dark spots in pakistan, specially formulated to fade hyperpigmentation and even out skin tone. Our potent blend of brightening ingredients works tirelessly to diminish stubborn dark spots, revealing a luminous complexion. Transform your skin with our top-rated serum and reclaim a youthful, radiant glow.

    ReplyDelete
  164. In Pakistan, finding the best moisturizer for dry skin in pakistan is essential for combating the harsh climate and maintaining skin hydration. Brands offer a range of options infused with hydrating ingredients like hyaluronic acid and shea butter, catering to diverse needs. These moisturizers provide intense nourishment, restoring moisture levels and promoting healthy, supple skin in Pakistan's varied environments.

    ReplyDelete