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.
Related
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());
}
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
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)
I'm writing here because I'm facing a probleme that I could not resolve even after many researches and tries.
I'm currently developing an Android Library which consists only of java classes and fragment. The problem is I need to send Local Notifications to the user, and clicking on the notifications should send the user back to the activity where he was. At this point, my library sends the notifications just fine. But the click on the notification doesn't have any action.
In my notification reciver class (which extends the BroadcastReceiver class), when the notification appears, I create a Pending Intent but I don't know what I can give as parameters to send the user to the activity. I tried using intent filters but it give me no results
So how can I have the notification sending back the user to the application ? The best would be if I was able to have the notification sending back the user to the activity where the notification is created (but it's a fragment so...)
In an usual app, I would've an intent sending back the user to an activity class but my library needs to have only fragments.
Maybe there is no problem and the solution is easy since I'm new to notifications
If someone here have an idea thanks for helping me ! :D
And if my problem isn't clear (Because of my bad english as an example) don't hesitate to ask me to add informations ^^
**Edit from 29 April : **
I managed to achieve it by giving to my broadcast pending intent the canonical name of my class using :
mContext.getClass().getCanonicalName();
Once in my broadcast receiver class I just get the class from the name of the sending class :
Class<?> activityClass = null;
try {
activityClass = Class.forName(stringSourceClass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Check out below code...
public BroadcastReceiver batteryReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
try {
String title = context.getString(R.string.app_name);
Intent intent1 = new Intent(context, YourActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),1,intent1,PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(title)
.setContentText("Hello")
.setAutoCancel(false)
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, notificationBuilder.build());
} catch (Exception e) {
}
}
};
check the Building a notification page:
Intent resultIntent = new Intent(this, ResultActivity.class);
...
// Because clicking the notification opens a new ("special") activity, there's
// no need to create an artificial back stack.
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
this,
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
just put your activity in resultIntent
how can I have the notification sending back the user to the
application ?
That's pretty simple:
1. While creating intent for pending intent call addAction ("action_name") method;
2. In activity you want to call (in manifest file) inside intent-filter tag add <action android:name="action_name>.
Now when your notification try to launch activity it would send intent message to system, which would search activity with proper action and launch it.
P.S. action name must be unique for every application
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.