I made a MediaPlayer some time ago and I faced a big issue. The audio can't be played in the background so I must use Service. At this point, I managed to play the music and to stop it, but when I click play again, it restarts and I don't know what to do. I am new to coding. Other than that I want to make a working seekbar and a textView for player position, but that for another time. If there is someone to help me I would really appreciate it.
Here is the code I am using now:
btPause = findViewById(R.id.btPauseMusic);
btPlay = findViewById(R.id.btPlayMusic);
btPlay.setOnClickListener(v -> {
startService(new Intent(this, BackgroundMusicService.class));
btPlay.setVisibility(View.GONE);
btPause.setVisibility(View.VISIBLE);
});
btPause.setOnClickListener(v -> {
stopService(new Intent(this, BackgroundMusicService.class));
btPause.setVisibility(View.GONE);
btPlay.setVisibility(View.VISIBLE);
});
}
The service:
public class BackgroundMusicService extends Service {
private MediaPlayer mediaPlayer;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mediaPlayer = MediaPlayer.create(this, R.raw.ding_dong);
mediaPlayer.start();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
mediaPlayer.stop();
}
}
Add this notification code in your BackgroundMusicService inside on onCreate.
Intent stopSelf = new Intent(this, BackgroundMusicService.class);
stopSelf.setAction("Stop");
PendingIntent pStopSelf = PendingIntent
.getService(this, 0, stopSelf
, PendingIntent.FLAG_CANCEL_CURRENT);
Notification notification;
NotificationCompat.Action action =
new NotificationCompat.Action.Builder(
0, "Pause", pStopSelf
).build();
Intent startSelf = new Intent(this, BackgroundMusicService.class);
stopSelf.setAction("Start");
PendingIntent pstartSelf = PendingIntent
.getService(this, 0, stopSelf
, PendingIntent.FLAG_CANCEL_CURRENT);
Notification notifications;
NotificationCompat.Action actions =
new NotificationCompat.Action.Builder(
0, "Play", pstartSelf
).build();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel("channal", "Notification", NotificationManager.IMPORTANCE_HIGH);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(serviceChannel);
notification = new NotificationCompat.Builder(this, "channal")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentText("Music.")
.setPriority(Notification.PRIORITY_MAX)
.addAction(action)
.addAction(actions).build();
} else {
notification = new NotificationCompat.Builder(this, "channal")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("App name")
.setContentText("Music.")
.setPriority(Notification.PRIORITY_MAX)
.addAction(action)
.addAction(actions)
.build();
}
NotificationManager notificationManager =
(NotificationManager) getSystemService(Service.NOTIFICATION_SERVICE);
notificationManager.notify(1, notification);
startForeground(1, notification);
In onStartCommand your intent actions are called where you can pause and play the music by using the length.
int length=0;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
if ("STOP".equals(intent.getAction())) {
//inside here pause the music.
mediaPlayer.pause();
length = mediaPlayer.getCurrentPosition();
}else if ("Start".equals(intent.getAction())) {
//inside here play the music with seekto by length where the music was.
mediaPlayer.start();
mediaPlayer.seekTo(length);
}
return START_STICKY;
}
Note: If you still did not understand anything you can ask me in the comment.
Related
I have an Activity where the user can download a video. Upon user's click, the Download Service starts to download the content.
There is a progress bar in the Activity UI which I would like to update according to download progress in the service which broadcasts the progress periodically.
Everything works fine but after a certain time the service stops sending any broadcast progress, hence, the UI does not update anymore.
Additionally, how I can resume receiving the progress broadcast when the user goes to another Activity and comes back to this Activity? I mean, even if the above issue is solved, when the user presses back button and go to other activity and comes back to this activity, the progress gets lots. How can I check for any existing broadcast and receive it whenever the user comes to this activity.
In the ACTIVITY:
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
Log.d("DownloadService", "Progress Received In Activity");
Double progress = bundle.getDouble("PROGRESS");
updateDownloadProgressBar(progress);
}
}
};
private void startDownloadService() {
final String videoId = mItem.getAttributes().get(KEY_ASSET_ID);
Intent intent = new Intent(this, DownloadService.class);
intent.putExtra("VIDEOID", videoId);
startService(intent);
}
in the onResume():
registerReceiver(receiver, new IntentFilter(DownloadService.NOTIFICATION_SERVICE));
in the onPause():
unregisterReceiver(receiver);
In the SERVICE:
private void publishProgress(double progress) {
Log.d(TAG, "Broadcasting progress from Service");
Intent intent = new Intent(NOTIFICATION_SERVICE);
intent.putExtra("PROGRESS", progress);
sendBroadcast(intent);
}
The download and progress work fine to 38% then stop.
It seems that the service is being stopped/killed from the OS, to avoid that use foreground service so you can make sure it will not be killed from the OS.
See the sample code below:
Service
public class PendingService extends Service {
private final static String TAG = "PendingService";
public final static int NOTIFICATION_ID = 94;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startInForeground();
// Do your work here ...
return START_STICKY;
}
private void startInForeground() {
String NOTIFICATION_CHANNEL_ID = "default";
String NOTIFICATION_CHANNEL_NAME = "My Pending Service";
String NOTIFICATION_CHANNEL_DESC = "This notification holding a pending task";
Intent notificationIntent = new Intent(this, SplashActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.notification)
.setOngoing(true)
.setAutoCancel(true)
.setContentIntent(pendingIntent);
if (Build.VERSION.SDK_INT >= 26) {
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
channel.setDescription(NOTIFICATION_CHANNEL_DESC);
channel.setSound(null, null);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
notificationManager.createNotificationChannel(channel);
}
}
Notification notification = builder.build();
startForeground(NOTIFICATION_ID, notification);
}
#Override
public void onDestroy() {
super.onDestroy();
removeNotification(NOTIFICATION_ID);
// ....
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void removeNotification(int notificationId) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
notificationManager.cancel(notificationId);
}
}
}
Utils you may need
class ServiceUtils {
/**
* #param service: Service to run
*/
fun startService(context: Context, service: Class<out Service>) {
val serviceIntent = Intent(context, service)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(serviceIntent)
} else {
context.startService(serviceIntent)
}
}
/**
* #return True: if the service is running
*/
fun isServiceRunning(context: Context, serviceClass: Class<*>): Boolean {
val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.name == service.service.className) {
return true
}
}
return false
}
}
I'm creating a ClockApp for Android. I have AlarmBroadcastReceiver which gives me a notification with the button close alarm and when an user clicks by that button the notification will be disappeared. However, it doesn't work when my app was closed. For example, I set alarm at 7:00 am and I closed my app then I waked up and I found on my phone a notification close alarm I clicked by that button but I just was redirected to a main activity then I clicked again and only then the notification will be disappeared. Why do I have to click two times? However, if my app isn't closed I have to click only one time and the notification will be disappeared. I hope you'll help me with my problem)
Code: (I have MainActivity with tabs)
MainActivity:
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// cancel notifications
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (intent.getBooleanExtra("alarm_cancel_notification", false)) {
if (notificationManager != null) {
notificationManager.cancel(1);
}
}
}
AlarmFragment:
private void startAlarm() {
Intent intent = new Intent(getContext(), AlarmManagerBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
getContext(),
1,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT >= 23) {
AlarmManager.AlarmClockInfo alarmClockInfo =
new AlarmManager.AlarmClockInfo(mCalendar.getTimeInMillis(), pendingIntent);
mAlarmManager.setAlarmClock(alarmClockInfo, pendingIntent);
} else if (Build.VERSION.SDK_INT >= 19) {
mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, mCalendar.getTimeInMillis(), pendingIntent);
} else {
mAlarmManager.set(AlarmManager.RTC_WAKEUP, mCalendar.getTimeInMillis(), pendingIntent);
}
}
BroadcastReceiver:
public class AlarmManagerBroadcastReceiver extends BroadcastReceiver {
private static final int ALARM_EXPIRED_NOTIFICATION_ID = 1;
#Override
public void onReceive(Context context, Intent intent) {
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent notificationIntent = new Intent(context, MainActivity.class);
notificationIntent.putExtra("alarm_cancel_notification", true);
PendingIntent notificationPendingIntent = PendingIntent.getActivity(
context,
1,
notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews remoteViews = new RemoteViews(
context.getPackageName(),
R.layout.partial_notification);
remoteViews.setTextViewText(
R.id.cancel_button_notification,
context.getString(R.string.alarm_notification));
remoteViews.setOnClickPendingIntent(
R.id.cancel_button_notification,
notificationPendingIntent);
NotificationCompat.Builder builder = new NotificationCompat.Builder(
context,
ChannelIdApp.CHANNEL_ID);
builder.setAutoCancel(true)
.setTicker("Alarm")
.setCustomContentView(remoteViews)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM))
.setSmallIcon(R.drawable.ic_stat_notify_clock);
Notification notification = builder.build();
notification.flags = notification.flags | Notification.FLAG_INSISTENT;
if (notificationManager != null) {
notificationManager.notify(ALARM_EXPIRED_NOTIFICATION_ID, notification);
}
}
}
Channel Id:
public class ChannelIdApp extends Application {
public static final String CHANNEL_ID = "clock_channel_id";
#Override
public void onCreate() {
super.onCreate();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel notificationChannel = new NotificationChannel(
CHANNEL_ID,
"Clock notifications",
NotificationManager.IMPORTANCE_HIGH);
notificationChannel.enableVibration(true);
notificationChannel.enableLights(true);
if (notificationManager != null) {
notificationManager.createNotificationChannel(notificationChannel);
}
}
}
}
Manifest:
<activity
android:launchMode="singleTop"
android:name=".activities.MainActivity"
android:screenOrientation="portrait" />
<receiver
android:exported="false"
android:name=".AlarmManagerBroadcastReceiver" />
try adding .setAutoCancel(true); in your AlarmManagerBroadcastReceiver class after this line
NotificationCompat.Builder builder = new NotificationCompat.Builder(
context,
ChannelIdApp.CHANNEL_ID);
builder.setAutoCancel(true)
.setTicker("Alarm")
.setCustomContentView(remoteViews)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM))
.setSmallIcon(R.drawable.ic_stat_notify_clock)
// <<here>> ;
Am Working on a timer based app where the notification shows up when the timer starts to run. I have set it as ongoing so that it cannot be cleared.
I have used cancelAll() method for some cases which works fine but when I force close the app, the notification still shows up and cannot be removed and tried to use the method in onDestroy() method still the problem prevails.
Here is my code and created the channel in another class :
public void sendNotif(){
Intent resultIntent = new Intent(this, TimerActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
not = new NotificationCompat.Builder(this,Notif.CHANNEL_ID)
.setSmallIcon(R.drawable.curved_shape)
.setContentTitle("Productivity Timer")
.setContentText("Your Timer is Running")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
.setOngoing(true)
.setContentIntent(pendingIntent)
.build();
notificationManager.notify(1,not);
}
I found this great solution once, I will retype it here
Since your application and the notification are handled in different threads, so killing your application won't kill the notification. The solution is to create a Service to kill notification, since services will restart themselves when the app is killed suddenly, you can use the automatic restart to kill the notification.
Create the service class
public class KillNotificationsService extends Service {
public class KillBinder extends Binder {
public final Service service;
public KillBinder(Service service) {
this.service = service;
}
}
public static int NOTIFICATION_ID = 666;
private NotificationManager mNM;
private final IBinder mBinder = new KillBinder(this);
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
#Override
public void onCreate() {
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNM.cancel(NOTIFICATION_ID);
}
}
Add it to your manifest
<service android:name="KillNotificationsService"></service>
Always create the Service before fireing the notification, and use the static notificationid
ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder binder) {
((KillBinder) binder).service.startService(new Intent(
MainActivity.this, KillNotificationsService.class));
Notification notification = new Notification(
R.drawable.ic_launcher, "Text",
System.currentTimeMillis());
Intent notificationIntent = new Intent(MainActivity.this,
Place.class);
PendingIntent contentIntent = PendingIntent.getActivity(
MainActivity.this, 0, notificationIntent, 0);
notification.setLatestEventInfo(getApplicationContext(),
"Text", "Text", contentIntent);
NotificationManager mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNM.notify(KillNotificationsService.NOTIFICATION_ID,
notification);
}
public void onServiceDisconnected(ComponentName className) {
}
};
bindService(new Intent(MainActivity.this,
KillNotificationsService.class), mConnection,
Context.BIND_AUTO_CREATE);
This question already has answers here:
Android - implementing startForeground for a service?
(11 answers)
Closed 1 year ago.
I am new to android. Can anyone post the link or code for "android foreground service example with notification". I googled , but didn't get any example of foreground service.
Create a Notification, perhaps using Notification.Builder or NotificationCompat.Builder, and pass that to startForeground() on the service:
public class Downloader extends IntentService {
private static int FOREGROUND_ID=1338;
public Downloader() {
super("Downloader");
}
#Override
public void onHandleIntent(Intent i) {
startForeground(FOREGROUND_ID,
buildForegroundNotification(filename));
// do useful work here
stopForeground(true);
}
private Notification buildForegroundNotification(String filename) {
NotificationCompat.Builder b=new NotificationCompat.Builder(this);
b.setOngoing(true);
b.setContentTitle(getString(R.string.downloading))
.setContentText(filename)
.setSmallIcon(android.R.drawable.stat_sys_download)
.setTicker(getString(R.string.downloading));
return(b.build());
}
}
(a trimmed-down service from this sample project)
A better example would be:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction().equals(Constants.ACTION.STARTFOREGROUND_ACTION)) {
Log.i(LOG_TAG, "Received Start Foreground Intent ");
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setAction(Constants.ACTION.MAIN_ACTION);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
Intent previousIntent = new Intent(this, ForegroundService.class);
previousIntent.setAction(Constants.ACTION.PREV_ACTION);
PendingIntent ppreviousIntent = PendingIntent.getService(this, 0,
previousIntent, 0);
Intent playIntent = new Intent(this, ForegroundService.class);
playIntent.setAction(Constants.ACTION.PLAY_ACTION);
PendingIntent pplayIntent = PendingIntent.getService(this, 0,
playIntent, 0);
Intent nextIntent = new Intent(this, ForegroundService.class);
nextIntent.setAction(Constants.ACTION.NEXT_ACTION);
PendingIntent pnextIntent = PendingIntent.getService(this, 0,
nextIntent, 0);
Bitmap icon = BitmapFactory.decodeResource(getResources(),
R.drawable.truiton_short);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("Truiton Music Player")
.setTicker("Truiton Music Player")
.setContentText("My Music")
.setSmallIcon(R.drawable.ic_launcher)
.setLargeIcon(
Bitmap.createScaledBitmap(icon, 128, 128, false))
.setContentIntent(pendingIntent)
.setOngoing(true)
.addAction(android.R.drawable.ic_media_previous,
"Previous", ppreviousIntent)
.addAction(android.R.drawable.ic_media_play, "Play",
pplayIntent)
.addAction(android.R.drawable.ic_media_next, "Next",
pnextIntent).build();
startForeground(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE,
notification);
} else if (intent.getAction().equals(Constants.ACTION.PREV_ACTION)) {
Log.i(LOG_TAG, "Clicked Previous");
} else if (intent.getAction().equals(Constants.ACTION.PLAY_ACTION)) {
Log.i(LOG_TAG, "Clicked Play");
} else if (intent.getAction().equals(Constants.ACTION.NEXT_ACTION)) {
Log.i(LOG_TAG, "Clicked Next");
} else if (intent.getAction().equals(
Constants.ACTION.STOPFOREGROUND_ACTION)) {
Log.i(LOG_TAG, "Received Stop Foreground Intent");
stopForeground(true);
stopSelf();
}
return START_STICKY;
}
Took reference from a tutorial here.. maybe of help to you
I'm developing an online radio application. The application works in the background. When I click the NotificationManager, radioclass starts working again. I want to call the radioclass that are running. How can I do?
player = MediaPlayer.create(this, Uri.parse("http://...../playlist.m3u8"));
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer player) {
}
});
player.start();
final int notificationID = 1234;
String msg = "mesajjj";
Log.d(TAG, "Preparing to update notification...: " + msg);
NotificationManager mNotificationManager = (NotificationManager) this
.getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent = new Intent(this, RadioClass.class);
//Here RadioClass running again. But RadioClass already running. I should call RadioClass that is running.
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
this).setSmallIcon(R.drawable.logotam)
.setContentTitle("Test FM")
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
.setContentText(msg);
mBuilder.setContentIntent(pendingIntent);
mNotificationManager.notify(notificationID, mBuilder.build());
If you want to go back to the same activity you are currently running, you can do it like this:
Add the following tag on your AndroidManifest.xml:
<activity
........
android:launchMode="singleTop" >
........
</activity>
Modify your PendingIntent like this:
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
With this modifications, you ensure that your activity will only have one instance at any given time. On your activity class, you can also override the onNewIntent method:
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
}
This method will handle all of the additional calls to your activity.