I am creating an app that has a constant notification that reports stats to the user. Every 10 minute, I update the stats in the app, then update the notification. The problem is, the stats update in the app, but the notification does not update until I open the app. I call the same method to update the notification regardless of if the app is open or if it is called through a service.
Is there something special I have to do because it's running through a service?
Service Code (again, this works fine):
Thread.sleep(((10 /* minutes */) * 60 * 1000));
Handler handler = new Handler(getApplicationContext().getMainLooper());
Runnable runnable = new Runnable() {
#Override
public void run() {
OverviewFragment.refresh(getApplicationContext());
}
};
handler.post(runnable);
System.out.println("Updated values through service.");
Refresh Code (for notification):
builder = new NotificationCompat.Builder(context)
.setSmallIcon(R.mipmap.ic_launcher_white)
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher_old))
.setAutoCancel(false)
.setContent(remoteViews)
.setContentIntent(pendingIntent)
.setPriority(Notification.PRIORITY_MAX);
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
builder.setOngoing(true);
notificationManager.notify(notificationId, builder.build());
Related
I am just curious to know what are the differences between NotificationManager.notify and startForeground in Android.
Using NotificationManager.notify you can post as many updates to a notification as you like including adjustments to progress bars via Noticiation.Builder.setProgress in this way you only show one notification to the User, and its the one required by startForeground.
When you want to update a Notification set by startForeground(), simply build a new notication and then use NotificationManager to notify it.
The KEY point is to use the same notification id.
I didn't test the scenario of repeatedly calling startForeground() to update the Notification, but I think that using NotificationManager.notify would be better.
Updating the Notification will not remove the Service from the foreground status (this can be done only by calling stopForground.
Here is an example:
private static final int notif_id=1;
#Override
public void onCreate (){
this.startForeground();
}
private void startForeground() {
startForeground(notif_id, getMyActivityNotification(""));
}
private Notification getMyActivityNotification(String text){
// The PendingIntent to launch our activity if the user selects
// this notification
CharSequence title = getText(R.string.title_activity);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MyActivity.class), 0);
return new Notification.Builder(this)
.setContentTitle(title)
.setContentText(text)
.setSmallIcon(R.drawable.ic_launcher_b3)
.setContentIntent(contentIntent).getNotification();
}
/**
* this is the method that can be called to update the Notification
*/
private void updateNotification() {
String text = "Some text that will update the notification";
Notification notification = getMyActivityNotification(text);
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(notif_id, notification);
}
You can find more examples and clarification on NotificationManager.notify here
I'd also suggest you to refer this page in order to understand more on startForeground
Usages of startForeground could be found here
I have used foreground service but when the app is in bg, it shows task Completed which I dont want. How can I remove it? If this line (.addAction(R.drawable.ic_cancel, getString(R.string.remove_location_updates),
servicePendingIntent)) is removed, the bg service doesn't work. If this code is used: '.setContentIntent(servicePendingIntent)', when I click in the noti, the app doesn't open, noti closed and service stops. How can I solve it? Thanks in advance
private Notification getNotification() {
Intent intent = new Intent(this, LocationUpdatesService.class);
CharSequence text = Utils.getLocationText(mLocation);
// Extra to help us figure out if we arrived in onStartCommand via the notification or not.
intent.putExtra(EXTRA_STARTED_FROM_NOTIFICATION, true);
// The PendingIntent that leads to a call to onStartCommand() in this service.
PendingIntent servicePendingIntent = PendingIntent.getService(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent activityPendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, LiveTrack.class), 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.addAction(R.drawable.ic_cancel, getString(R.string.remove_location_updates),
servicePendingIntent)
.setContentIntent(activityPendingIntent)
// .setContentIntent(servicePendingIntent)
.setContentText("App name")
.setContentTitle(Utils.getLocationTitle(this))
.setOngoing(true)
.setPriority(Notification.PRIORITY_HIGH)
.setSmallIcon(R.mipmap.ic_launcher)
.setTicker(text)
.setWhen(System.currentTimeMillis());
// Set the Channel ID for Android O.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(CHANNEL_ID); // Channel ID
}
return builder.build();
}
private void onNewLocation(Location location) {
mLocation = location;
// Notify anyone listening for broadcasts about the new location.
Intent intent = new Intent(ACTION_BROADCAST);
intent.putExtra(EXTRA_LOCATION, location);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
// Update notification content if running as a foreground service.
if (serviceIsRunningInForeground(this)) {
mNotificationManager.notify(NOTIFICATION_ID, getNotification());
}
}
public boolean serviceIsRunningInForeground(Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(
Integer.MAX_VALUE)) {
if (getClass().getName().equals(service.service.getClassName())) {
if (service.foreground) {
return true;
}
}
}
return false;
}
If you will look at official document, it says
For user-initiated work that need to run immediately and must execute
to completion, use a foreground service. Using a foreground service
tells the system that the app is doing something important and it
shouldn’t be killed. Foreground services are visible to users via a
non-dismissible notification in the notification tray.
Even in the services document it says
A foreground service performs some operation that is noticeable to the
user. For example, an audio app would use a foreground service to play
an audio track. Foreground services must display a Notification.
Foreground services continue running even when the user isn't
interacting with the app.
So it seems, there must be non-dismissible notification when you are using foreground services.
I have to create a service which tracks the GPS location of the user even when the application is killed until when i stop the service. Is it possible?
I have created a service which makes use of LocationListener and also made use of socket.io which communicates with server. But when the application is paused the location updates donot reflect and when i kill the application the socket closes. Please suggest a proper way to implement.
Link to the service i have created
This is my onStartCommand
h = new Handler();
r = new Runnable() {
#Override
public void run() {
startSomeJob();
startForeground(101, updateNotification(0));
}
};
h.post(r);
And here is notification:
private Notification updateNotification(int progress) {
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
new Intent(action), 0);
String info = progress + "%";
NotificationManager mNotifyManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) if (mNotifyManager != null) {
createChannel(mNotifyManager);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "101")
.setContentTitle(info)
.setTicker(info)
.setContentText("Uploading")
.setVibrate(new long[] {0L})
.setProgress(100, progress, false)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent)
.setOngoing(true);
return builder.build();
}
And in my someJob if there is some update, it call startForeground(101, updateNotification(percentDone));
In your case when location is changed in function onLocationChanged you need to call startForeground with notification.
how can i create a notification in the notifications bar that disappear after 5 seconds?
For example; this is the notification code:
Intent intent = new Intent(this, NotificationReceiver.class);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);
// Build notification
// Actions are just fake
Notification noti = new Notification.Builder(this)
.setContentTitle("Notification")
.setContentText("This is a notification that didsappears in 5 seconds")
.setSmallIcon(R.drawable.icon)
.setContentIntent(pIntent)
.addAction(R.drawable.icon)
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(0, noti);
Starting from this code how can i create my notification that disappear after 5 seconds?
You can simply cancel your notification after 5 seconds.For this you can use either Timer or Handler.Here is Handler solution:
Handler handler = new Handler();
long delayInMilliseconds = 5000;
handler.postDelayed(new Runnable() {
public void run() {
notificationManager.cancel(YourNotificationId);
}}, delayInMilliseconds);
if you want to use Timer instead of Handler. Then you can try:
Timer timer = new Timer();
timer.schedule(new TimerTask()
{
public void run()
{
notificationManager.cancel(YourNotificationId);
}},delayInMilliseconds);
}
You can use method cancel(int id) or cancelAll() to dismiss your notifications.
Start a timer for 5 seconds and when it ends call cancell();
http://developer.android.com/reference/android/app/NotificationManager.html#cancel(int)
Is it possible to make a notification automatically disappear after a period of time?
You can use the AlarmManager. I think is more appropriate and more easier to implement than an Android Service.
With AlarmManager you do not need worry about make something running until the time finish. Android do that for you, and send a brodcast when it happen. Your application must have a Receiver to get the correct intent.
Look theses examples:
Android: How to use AlarmManager
Alarm Manager Example
Now there is an option called .setTimeoutAfter(long durationMs)
https://developer.android.com/reference/android/app/Notification.Builder.html#setTimeoutAfter(long)
Yeah, you can just create a service that runs in the background that'll timeout after five minutes and delete your notification. Whether you "should" actually do that is up for debate. A notification should be there to notify the user... and the user should be able to dismiss it on their own.
From d.android.com:
A Service is an application component that can perform long-running
operations in the background and does not provide a user interface.
Yeah, it is very easy.
Where you get notification there add one handler if notification is not read by user then remove notification.
#Override
public void onMessageReceived(RemoteMessage message) {
sendNotification(message.getData().toString);
}
add notification code
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("TEST NOTIFICATION")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
int id = 0;
notificationManager.notify(id, notificationBuilder.build());
removeNotification(id);
}
cancel notification code.
private void removeNotification(int id) {
Handler handler = new Handler();
long delayInMilliseconds = 20000;
handler.postDelayed(new Runnable() {
public void run() {
notificationManager.cancel(id);
}
}, delayInMilliseconds);
}
You could also use a classic Java Runnable for a simple small Thread.
Handler h = new Handler();
long delayInMilliseconds = 5000;
h.postDelayed(new Runnable() {
public void run() {
mNotificationManager.cancel(id);
}
}, delayInMilliseconds);
Also look here:
Clearing notification after a few seconds