'How to have a single instance of exoPlayer in a background?

I have almost a week figuring out how should I have one instance of exoplayer in background. I want to use this instance in a playerview and in notification as well. Problem I am facing now, the player plays well, after a time it pauses (to release resource I guess), but when i click play it plays again, when i click other oudio, I get two audio playing at same time. Here are my codes.

------------------------ BACKGROUND SERVICE --------------------------------------

public class BackgroundPlayingService extends Service {
public static PlayerNotificationManager playerNotificationManager;
public static ExoPlayer exoPlayer;
@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (this.exoPlayer == null){
        createPlayer();
    }
    /////////////////THIS WAS ADDED LATER
    return START_STICKY;
}

@Override
public void onCreate() {
    super.onCreate();
   

}

@Override
public void onDestroy() {
    super.onDestroy();
    exoPlayer.pause();
    exoPlayer = null;
    playerNotificationManager.setPlayer(null);
}

private void createPlayer(){
    exoPlayer = new ExoPlayer.Builder(this).build();
    MediaItem mediaItem;
    try {
        mediaItem = MediaItem.fromUri(Uri.parse(DataUtility.playingUrl));
    }catch (Exception e){
        mediaItem = MediaItem.fromUri(Uri.parse("https://server13.mp3quran.net/husr/062.mp3"));
    }

    exoPlayer.setMediaItem(mediaItem);
    exoPlayer.prepare();
    exoPlayer.addListener(new Player.Listener() {


        @Override
        public void onPlaybackStateChanged(int playbackState) {
            Player.Listener.super.onPlaybackStateChanged(playbackState);
            try {
                if (ThePlayingActivity.dialog.isShowing()){
                    ThePlayingActivity.dialog.dismiss();}
            }catch (Exception ignore){

            }

            if (playbackState==Player.STATE_READY){
                try {
                    ThePlayingActivity.downloadBtn.setVisibility(View.VISIBLE);
                    showNotification();
                }catch (Exception ignore){

                }


            }

            if (playbackState == Player.STATE_BUFFERING) {
                try {
                    ThePlayingActivity.myProgress.setVisibility(View.VISIBLE);

                }catch (Exception e){

                }

            } else {
                try {
                    ThePlayingActivity.myProgress.setVisibility(View.GONE);
                }catch (Exception e){

                }

            }

        }

        @Override
        public void onIsLoadingChanged(boolean isLoading) {
            Player.Listener.super.onIsLoadingChanged(isLoading);

        }

        @Override
        public void onPlayerError(PlaybackException error) {
            Player.Listener.super.onPlayerError(error);
            try {
                if (ThePlayingActivity.dialog.isShowing()){
                    ThePlayingActivity.dialog.dismiss();

                }
                playerNotificationManager.setPlayer(null);
            }catch (Exception ignore){

            }

        }
    });
    exoPlayer.play();
    try {
        ThePlayingActivity.myPlayerView.setPlayer(exoPlayer);
    }catch (Exception e){
        Log.d("background", "createPlayer: set player to view"+e.getLocalizedMessage());
    }



}

public static void setNewPlayeData(){
    MediaItem mediaItem = MediaItem.fromUri(Uri.parse(DataUtility.playingUrl));
    exoPlayer.setMediaItem(mediaItem);
    exoPlayer.prepare();
    ThePlayingActivity.myPlayerView.setPlayer(exoPlayer);
    try {
        ThePlayingActivity.myPlayerView.setPlayer(exoPlayer);
    }catch (Exception e){
        Log.d("background", "createPlayer: set player to view"+e.getLocalizedMessage());
    }


}

public void showNotification() {
    playerNotificationManager = new PlayerNotificationManager.Builder(this, 151,
            this.getResources().getString(R.string.app_name))
            .setChannelNameResourceId(R.string.app_name)
            .setChannelImportance(IMPORTANCE_HIGH)
            .setMediaDescriptionAdapter(new PlayerNotificationManager.MediaDescriptionAdapter() {
                @Override
                public CharSequence getCurrentContentTitle(Player player) {
                    return player.getCurrentMediaItem().mediaMetadata.displayTitle;
                }

                @Nullable
                @Override
                public PendingIntent createCurrentContentIntent(Player player) {
                    return null;
                }

                @Nullable
                @Override
                public CharSequence getCurrentContentText(Player player) {
                    return Objects.requireNonNull(player.getCurrentMediaItem()).mediaMetadata.artist;
                }

                @Nullable
                @Override
                public Bitmap getCurrentLargeIcon(Player player, PlayerNotificationManager.BitmapCallback callback) {

                    return null;
                }


            }).setNotificationListener(new PlayerNotificationManager.NotificationListener() {
                @Override
                public void onNotificationCancelled(int notificationId, boolean dismissedByUser) {


                }

                @Override
                public void onNotificationPosted(int notificationId, Notification notification, boolean ongoing) {
                    PlayerNotificationManager.NotificationListener.super.onNotificationPosted(notificationId, notification, ongoing);
                }
            })

            .build();
    playerNotificationManager.setUseStopAction(false);
    try {
        playerNotificationManager.setPlayer(exoPlayer);
    }catch (Exception e){

    }
}

} -----------------------HERE IS THE ACTIVITY WITH PLAYER ----------------------------------

public class ThePlayingActivity extends AppCompatActivity {
private static final int PERMISION_STORAGE_CODE = 100;
private ProgressBar  downloadingProgress;
public static ProgressBar myProgress;
public static Dialog dialog;
private ConstraintLayout layoutForSnack;
long downloadId;
private PowerManager powerManager;
private PowerManager.WakeLock wakeLock;
String myurl;
public static PlayerControlView myPlayerView;
private TextView currentPlaying, downloadingTv;
public static Button downloadBtn;
private String thePlayingSura;
private final BroadcastReceiver onDownloadComplete = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID,-1);
        if (downloadId == id){
            downloadingProgress.setVisibility(View.GONE);
            downloadingTv.setVisibility(View.GONE);
            downloadBtn.setText("DOWNLOADED");
            downloadBtn.setBackgroundColor(Color.TRANSPARENT);
            downloadBtn.setTextColor(Color.BLACK);
            downloadBtn.setClickable(false);
            Toast.makeText(context, "DOWNLOAD COMPLETED", Toast.LENGTH_SHORT).show();
        }
    }
};
@SuppressLint("SetTextI18n")
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_the_playing);
    myPlayerView = findViewById(R.id.playerView);
    Intent dataIntent = getIntent();
    myurl = dataIntent.getStringExtra("theUrl");
    if (BackgroundPlayingService.exoPlayer == null){
    startService();}else{
        BackgroundPlayingService.setNewPlayeData();
        myPlayerView.setPlayer(BackgroundPlayingService.exoPlayer);
    }
    keepActivityAlive();
    registerReceiver(onDownloadComplete,new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
    downloadingProgress = findViewById(R.id.downloadProgress);
    downloadingTv = findViewById(R.id.downloadingWaitTv);
    currentPlaying = findViewById(R.id.currentPlaying);
    downloadBtn = findViewById(R.id.downloadbtn);
    downloadBtn.setVisibility(View.GONE);
    myProgress = findViewById(R.id.progressBar2);
    myProgress.setVisibility(View.GONE);
    layoutForSnack = findViewById(R.id.constraintLayout);

    downloadingProgress.setVisibility(View.GONE);
    downloadingTv.setVisibility(View.GONE);


    thePlayingSura = dataIntent.getStringExtra("sendSuraName");
    currentPlaying.setText(thePlayingSura+" - " + DataUtility.theKariName);

    /////////////end of ids
  showLoadingDialog();


    /////////////////download
    downloadBtn.setOnClickListener(view -> {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
            if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED){
                //todo ask permission
                String permissions[] = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
                requestPermissions(permissions,PERMISION_STORAGE_CODE);
            }else{
                downloadStaffs();

            }
        }else {
            //TODO DOWNLOAD
            downloadStaffs();
        }



    });

    /////////////////////////////////////////////////////////////////////////////////////





    ///////////////////////////////////////////////////////////////////////////////////////////



}




@Override
public void onBackPressed() {
    super.onBackPressed();
//todo fire service (may be)
}

private void showLoadingDialog() {
    dialog = new Dialog(ThePlayingActivity.this);
    dialog.setContentView(R.layout.dialog_loading_quran);
    dialog.setCancelable(false);
    dialog.show();
}

private void showSnackBar() {
    Snackbar snackbar = Snackbar.make(layoutForSnack, "THERE WAS ON ERROR, CHECK YOUR INTERNET CONNECTION", Snackbar.LENGTH_INDEFINITE);
    snackbar.setAction("RETRY", view -> {

    });
    snackbar.setActionTextColor(Color.YELLOW);
    snackbar.show();
}



@Override
protected void onStop() {
    super.onStop();

}


@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    switch (requestCode){
        case PERMISION_STORAGE_CODE:{
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                // we have permission
                //todo Download
                downloadStaffs();
            }else{
                Toast.makeText(ThePlayingActivity.this , "PERMISSION DENIED... CAN NOT DOWNLOAD", Toast.LENGTH_SHORT).show();
            }
        }
    }
}


@Override
protected void onDestroy() {
    super.onDestroy();
    unregisterReceiver(onDownloadComplete);
    try {
        if (wakeLock.isHeld()){
            wakeLock.release();}
    }catch (Exception ignore){

    }

}


private void downloadStaffs(){

    DownloadManager.Request request = new DownloadManager.Request(Uri.parse(DataUtility.playingUrl));

    request.setDescription("Download File");
    request.setTitle(thePlayingSura);
    request.allowScanningByMediaScanner();
    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
    request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, thePlayingSura+" - "+ DataUtility.theKariName+".mp3");

    final DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);

    final long downloadId = manager.enqueue(request);
    this.downloadId = downloadId;

    final ProgressBar mProgressBar = (ProgressBar) findViewById(R.id.downloadProgress);
    downloadingTv.setVisibility(View.VISIBLE);
    mProgressBar.setVisibility(View.VISIBLE);

    new Thread(new Runnable() {

        @SuppressLint("Range")
        @Override
        public void run() {

            boolean downloading = true;

            while (downloading) {

                DownloadManager.Query q = new DownloadManager.Query();
                q.setFilterById(downloadId);

                Cursor cursor = manager.query(q);
                cursor.moveToFirst();
                @SuppressLint("Range") int bytes_downloaded = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
                @SuppressLint("Range") int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));

                if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
                    downloading = false;
                }

                final double dl_progress = (int) ((bytes_downloaded * 100l) / bytes_total);

                runOnUiThread(new Runnable() {


                    @Override
                    public void run() {
                        mProgressBar.setProgress((int) dl_progress);


                    }
                });

                Log.d("MESSAGES", statusMessage(cursor));
                cursor.close();
            }

        }
    }).start();
}
@SuppressLint("Range")
private String statusMessage(Cursor c) {
    String msg = "???";

    switch (c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS))) {
        case DownloadManager.STATUS_FAILED:
            msg = "Download failed!";
            break;

        case DownloadManager.STATUS_PAUSED:
            msg = "Download paused!";
            break;

        case DownloadManager.STATUS_PENDING:
            msg = "Download pending!";
            break;

        case DownloadManager.STATUS_RUNNING:
            msg = "Download in progress!";
            break;

        case DownloadManager.STATUS_SUCCESSFUL:
            msg = "Download complete!";
            break;

        default:
            msg = "Download is nowhere in sight";
            break;
    }

    return (msg);
}



}


private void keepActivityAlive(){
    powerManager = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
    wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"QuranAudio:WakeLock");
}

private  void startService(){
    Intent i = new Intent(this, BackgroundPlayingService.class);
    startService(i);
}

}



Solution 1:[1]

I figured it out.

I had to keep most of my business inside in onStartCommand

public class BackgroundPlayingService extends Service {
public static final String TAG = "bck_service";
public static ExoPlayer player;
public static PlayerNotificationManager playerNotificationManager;

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    String url = DataUtility.playingUrl;
    if (url==null){
      url = "https://server8.mp3quran.net/afs/Rewayat-AlDorai-A-n-Al-Kisa-ai/025.mp3";
    }
    if (player == null){
        player = createPlayerIfNull();
        MediaItem mediaItem = MediaItem.fromUri(Uri.parse(url));
        player.setMediaItem(mediaItem);
        player.prepare();
        player.addListener(new Player.Listener() {

            @Override
            public void onEvents(Player player, Player.Events events) {
            }

            @Override
            public void onPlaybackStateChanged(int playbackState) {
                Player.Listener.super.onPlaybackStateChanged(playbackState);
                try {
                    if (ThePlayingActivity.dialog.isShowing()){
                        ThePlayingActivity.dialog.dismiss();}
                }catch (Exception ignore){

                }

                if (playbackState==Player.STATE_READY){
                    try {
                        ThePlayingActivity.downloadBtn.setVisibility(View.VISIBLE);
                        showNotification();
                    }catch (Exception ignore){

                    }


                }

                if (playbackState == Player.STATE_BUFFERING) {
                    try {
                        ThePlayingActivity.myProgress.setVisibility(View.VISIBLE);

                    }catch (Exception e){

                    }

                } else {
                    try {
                        ThePlayingActivity.myProgress.setVisibility(View.GONE);
                    }catch (Exception e){

                    }

                }

            }

            @Override
            public void onIsLoadingChanged(boolean isLoading) {
                Player.Listener.super.onIsLoadingChanged(isLoading);

            }

            @Override
            public void onPlayerError(PlaybackException error) {
                Player.Listener.super.onPlayerError(error);
                try {
                    if (ThePlayingActivity.dialog.isShowing()){
                        ThePlayingActivity.dialog.dismiss();}
                }catch (Exception ignore){

                }

            }
        });
        player.play();

        try {
            ThePlayingActivity.myPlayerView.setPlayer(player);

        }catch (Exception ignore){}

    }

    //notification
    createNotificationChannel();
    Intent i = new Intent(this,BackgroundPlayingService.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this,0,i,0);
    Notification notification = new NotificationCompat.Builder(this,"myChannelId")
            .setContentTitle("QURAN IS PLAYING")
            .setContentText("This means that Qur-an app is open. You can close it from app exit menu")
            .setSmallIcon(androidx.core.R.drawable.notification_icon_background)
            .setContentIntent(pendingIntent)
            .build();

    startForeground(1,notification);
    return START_STICKY;
}

public ExoPlayer createPlayerIfNull() {
    if (player == null) {
        player = new ExoPlayer.Builder(BackgroundPlayingService.this).build();
        ThePlayingActivity.myProgress.setVisibility(View.VISIBLE);
        try {
            ThePlayingActivity.dialog.show();
        }catch (Exception e){
            Log.d(TAG, "createPlayerIfNull: ");
        }

    }
    return player;
}
private void createNotificationChannel(){
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
        NotificationChannel channel = new NotificationChannel("myChannelId","qur-anAudiChannel", NotificationManager.IMPORTANCE_LOW);
        NotificationManager manager = getSystemService(NotificationManager.class);
        manager.createNotificationChannel(channel);
    }
}

@Override
public void onDestroy() {
    super.onDestroy();
    player.stop();
    player = null;
    stopForeground(true);

}

public void showNotification() {
    playerNotificationManager = new PlayerNotificationManager.Builder(this, 151,
            this.getResources().getString(R.string.app_name))
            .setChannelNameResourceId(R.string.app_name)
            .setChannelImportance(IMPORTANCE_HIGH)
            .setMediaDescriptionAdapter(new PlayerNotificationManager.MediaDescriptionAdapter() {
                @Override
                public CharSequence getCurrentContentTitle(Player player) {
                    return player.getCurrentMediaItem().mediaMetadata.displayTitle;
                }

                @Nullable
                @Override
                public PendingIntent createCurrentContentIntent(Player player) {
                    return null;
                }

                @Nullable
                @Override
                public CharSequence getCurrentContentText(Player player) {
                    return Objects.requireNonNull(player.getCurrentMediaItem()).mediaMetadata.artist;
                }

                @Nullable
                @Override
                public Bitmap getCurrentLargeIcon(Player player, PlayerNotificationManager.BitmapCallback callback) {

                    return null;
                }


            }).setNotificationListener(new PlayerNotificationManager.NotificationListener() {
                @Override
                public void onNotificationCancelled(int notificationId, boolean dismissedByUser) {


                }

                @Override
                public void onNotificationPosted(int notificationId, Notification notification, boolean ongoing) {
                    PlayerNotificationManager.NotificationListener.super.onNotificationPosted(notificationId, notification, ongoing);
                }
            })

            .build();
    playerNotificationManager.setUseStopAction(false);
    try {
        playerNotificationManager.setPlayer(player);
    }catch (Exception e){

    }}
}

-------------------- player view activity ------------------------------------

public class ThePlayingActivity extends AppCompatActivity {
private static final int PERMISION_STORAGE_CODE = 100;
private ProgressBar downloadingProgress;
public static ProgressBar myProgress;
public static Dialog dialog;
private ConstraintLayout layoutForSnack;
long downloadId;
private PowerManager powerManager;
private PowerManager.WakeLock wakeLock;
String myurl;
public static PlayerControlView myPlayerView;
private TextView currentPlaying, downloadingTv;
public static Button downloadBtn;
private String thePlayingSura;
private BroadcastReceiver onDownloadComplete = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
        if (downloadId == id) {
            downloadingProgress.setVisibility(View.GONE);
            downloadingTv.setVisibility(View.GONE);
            downloadBtn.setText("DOWNLOADED");
            downloadBtn.setBackgroundColor(Color.TRANSPARENT);
            downloadBtn.setTextColor(Color.BLACK);
            downloadBtn.setClickable(false);
            Toast.makeText(context, "DOWNLOAD COMPLETED", Toast.LENGTH_SHORT).show();
        }
    }
};

@SuppressLint("StaticFieldLeak")

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_the_playing);
    myPlayerView = findViewById(R.id.playerView);
    Intent dataIntent = getIntent();
    myurl = dataIntent.getStringExtra("theUrl");

    Intent backgroundPlayIntent = new Intent(ThePlayingActivity.this,BackgroundPlayingService.class);
    try {
        stopService(backgroundPlayIntent);
    }catch (Exception e){}

    if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
        startForegroundService(backgroundPlayIntent);
    }else{
        startService(backgroundPlayIntent);
    }

    keepActivityAlive();
    registerReceiver(onDownloadComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
    downloadingProgress = findViewById(R.id.downloadProgress);
    downloadingTv = findViewById(R.id.downloadingWaitTv);
    currentPlaying = findViewById(R.id.currentPlaying);
    downloadBtn = findViewById(R.id.downloadbtn);
    downloadBtn.setVisibility(View.GONE);
    myProgress = findViewById(R.id.progressBar2);
    myProgress.setVisibility(View.VISIBLE);
    layoutForSnack = findViewById(R.id.constraintLayout);

    downloadingProgress.setVisibility(View.GONE);
    downloadingTv.setVisibility(View.GONE);


    thePlayingSura = dataIntent.getStringExtra("sendSuraName");
    currentPlaying.setText(thePlayingSura + " - " + DataUtility.theKariName);

    /////////////end of ids
  showLoadingDialog();


    /////////////////download
    downloadBtn.setOnClickListener(view -> {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
                String permissions[] = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
                requestPermissions(permissions, PERMISION_STORAGE_CODE);
            } else {
                downloadStaffs();

            }
        } else {
            downloadStaffs();
        }

    });
}


private void showLoadingDialog() {
    dialog = new Dialog(ThePlayingActivity.this);
    dialog.setContentView(R.layout.dialog_loading_quran);
    dialog.setCancelable(false);
    dialog.show();
}

public  void showSnackBar() {
    Snackbar snackbar = Snackbar.make(layoutForSnack, "THERE WAS ON ERROR, CHECK YOUR INTERNET CONNECTION", Snackbar.LENGTH_INDEFINITE);
    snackbar.setAction("RETRY", view -> {
        //todo retry player

    });
    snackbar.setActionTextColor(Color.YELLOW);
    snackbar.show();
}


@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    switch (requestCode) {
        case PERMISION_STORAGE_CODE: {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // we have permission
                downloadStaffs();
            } else {
                Toast.makeText(ThePlayingActivity.this, "PERMISSION DENIED... CAN NOT DOWNLOAD", Toast.LENGTH_SHORT).show();
            }
        }
    }
}


@Override
protected void onDestroy() {
    super.onDestroy();
    unregisterReceiver(onDownloadComplete);
    try {
        if (wakeLock.isHeld()) {
            wakeLock.release();
        }
    } catch (Exception ignore) {

    }

}


private void downloadStaffs() {

    DownloadManager.Request request = new DownloadManager.Request(Uri.parse(DataUtility.playingUrl));

    request.setDescription("Download File");
    request.setTitle(thePlayingSura);
    request.allowScanningByMediaScanner();
    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
    request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, thePlayingSura + " - " + DataUtility.theKariName + ".mp3");

    final DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);

    final long downloadId = manager.enqueue(request);
    this.downloadId = downloadId;

    final ProgressBar mProgressBar = (ProgressBar) findViewById(R.id.downloadProgress);
    downloadingTv.setVisibility(View.VISIBLE);
    mProgressBar.setVisibility(View.VISIBLE);

    new Thread(new Runnable() {

        @SuppressLint("Range")
        @Override
        public void run() {

            boolean downloading = true;

            while (downloading) {

                DownloadManager.Query q = new DownloadManager.Query();
                q.setFilterById(downloadId);

                Cursor cursor = manager.query(q);
                cursor.moveToFirst();
                @SuppressLint("Range") int bytes_downloaded = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
                @SuppressLint("Range") int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));

                if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
                    downloading = false;
                }

                final double dl_progress = (int) ((bytes_downloaded * 100l) / bytes_total);

                runOnUiThread(new Runnable() {


                    @Override
                    public void run() {
                        mProgressBar.setProgress((int) dl_progress);


                    }
                });

                Log.d("MESSAGES", statusMessage(cursor));
                cursor.close();
            }

        }
    }).start();
}

@SuppressLint("Range")
private String statusMessage(Cursor c) {
    String msg = "???";

    switch (c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS))) {
        case DownloadManager.STATUS_FAILED:
            msg = "Download failed!";
            break;

        case DownloadManager.STATUS_PAUSED:
            msg = "Download paused!";
            break;

        case DownloadManager.STATUS_PENDING:
            msg = "Download pending!";
            break;

        case DownloadManager.STATUS_RUNNING:
            msg = "Download in progress!";
            break;

        case DownloadManager.STATUS_SUCCESSFUL:
            msg = "Download complete!";
            break;

        default:
            msg = "Download is nowhere in sight";
            break;
    }

    return (msg);
}


private void keepActivityAlive() {
    powerManager = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
    wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "QuranAudio:WakeLock");
}

private void startService() {
    Intent i = new Intent(this, BackgroundPlayingService.class);
    startService(i);
}}

--------------------- extra -------------------------------------- I also had to create other service to remove notification when the user kill app by clearing app from recent apps. here is it

MyAppService extends Service {

@Override
public void onTaskRemoved(Intent rootIntent) {
    super.onTaskRemoved(rootIntent);
    Intent i = new Intent(MyAppService.this,BackgroundPlayingService.class);
    try {
        BackgroundPlayingService.playerNotificationManager.setPlayer(null);
        stopService(i);
    }catch (Exception ignore){}

}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}}

-------------------- WARNING ---------------------------------- I don't take this as a best approach, but it gave me a quick solution while waiting for a better approach. I will pot the app link here when it's available in playstore.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Moh'd Khamis Songoro