I am able to create notifications. Currently when a user gets a friend request, it says "New friend request from someUsername". However, if the user receives multiple friend requests, I want to update the text to say "New friend requests."
From my understanding, I just have to change the text using the same Builder object I used to create the initial notification.
My idea was to create a HashMap mapping all the IDs used in NotificationManager's notify( int id, Builder builder ) to the Builder objects.
When a notification is clicked, the notification disappears (due to my use of setAutoCancel(true) ), however, I don't know how to detect this so I can remove the Builder object from the HashMap as well.
The reason I would like to remove the Builder object is because when the HashMap's get(id) method returns null, I'll know to display "New friend request from " instead of "New friend requests".
If my algorithm is over-complicated, by all means correct me. Otherwise, how can I detect when a notification is canceled?
Side note: I plan on doing this same thing for messages and possibly other kinds of notifications.
In case it's needed, this is my function that creates the notifications (the id is hardcoded for now):
private void triggerNotification(String content, Context context) {
Log.i("Thread", "notification triggered");
NotificationCompat.Builder builder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Anime Chatter")
.setContentText( content );
builder.setAutoCancel( true );
Intent i = new Intent(context, Friends.class);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, i, 0);
builder.setContentIntent(contentIntent);
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService( Context.NOTIFICATION_SERVICE );
mNotificationManager.notify( 1010, builder.build());
}
The most solid way to go at this is to create a dedicated table to deal with notifications.
That may be too much work, but it's how the biggest apps deal with notifications - which has been seen and which hasn't etc.
For a more simple approach just add some code in your activity, when dealing with the intent, that tracks the last notification clicked in a persistent way (SharedPrefs?) so that whatever controller is dispatching the notifications knows if there should be more than one notification to be seen or not (for example if the user dismisses a notification without clicking on it, there is still more than one friend request he doesnt know about). This controller should also keep track of the last sent notification (SharedPrefs again). This way when the controller dispatches the notification it can compare the last sent and the last clicked and see if there is only one, or several.
Seems pretty straight forward to me. Can help you with code if needed.
What you're looking for is Notification.Builder#setDeleteIntent(PendingIntent).
The pending intent you set here (you should wrap a Broadcast Intent) will be fired when the notification is canceled by the user. You can respond to the broadcast and update your persistent storage (db, shared prefs, whatever) where you're keeping track of active notifications to determine what you should show when the next one comes in.
Related
I'm having trouble with notifications on Android. I use the code below to generate a notification on the device whenever a GCM message is received by my app. However, it's producing unexpected results.
public class MyGcmListenerService extends GcmListenerService implements Constants {
private static final String TAG = "MyGcmListenerService";
#Override
public void onMessageReceived(String from, Bundle data) {
String message = data.getString("msg");
sendNotification(message);
}
private void sendNotification(String message) {
NotificationManager notificationManager =
(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = getString(R.string.gcm_notification_channel_name);
String description = getString(R.string.gcm_notification_channel_description);
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel(GCM_NOTIFICATION_CHANNEL_ID, name,
importance);
channel.setDescription(description);
channel.setLockscreenVisibility(NotificationCompat.VISIBILITY_PUBLIC);
channel.enableVibration(true);
channel.setSound(defaultSoundUri,
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT)
.build());
notificationManager.createNotificationChannel(channel);
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this,
GCM_NOTIFICATION_CHANNEL_ID)
.setContentText(message)
.setContentTitle("My Title")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setDefaults(Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setSmallIcon(R.drawable.ic_notification);
notificationManager.notify(0, notificationBuilder.build());
}
}
If a GCM message is received whilst the app is open (not just running, but actually open on the screen), then the resulting notification has only a title, and doesn't show the message. This screenshot demonstrates this case. Further, if I send multiple GCM messages to the device whilst the app is in the foreground, only one is displayed.
If a message is received whilst the app is either closed or running in the background, the resulting notification shows only the message, and has no title. This screenshot shows the two messages side-by-side - the bottom one was received with the app in the foreground, the top was received with the app in the background. If multiple messages are received whilst the app is in the background, all are displayed (in contrast to what happens when the app is in the foreground). This screenshot shows that multiple messages are displayed when they're received with the app in the background.
Also, the notification only appears as heads-up when the app is in the foreground.
Finally, if received in the foreground, the resulting notification does nothing when tapped. However, if received in the background, the notification opens the app when tapped. Not really bothered by this, just thought it might be indicative of the problem.
FYI: when testing, I tried both keeping the GCM message the same every time, as well as varying it. Both scenarios gave the same result.
What I'd like to figure out:
How to get both the title and message to display regardless of whether app is in foreground or not. This is the most important.
How to get the notification to appear as heads-up when the app is in the background.
Just to pre-empt any responses saying not to abuse heads-up, it's the most important feature of the app (the app must notify users of certain events in real-time), according to our users.
Update:
Bas van Stein's answer allowed me to figure out why the either only the title or message was displayed.
As he correctly pointed out, when the app is in the background, GCM messages are handled by the system. This drove me to inspect the script that is used to send messages by the backend. I realised that the person who wrote this script had sent the message within the title field of the notification field of the GCM message, and there was no body field. So I corrected this issue, and the notifications displayed correctly (for app in background).
This also allowed me to realise that the line String message = data.getString("msg"); in onMessageReceived was returning null. I changed the method as follows:
public void onMessageReceived(String from, Bundle data) {
Bundle notification = data.getBundle("notification");
String title = notification.getString("title");
String message = notification.getString("body");
sendNotification(title, message);
}
Then I added title as a parameter to sendNotification and changed the line that sets the notification title to: .setContentTitle(title). Now notifications are displayed correctly when the app is in the foreground.
Further, I added a static int to the class that I use as the notification ID (incremented every time), so now multiple notifications display correctly.
Still not solved:
I'm still unable to have notifications appear as heads-up when the app is in the background. I tried adding "priority": "high" to the GCM message notification payload, but this had no effect - apparently this is the default for a GCM notification anyway.
This answer will be only a part of the complete solution but here we go:
First issue, the background and foreground notifications seem to be generated by two different functions, you can test this by applying a break point in your code and attach the debugger. You will likely see that the background notification is not triggering the break point in this code. Perhaps you miss a manifest service?
Second issue, that only one notification is being shown is because of this line:
notificationManager.notify(0, notificationBuilder.build());
The 0 here is the notification id, if you create multiple notifications with the same id it will overwrite the notification instead of showing a new one.
Third issue, that the application is not opened on notification tab, is because there is no intent attached to the notification you generate in your code.
You can use something like this for an intent:
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_ONE_SHOT);
notificationBuilder.setContentIntent(pIntent);
The intent is being called when you click on the notification, this could be any intent so you can open a special activity for example.
Hope this brings you in the correct direction.
I'm wondering how to create a notification in android with action icons that allowed me to call a method in the main activity.
just like the one in this image : Notification icon exemple
First Welcome to stackoverflow. I'd like to remind you this is not a website to learn how to program but a website to ask questions with actual problems that can help the community. Your questions have to be detailed and specific with your code or attempt as well as the error log.
That being said, here is the best way to create a notification:
Step 1 - Create Notification Builder
First step is to create a notification builder using NotificationCompat.Builder.build(). You can use Notification Builder to set various Notification properties (small icons, large icons, title, priority etc)
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
Step 2 - Setting Notification Properties
Once you have Builder object, you can set its Notification properties using Builder object as per your requirement. But this is mandatory to set at least following −
A small icon, set by setSmallIcon()
A title, set by setContentTitle()
Detail text, set by setContentText()
mBuilder.setSmallIcon(R.drawable.notification_icon);
mBuilder.setContentTitle("I'm a notification alert, Click Me!");
mBuilder.setContentText("Hi, This is Android Notification Detail!");
Step 3 - Attach Actions
This is optional and only required if you want to attach an action with the notification. An action will allows users to go directly from the notification to an Activity in your application (where they can look at one or more events or do further work).
The action is defined by a PendingIntent containing an Intent that starts an Activity in your application. To associate the PendingIntent with a gesture, call the appropriate method of NotificationCompat.Builder.
For example, if you want to start Activity when the user clicks the notification text in the notification drawer, you add the PendingIntent by calling setContentIntent().
A PendingIntent object helps you to perform an action on your application's behalf, often at a later time, regardless whether or not your application is running.
Also there's the stackBuilder object which will contain an artificial back stack for the started Activity. This ensures that navigating backward from the Activity leads out of your application to the Home screen.
Intent resultIntent = new Intent(this, ResultActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(ResultActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
Step 4 - Issue the notification
Finally, you pass the Notification object to the system by calling NotificationManager.notify() to send your notification. Make sure you call NotificationCompat.Builder.build() method on builder object before notifying it. This method combines all of the options that have been set and return a new Notification object.
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// notificationID allows you to update the notification later on.
mNotificationManager.notify(notificationID, mBuilder.build());
I hope this answers your question.
My Activityhosts 3 tabs and each tab is a Fragment.
I also have a Service which query a database perdiodically. Depending on the result of the query, I raise a Notification (from the Service).
When I click on the Notification, is it possible to launch a specific fragment? If yes, how can I do so?
Here is what I've done so far, in my Service class:
// When notification is clicked, go back to TabOperations Fragment
Intent i = new Intent(this, TabOperations.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, i,PendingIntent.FLAG_UPDATE_CURRENT); // Give the phone access to the app
notification.setContentIntent(pi);
// Issue notification
NotificationManager nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
nm.notify(UNIQUE_ID, notification.build());
Of course, this does not work.
Any advice?
Instead of the Service sending a Notification, perhaps you would be better off with a different messaging system. For example, you can utilize the Observer pattern (or third-party libraries like EventBus) to send a message from the Service to the Activity that cares about such events. The activity can then use the event to start and attach the Fragment as necessary.
I am working on an Android application in which I have to compare current time , with a time (saved) in a file, though everything is working fine. I have use services and in service i have use THREAD to run the service infinitely, and in addition to this i have also used PARTIAL_WAKE_LOCK to continue service even the device is sleep but the issue is that instead of acquiring PARTIAL_WAKE_LOCK my service runs for 1/2 hours and then again go to sleep. I don't want to acquire FULL_WAKE_LOCK. Is there any one who can guide me what i have to do in order to run this comparison, i.e. my service will run perfectly once the user set the time.
Thank you in advance.
You are doing it the wrong way. To create permanent service you must
declare it as foreground. No other way about it:
myService.startForeground(MY_NOTIFICATION_ID, my_notification);
If your interest with such a service is to periodically perform fast-ending
actions, and if the in between periods are long, you probably want to use
the alarm API and improve your app's battery consumption.
Edit:
To set a foreground service you must supply the system with a notification
object to be displayed at notification bar for as long as the service is in foreground
Why is that? Because foreground services cannot be killed, and Android needs to know
that the user is aware of that fact.
Setting as foreground:
static final int NOTIF_ID = 100;
// Create the FG service intent
Intent intent = new Intent(getApplicationContext(), MyActivity.class); // set notification activity
showTaskIntent.setAction(Intent.ACTION_MAIN);
showTaskIntent.addCategory(Intent.CATEGORY_LAUNCHER);
showTaskIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pIntent = PendingIntent.getActivity(
getApplicationContext(),
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
Notification notif = new Notification.Builder(getApplicationContext())
.setContentTitle(getString(R.string.app_name))
.setContentText(contentText)
.setSmallIcon(R.drawable.ic_notification)
.setContentIntent(pIntent)
.build();
startForeground(NOTIF_ID, notif);
And reverting to 'stardard' service mode:
stopForeground(true).
Both setting to foreground and reverting to background can be called by either the service itself (e.g. its onCreate() method) or by external code (e.g. the activity that initiated the service). No problems here.
I'm learning how to make apps for android and I have started by creating one which makes my phone scream when its dropped.
I got it working to where the phone screams when dropped, but now I need to make it so that the phone screams when dropped even when the app is closed, and to show a notification in the notification bar saying that its running
What should I use to do this? Should I use intentService? Ive been looking all over and I'm not sure where to look. Any guides would be appreciated
You need to make your service run in the foreground. You can achieve this by showing a notification when your service is running.
This is how you need to make your service run as foreground
private void showNotification(String title)
{
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(title);
startForeground(1000,mBuilder.build()); // 1000 - is Id for the notification
}
You can also set your custom RemoteViews in notification using setContent
You can remove the service from foreground state using stopForeground
check Service Training.
For your use case it's important that it's an foreground service:
Documentation Service