Get notification Title from BroadcastReceiver (direct reply Android N) - java

Since I'm building a messaging app, and there could be more than one notification with the direct reply, I need to be able to identify which one is sending the text in order to send the message to the right person... How could I achieve that ?
My thought was to get the title of the notification using extras, but I can't seem to get the extras in the BroadcastReceiver (in the Reply Reciever Activity). Extras only work when the notification is clicked and so dismissed (and so I can get the intent with the extra).
Here is the code of the notification :
resultIntent= new Intent(NotificationService.this, StartNAFromNS.class);
resultIntent.putExtra(Intent.EXTRA_TITLE, underestood_name.replace("__", " "));
int Unique_Code = Retrieve_int("Unique_Code", 0, this);
Unique_Code=Unique_Code+1;
Save_int("Unique_Code", Unique_Code, this);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(NotificationService.this);
stackBuilder.addParentStack(SearchActivity.class);
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =stackBuilder.getPendingIntent(Unique_Code,PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent replyPendingIntent = null;
if (Build.VERSION.SDK_INT >= 24) {
replyPendingIntent = PendingIntent.getBroadcast(
NotificationService.this,
0,
new Intent(NotificationService.this, ReplyReceiver.class),
PendingIntent.FLAG_UPDATE_CURRENT
);
}
RemoteInput remoteInput = new RemoteInput.Builder(KEY_NOTIFICATION_REPLY)
.setLabel("Tapez votre réponse ici")
.build();
android.support.v4.app.NotificationCompat.Action replyAction = new android.support.v4.app.NotificationCompat.Action.Builder(
0, "Répondre", replyPendingIntent)
.addRemoteInput(remoteInput)
.build();
miBuilder = new android.support.v4.app.NotificationCompat.Builder(NotificationService.this)
.setGroup("Groupe01")
.setShowWhen(true)
.setSubText(summary)
.setSmallIcon(R.drawable.ic_chat_bubble_outline_black_24dp)
.setContentTitle(mess_sender)
.setContentText(mess_contenu)
.setAutoCancel(true)
.setContentIntent(resultPendingIntent)
.setColor(getResources().getColor(R.color.colorPrimaryDark))
.setDefaults(Notification.DEFAULT_ALL)
.setPriority(Notification.PRIORITY_HIGH);
if (Build.VERSION.SDK_INT >= 24) {
miBuilder.addAction(replyAction);
}
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(notif_id, miBuilder.build());
Log.wtf("Notification", "Displayed");

To receive user input from the notification interface to the activity you declared in the reply action's intent:
Call getResultsFromIntent() by passing the notification action’s intent as the input parameter. This method returns a Bundle that contains the text response.
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
Query the bundle using the result key (provided to the RemoteInput.Builder constructor). You can complete this process and retrieve the input text by creating a method, as in the following code snippet:
// Obtain the intent that started this activity by calling
// Activity.getIntent() and pass it into this method to
// get the associated string.
private CharSequence getMessageText(Intent intent) {
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
if (remoteInput != null) {
return remoteInput.getCharSequence(KEY_NOTIFICATION_REPLY);
}
return null;
}
Build and issue another notification, using the same notification ID that you provided for the previous notification. The progress indicator disappears from the notification interface to inform users of a successful reply. When working with this new notification, use the context that gets passed to the receiver's onReceive() method.
// Build a new notification, which informs the user that the system
// handled their interaction with the previous notification.
Notification repliedNotification =
new Notification.Builder(context)
.setSmallIcon(R.drawable.ic_message)
.setContentText(getString(R.string.replied))
.build();
// Issue the new notification.
NotificationManager notificationManager =
NotificationManager.from(context);
notificationManager.notify(notificationId, repliedNotification);
For details, please have a look:https://developer.android.com/guide/topics/ui/notifiers/notifications.html (Retrieving user input from the inline reply)

Related

How to dismiss full screen intent to notification bar?

I am trying to display a notification about incoming call (from within my app) to a user. I found out that I can use NotificationCompat.Builder.setFullScreenIntent() to make a notification persistent on the top of the screen when application is running in the background.
However now when user does not answer the call and other party stops ringing how do I make that full screen intent disappear and show it inside a notification bar?
The only way I can think of is calling cancel() on that notification ID and creating a new one without full screen intent. But is this a good way of doing this? Is there a 'good practice' on how to achieve what I want?
Snippet showing how I create the notification:
public void displayNotification(String title, String text, int conversationId) {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
this.createNotificationChannel();
Intent intent = new Intent(context, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this.context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this.context, this.channelID);
builder.setContentTitle(title);
builder.setContentText(text);
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setFullScreenIntent(pendingIntent, true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this.context);
notificationManager.notify(conversationId, builder.build());
}

How to get data from firebase-message while Android app is in background

I'm sending firebase-messages using the firebase-console. The messages shall contain additional data like shown below with the purpose to open a specific URL within a webview in my app:
I set up my manifest and firebase class to get the messages. Within my firebase class I try to get the data:
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
if(remoteMessage.getData().containsKey("key1")) {
intent.putExtra("destination", remoteMessage.getData().get("key1"));
}
PendingIntent pendingIntent = PendingIntent.getActivity
(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
String channelId = "default";
NotificationCompat.Builder builder;
if (remoteMessage.getNotification() != null ) {
if (remoteMessage.getNotification().getTitle() != null) {
builder = new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_stat_onesignal_default)
.setContentTitle(remoteMessage.getNotification().getTitle())
.setStyle(new NotificationCompat.BigTextStyle().bigText(remoteMessage.getNotification().getBody()))
.setAutoCancel(true)
.setContentIntent(pendingIntent);
} else {
builder = new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_stat_onesignal_default)
.setStyle(new NotificationCompat.BigTextStyle().bigText(remoteMessage.getNotification().getBody()))
.setAutoCancel(true)
.setContentIntent(pendingIntent);
}
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(channelId, "default", NotificationManager.IMPORTANCE_DEFAULT);
manager.createNotificationChannel(channel);
}
manager.notify(0, builder.build());
}
}
Within my MainActivity class I try to get the data. When the app is in the foreground, the following works (no matter what activity is opened, it will jump to the MainActivity and execute the following):
#Override
protected void onNewIntent(Intent intent) {
if (intent.getExtras() != null) {
Bundle extras = intent.getExtras();
if(extras.containsKey("destination")) {
Log.e("FIREBASE_CONTAINS", (String) extras.get("destination"));
}
}
}
But the event wont trigger if the app started from the background. I tried to get the intent and check for the key within the onResume() event of the activity, but it does not work (Same in inCreate() and onStart()).
Can anybody help me?
------------EDIT-----------------
As described in one of the comments, the problem seems to be that Notification-Messages won't reach the onMessageReceived() event. Apparently the firebase console can't send data-notifications (which would reach the event) so I tried using POSTMAN. I've read that I have to leave the notification tag out of the message body and put all my information in the data section. But if I do so, the messages won't reach my app (they do, when I add the notification section again, but of course they are not reaching the onMessageReceived() event in that case).
There are 3 types of push messages
notification
data
and both
A push messages is basically a json payload:
payload:{
notificacion...
data
}
Rules for each type of push messages are differente. In your case you are using the Firebase web console and adding custom data, which mean your payload will have notification and data.
For the combined type the behaviour in backgroun is to use a default notificacion (NotificationCompat, the visual kind) and open the default activity registered in the manifest. In the activity you can get the data.
Lets say your default activity is called MainActivity
public class MainActivity {
onCreate...{
//... usual stuff
Intent fcmIntent = getIntent();
if fcmIntent != null
//check the extras and forward them to the next activity if needed
}
}
There are two type of push message
(1)Notification Message (will receive when app is in foreground)
(2)Data Message (will receive when app is in background+foreground)
Reference : https://firebase.google.com/docs/cloud-messaging/android/receive
You need to set click_action in firebase notification data set to be able to receive data from background and implement onMessageReceived to handle foreground data
See updated answer here: https://stackoverflow.com/a/73724040/7904082

update recycler view while receive fcm notification

I want to refresh my recycler view in fragment while receive FCM notification(if specific fragment is open) else receive notification.
I have tried multiple solutions, but that didn't work.
MyFirebaseMessagingService.java
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Map<String, String> data = remoteMessage.getData();
if (remoteMessage.getNotification() != null) {
String noti_body = remoteMessage.getNotification().getBody();
String noti_title = remoteMessage.getNotification().getTitle();
String noti_activity = data.get("activity");
mBuilder = new NotificationCompat.Builder(this, "M_CH_ID")
.setSmallIcon(R.mipmap.logo)
.setContentTitle(noti_title)
.setContentText(noti_body)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.logo))
.setColor(getResources().getColor(R.color.colorAccent))
.setDefaults(Notification.DEFAULT_ALL)
.setPriority(NotificationManager.IMPORTANCE_HIGH)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setAutoCancel(true); // clear notification after click
if (remoteMessage.getData().size() > 0) {
fragmentNewJobs c = new fragmentNewJobs();
if (c.getUserVisibleHint()) {//fragmentNewJobs.is_open
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("activity", noti_activity);
getApplicationContext().startActivity(intent);
}else {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("activity", noti_activity);
#SuppressLint("WrongConstant")
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);
mBuilder.setContentIntent(pi);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(0, mBuilder.build());
}
}
}
}
fragmentNewJobs c = new fragmentNewJobs();
if (c.getUserVisibleHint())
I have tried this, but it load fragmentNewJobs.java even I have opened any screen.
I want to refresh recyclerView in fragmentNewJobs.java only if fragmentNewJobs is open else receive notification.
I want to add only new item to recyclerView(not load all data if possible)
You can use Event Bus to publish message from receiver to particular fragment or activity.
And to findout if activity is visible or not have a look at this
Or if you are using fragment you can use static variable in Application class to track fragment(Most basic use)
i want to add only new item to recycler view(not load all data if
possible)
You can use BroadcastManager to send notification event to your existing Activity. Running Activity will add new item in List when it receive new broadcast.
Another option to notify Activity can be EventBus, that is fast growing, easy implementation library for notifying between Services, Activities and Fragments.
How to use BroadcastManager?
How to use EventBus?
i want to refresh recyclerview in fragmentNewJobs.java only if
fragmentNewJobs is open else receive notification.
For this you can take a static boolean in Application class, and make it true on Fragment's onResume() and make it false on onPause().
Then you can check Fragment's visibility by ApplicationClass.isFragmentVisible()
Edit
You can change fragmentVisible boolean inside setUserVisibleHint() of Fragment, that will work perfectly. You will need to make initially UserVisibleHint false because it is true default. Check this answer for better understanding.

How do I get the program to display multiple notifications on the screen?

i cant seem to understand how to display multiple notifications without one overlaying another. In my case it only displays one at the time.
picture 1
My goal is to get it to work like on the screenshot below
picture 2
What should I change or maybe add to my code?
chunk of code assigned for notifications
#Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
Intent intent = new Intent(ctx, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("com.example.romanchuk.appisode.notifyId", id);
intent.putExtra("com.example.romanchuk.appisode.show_id", show_id);
PendingIntent pendingIntent = PendingIntent.getActivity(ctx, sNotificationId /* Request code */, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
inboxStyle.addLine(message);
NotificationCompat.BigTextStyle bigText = new NotificationCompat.BigTextStyle();
bigText.bigText(message);
bigText.setBigContentTitle(getString(R.string.app_name));
NotificationCompat.Builder builder = new NotificationCompat.Builder(ctx);
Notification notification = null;
notification = builder.setSmallIcon(R.mipmap.ic_launcher).setTicker(title).setWhen(0)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.setColor(getResources().getColor(R.color.color_accent))
.setContentTitle("Appisode")
.setContentIntent(pendingIntent)
.setFullScreenIntent(pendingIntent, true)
.setContentText(message)
.setDefaults(Notification.DEFAULT_ALL)
.setAutoCancel(true)
.setStyle(inboxStyle)
.setSmallIcon(R.drawable.small_icon)
.setSound(defaultSoundUri).build();
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(sNotificationId++, notification);
}
If you want to show multiple notifications, You Notification id should be different, If the notification id already exists in the notifications it will override that notification.
notificationManager.notify(sNotificationId++, notification);
In this sNotificationId should be different for all notification
If your id or show_id is int and not constant and if it will be different for each notification you can use that also as notification id.
Or try to give different tag for each notification like this,
notificationManager.notify(String.valueOf(System.currentTimeMillis()), sNotificationId++, notification);

System notification from SyncAdapter:onPerformSync

I have sync adapter that performs some operation in background. To notify my main activity about sync operation status, I used broadcast receivers, so my activity is able to receive messages from sync adapter. It works fine. However, I also need to display notification on android status bar, that indicates some sync results.
So I wrote simple method reponsible to disaply system notification:
private void sendNotification(Context ctx, String message)
{
Intent intent = new Intent(ctx, this.getClass());
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(ctx)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Mobile Shopping")
.setContentText(message)
.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_SOUND | Notification.FLAG_SHOW_LIGHTS)
.setLights(0xff00ff00, 300, 100)
.setPriority(Notification.PRIORITY_DEFAULT);
//.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 , notificationBuilder.build());
}
Then, above method is called in onPerform sync:
#Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult)
{
.................
sendNotification(context, message);
}
Context is retrieved from constructor. It works without any problems, notification is showing.
However I also need to show main activity after user cicks on notification. So I believe I need to create PendingIntent and pass it to my notification builder (as it's commented in my code). But to pass main activity object to my sync adapter? Notification can be also displayed after auto sync finished.
Any tips?
So, I figured it out. Solution is to create pending intent this way:
Intent notificationIntent = new Intent(ctx, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 0, notificationIntent, 0);
So after user clicks to notification, main activity will be shown.

Categories

Resources