Weird issue with local notification on Oreo - android

I was trying to implement a feature where user can set a reminder that will be delivered with a local push notification.
I am using AlarmManager to throw a broadcast when the time is up.
Then in the broadcast receiver, I am posting a local notification and then starting a foreground service which starts an activity so I can wake the device and turn on the screen.
If I do nothing after posting the notification (simply return and not starting foreground service) I can get the device to show the notification with no problem.
However, if I start the service right after posting the notification, all I get is some vibration but I don't see the notification anywhere.
Even stranger, from the notification manager, it says there is 1 notification from getActiveNotifications() although there is nothing.
Receiver:
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (!action.equals(context.getString(R.string.reminder_action_string))) {
// fail safe check
return;
}
// create the channel for android 8
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID,
context.getString(R.string.reminder_notification_channel),
NotificationManager.IMPORTANCE_HIGH);
channel.setDescription(context.getString(R.string.reminder_notification_channel_desc));
final AudioAttributes attributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build();
channel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), attributes);
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, ReceiverReminder.CHANNEL_ID)
.setChannelId(ReceiverReminder.CHANNEL_ID)
.setContentTitle(context.getString(R.string.reminder_title))
.setContentText(intent.getStringExtra(ActivityReminderCreate.TEXT_STRING))
.setSmallIcon(R.drawable.ic_mic)
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(intent.getStringExtra(ActivityReminderCreate.TEXT_STRING)))
.setPriority(NotificationCompat.PRIORITY_MAX)
.setCategory(NotificationCompat.CATEGORY_ALARM)
.setVisibility(NotificationCompat.VISIBILITY_SECRET)
.setContentIntent(PendingIntent.getActivity(context, 0, new Intent(context, ActivityReminderList.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK), PendingIntent.FLAG_ONE_SHOT))
.setAutoCancel(true);
NotificationManagerCompat manager = NotificationManagerCompat.from(context);
Notification notification = builder.build();
final int id = mSecureRandom.nextInt();
manager.notify(id, notification);
Intent serviceIntent = new Intent(context, ServiceReminder.class);
serviceIntent.putExtras(intent);
serviceIntent.putExtra(KEY_ID, id);
serviceIntent.putExtra(KEY_NOTIFICATION, notification);
ContextCompat.startForegroundService(context, serviceIntent);
}
IntentService:
#Override
protected void onHandleIntent(#Nullable Intent intent) {
// construct notification object
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// start self in foreground
NotificationManager manager = getSystemService(NotificationManager.class);
Log.e(TAG, "notification count: " + manager.getActiveNotifications().length);
Notification notification = intent.getExtras().getParcelable(ReceiverReminder.KEY_NOTIFICATION);
int id = intent.getExtras().getInt(ReceiverReminder.KEY_ID);
startForeground(id, notification);
Log.e(TAG, "notification count: " + manager.getActiveNotifications().length);
}
// start an activity so device can be waken up
Intent activityIntent = new Intent(ServiceReminder.this, ActivityReminderList.class);
activityIntent.putExtra(ActivityReminderList.KEY_FROM_SERVICE, true);
startActivity(activityIntent);
}

I figured out why...
I used an IntentService which kills itself when its current job is done.
And in the case of a foreground service, the associated notification is dismissed when the service is stopped.
I've switched to using a Service instead, and the notification would stay there.

Related

Foreground service notification takes a few seconds to show up

Foreground service notification shows too slowly on Android 12. Used ContextCompat.startForegroundService(...) and mContext.startForegroundService(...). It still shows in 5-10 seconds.
Here is an example of my code:
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "Counting steps", NotificationManager.IMPORTANCE_DEFAULT);
channel.enableVibration(false);
channel.setSound(null, null);
channel.setShowBadge(false);
notificationManager.createNotificationChannel(channel);
}
}
The onStartCommand method:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String input = intent.getStringExtra("numberOfSteps");
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
Notification.Builder notificationBuilder = new Notification.Builder(this, CHANNEL_ID)
.setContentTitle("Counting steps")
.setContentText(input)
.setSmallIcon(R.drawable.ic_baseline_directions_walk_24)
.setContentIntent(pendingIntent);
startForeground(FOREGROUND_ID, notificationBuilder.build());
}
return START_STICKY;
}
How can I start or show a foreground service notification quickly?
Services that show a notification immediately
If a foreground service has at least one of the following
characteristics, the system shows the associated notification
immediately after the service starts, even on devices that run Android
12 or higher:
The service is associated with a notification that includes action
buttons. The service has a foregroundServiceType of
mediaPlayback, mediaProjection, or phoneCall. The service
provides a use case related to phone calls, navigation, or media
playback, as defined in the notification's category
attribute. The service has opted out of the behavior
change by passing FOREGROUND_SERVICE_IMMEDIATE into
setForegroundServiceBehavior() when setting up the
notification.
On Android 13 (API level 33) or higher, if the user denies the
notification permission, they still see notices related to foreground
services in the Foreground Services (FGS) Task Manager but don't see
them in the notification drawer.
See: Services that show a notification immediately
Java example code:
Notification.Builder notificationBuilder = new Notification.Builder(this, CHANNEL_ID)
.setContentTitle("Counting steps")
.setContentText(message)
.setSmallIcon(R.drawable.your_cool_icon)
.setContentIntent(pendingIntent);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
notificationBuilder.setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE);
}
Kotlin example:
val notificationBuilder: Notification.Builder =
Notification.Builder(this, CHANNEL_ID)
.setContentTitle("Notification title")
.setContentText("Content title")
.setSmallIcon(R.drawable.your_cool_icon)
.setContentIntent(pendingIntent)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
notificationBuilder.setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE)
}

How to create multiple notification for each uploading progress in foreground service?

Here I tried to implement feature ,user to user send media
I tried to upload media using foreground service.
I want to set multiple notification in foreground service like this
what I have used
public class MyApplication extends Application {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
"Example Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
service class
public class Upload extends Service
{
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("sending to "+firstName)
.setProgress(100,0,true)
.setSmallIcon(R.drawable.logo_la)
.setContentIntent(pendingIntent)
.build();
startForeground(unique_id, notification);
}
}
from activity
On each time of new uploading
Intent serviceIntent = new Intent(this, Upload.class);
ContextCompat.startForegroundService(this, serviceIntent);
this is show only single notification

permanent notification does not show

I submitted my app at the end of 2017 in the play store and it worked.
Then it was built in Eclipse.
Now I run it in Android Studio and the same code doesn't show any notification.
It is a permanent notification which is present after I call the app's finish() method. (why I do this: see at the bottom if you want to know).
So I looked at all the examples and NONE of the work. No single notification is shown.
So I start an activity and in the activity I show the notification. Then I call finish().
This is my code:
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
intent, 0);
CharSequence connectedPart = getResources().getString(R.string.app_name);
String melding = "";
melding = getResources().getString(R.string.screentimeoutsetto) + " " + newTimeString + ".";
NotificationManager notificationManager = (NotificationManager) this
.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification.Builder(this)
.setContentTitle(connectedPart)
.setTicker(connectedPart)
.setContentText(melding)
.setSmallIcon(R.drawable.ic_stat_name)
.setContentIntent(pendingIntent)
.setOngoing(true)
.build();
notification.flags |= Notification.FLAG_ONGOING_EVENT;
notification.flags |= Notification.FLAG_NO_CLEAR;
notificationManager.notify(2, notification);
dependencies:
dependencies{
implementation "com.android.support:support-compat:26.1.0"
}
Why I do this:
My app does 1 thing: toggle the screentimeout. So when you start it it sets the screentimeout to 30 minutes (starts, sets a notification, then finish()). Start again, it removes the notification and restore the original value for the screen timeout.
Starting with Android Oreo, all notifications require a notification channel, otherwise the notification wont post and an error will appear in your logcat. Here's an example of how you can do it, lifted from one of my apps:
private static void createNotificationChannel(Context ctx) {
if(SDK_INT < O) return;
final NotificationManager mgr = ctx.getSystemService(NotificationManager.class);
if(mgr == null) return;
final String name = ctx.getString(R.string.channel_name);
if(mgr.getNotificationChannel(name) == null) {
final NotificationChannel channel =
new NotificationChannel(CHANNEL_ID, name, IMPORTANCE_DEFAULT);
mgr.createNotificationChannel(channel);
}
}
//Usage...
createNotificationChannel(context);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID);
builder.setSmallIcon(R.drawable.ic_alarm_white_24dp);
//etc...
manager.notify(id, builder.build());
Now from Android 8.0 and onward you need to create notification channel before showing notifications. Here is the Docs link
https://developer.android.com/training/notify-user/channels

Starting a Service with Alarm after the app is closed

I am making a simple app that that consists of a service that pops a notification several times a day. I am trying to make this with a Alarm. All works perfect if I don't close the app. However, if I close the app when the receiver is triggered I get the message "the app has stopped working" or whatever.
I was wandering if it is because the service cannot work without an activity of the app or something? Any insights?
Here is my code:
The receiver:
public class AlarmReceiver extends BroadcastReceiver {
public static final int REQUEST_CODE = 12345;
public static final String ACTION = "com.ddimitrovd.hap4eapp4e.alarm";
// Triggered by the Alarm periodically (starts the service to run task)
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, MainIntentService.class);
i.putExtra("foo", "bar");
context.startService(i);
}
}
Here is the Service:
public class MainIntentService extends IntentService {
int noteID = 1;
String chanelID;
public MainIntentService() {
super("MainIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
chanelID = getString(R.string.channel_ID);
Toast.makeText(this, "My Service Started", Toast.LENGTH_LONG).show();
// Do the task here
createNotificationChannel();
popNotif();
}
public void onDestroy() {
Toast.makeText(this, "My Service Stopped", Toast.LENGTH_LONG).show();
}
private void popNotif() {
// Create an explicit intent for an Activity in your app
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, chanelID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("My notification")
.setContentText("Hello World!")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
// Set the intent that will fire when the user taps the notification
.setContentIntent(pendingIntent)
.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(noteID, mBuilder.build());
}
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = getString(R.string.channel_name);
String description = getString(R.string.channel_description);
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(chanelID, name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
}
I am certain the alarm triggers the receiver.
Thank you!
I think that I found the problem. I reckon that my IntentService can not execute complexly because the BroadcastReceiver process is killed before it can do it. More info here.
What I did was simply to pop my notification in the receiver, but I guess a better solution would be to start another thread or to put it async.

Android foreground service notification not showing

I am trying to start a foreground service. I get notified that the service does start but the notification always gets suppressed. I double checked that the app is allowed to show notifications in the app info on my device. Here is my code:
private void showNotification() {
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);
Bitmap icon = BitmapFactory.decodeResource(getResources(),
R.mipmap.ic_launcher);
Notification notification = new NotificationCompat.Builder(getApplicationContext())
.setContentTitle("Revel Is Running")
.setTicker("Revel Is Running")
.setContentText("Click to stop")
.setSmallIcon(R.mipmap.ic_launcher)
//.setLargeIcon(Bitmap.createScaledBitmap(icon, 128, 128, false))
.setContentIntent(pendingIntent)
.setOngoing(true).build();
startForeground(Constants.FOREGROUND_SERVICE,
notification);
Log.e(TAG,"notification shown");
}
Here is the only error I see in relation:
06-20 12:26:43.635 895-930/? E/NotificationService: Suppressing notification from the package by user request.
It's because of Android O bg services restrictions.
So now you need to call startForeground() only for services that were started with startForegroundService() and call it in first 5 seconds after service has been started.
Here is the guide - https://developer.android.com/about/versions/oreo/background#services
Like this:
//Start service:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(new Intent(this, YourService.class));
} else {
startService(new Intent(this, YourService.class));
}
Then create and show notification (with channel as supposed earlier):
private void createAndShowForegroundNotification(Service yourService, int notificationId) {
final NotificationCompat.Builder builder = getNotificationBuilder(yourService,
"com.example.your_app.notification.CHANNEL_ID_FOREGROUND", // Channel id
NotificationManagerCompat.IMPORTANCE_LOW); //Low importance prevent visual appearance for this notification channel on top
builder.setOngoing(true)
.setSmallIcon(R.drawable.small_icon)
.setContentTitle(yourService.getString(R.string.title))
.setContentText(yourService.getString(R.string.content));
Notification notification = builder.build();
yourService.startForeground(notificationId, notification);
if (notificationId != lastShownNotificationId) {
// Cancel previous notification
final NotificationManager nm = (NotificationManager) yourService.getSystemService(Activity.NOTIFICATION_SERVICE);
nm.cancel(lastShownNotificationId);
}
lastShownNotificationId = notificationId;
}
public static NotificationCompat.Builder getNotificationBuilder(Context context, String channelId, int importance) {
NotificationCompat.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
prepareChannel(context, channelId, importance);
builder = new NotificationCompat.Builder(context, channelId);
} else {
builder = new NotificationCompat.Builder(context);
}
return builder;
}
#TargetApi(26)
private static void prepareChannel(Context context, String id, int importance) {
final String appName = context.getString(R.string.app_name);
String description = context.getString(R.string.notifications_channel_description);
final NotificationManager nm = (NotificationManager) context.getSystemService(Activity.NOTIFICATION_SERVICE);
if(nm != null) {
NotificationChannel nChannel = nm.getNotificationChannel(id);
if (nChannel == null) {
nChannel = new NotificationChannel(id, appName, importance);
nChannel.setDescription(description);
nm.createNotificationChannel(nChannel);
}
}
}
Remember that your foreground notification will have the same state as your other notifications even if you'll use different channel ids, so it might be hidden as a group with others. Use different groups to avoid it.
The problem was i am using Android O and it requires more information. Here is the successful code for android O.
mNotifyManager = (NotificationManager) mActivity.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) createChannel(mNotifyManager);
mBuilder = new NotificationCompat.Builder(mActivity, "YOUR_TEXT_HERE").setSmallIcon(android.R.drawable.stat_sys_download).setColor
(ContextCompat.getColor(mActivity, R.color.colorNotification)).setContentTitle(YOUR_TITLE_HERE).setContentText(YOUR_DESCRIPTION_HERE);
mNotifyManager.notify(mFile.getId().hashCode(), mBuilder.build());
#TargetApi(26)
private void createChannel(NotificationManager notificationManager) {
String name = "FileDownload";
String description = "Notifications for download status";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel mChannel = new NotificationChannel(name, name, importance);
mChannel.setDescription(description);
mChannel.enableLights(true);
mChannel.setLightColor(Color.BLUE);
notificationManager.createNotificationChannel(mChannel);
}
For me everything was set correctly (also added FOREGROUND_SERVICE permission to manifest),
but I just needed to uninstall the app and reinstall it.
If none of the above worked you should check if your notification id is 0 ...
SURPRISE!! it cannot be 0.
Many thanks to #Luka Kama for this post
startForeground(0, notification); // Doesn't work...
startForeground(1, notification); // Works!!!
if you are targeting Android 9(Pie) api level 28 and higher than you should give FOREGROUND_SERVICE permission in manifest file.see this link : https://developer.android.com/about/versions/pie/android-9.0-migration#bfa
I can not believe it. In my case, after adding 'android:name=".App"' to AndroidManifest.xml, the notification started showing.
Example:
<application
android:name=".App"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
For Android API level 33+ you need to request POST_NOTIFICATIONS runtime permission. Although this doesn't prevent the foreground service from running, it's still mandatory to notify as we did for < API 33:
Note: Apps don't need to request the POST_NOTIFICATIONS permission in order to launch a foreground service. However, apps must include a notification when they start a foreground service, just as they do on previous versions of Android.
See more in Android Documentation.
In my case, it was caused by me using IntentService.
In short, if you want a foreground service then subclass Service.

Categories

Resources