So I got push-notifications working with Google's Firebase Cloud Messaging. The only problem now is that the notification doesn't show any alert, only if I pull down the notification drawer that I see it's there.
I've got this part of the code where I think that "popup" feature is added
public void displayNotification(String title, String body){
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mContext, Constants.CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(body);
Intent intent = new Intent(mContext, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(mContext,0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pendingIntent);
NotificationManager mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
if(mNotificationManager != null) {
mNotificationManager.notify(1, mBuilder.build());
}
}
Other problem I have is that when I click the notification, it opens the activity but doesn't delete the notification.
Foreground pop-up
Under the builder, you are required to set high or max priority as well as the default notification vibration / sound so that you can see the 'pop-up' window
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setDefaults(NotificationCompat.DEFAULT_ALL);
Background pop-up
To achieve background pop-up, you need to fine-tune your FCM payload. If you have both data and notification in your payload, the pop up cannot be handled by your displayNotification method. You will need a data only payload.
Google has placed this behavior in the documentation.
Reference - FCM for android: popup system notification when app is in background
AutoCancel
For your second issue, add the setAutoCancel in your builder
.setAutoCancel(true)
Extra note
For some devices like Xiaomi and Redmi, you need to go to Settings to enable floating notification
Related
I'm using Google FCM to deliver notifications to my app. I am currently sending data notifications and having my android app construct the push notification. I want the user to be able to click on the notification and have it route them to the appropriate fragment/activity.
It is working great except for one flow.
User terminates app -> Receives notification -> Clicks notification -> App launches and data passed correctly to the splash activity from the notification (I'm using a notification activity to broadcast/start intents) -> User receives another notification while app is open -> User clicks notification -> Notification activity, which just previously launched correctly, does not launch.
I'm scratching my head trying to figure out why this could be. My guess is something to do with the contexts being wrong since the app is being launched from the notification, but I've tried to use both "this" and "getApplicationContext()" and neither fixed the issue.
Below is how I construct the notification and pending intent.
Intent notificationIntent = new Intent(this, NotificationActivity.class);
notificationIntent.putExtra(Variables.INTENT_NOTIFICATION_DATA, "dummy_data");
notificationIntent.setAction(Variables.NOTIFICATION_CLICK);
PendingIntent contentIntent = PendingIntent.getActivity(this,
0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(this, Variables.CHANNEL)
.setContentTitle("New Notification")
.setContentText("Dummy text")
.setSmallIcon(R.drawable.notification_icon)
.setContentIntent(contentIntent)
.setAutoCancel(true)
.setOngoing(false)
.build();
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (mNotificationManager != null) {
mNotificationManager.notify(0, notification);
}
I know that to support Lollipop Material design guidelines we have to make notification icon as transparent.
Here is my FCM onMessageReceived() function to show noticication.
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
NotificationCompat.Builder mBuilder;
mBuilder = new NotificationCompat.Builder(this)
.setContentTitle(remoteMessage.getNotification().getBody()) // title for notification
.setContentText(remoteMessage.getNotification().getTitle()) // message for notification
.setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND)
.setSmallIcon(getNotificationIcon())
.setAutoCancel(true); // clear notification after click
Intent intent = new Intent(this, CheckInListPage.class);
PendingIntent pi = PendingIntent.getActivity(this,0,intent,Intent.FLAG_ACTIVITY_NEW_TASK);
mBuilder.setContentIntent(pi);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
private int getNotificationIcon() {
boolean useWhiteIcon = (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP);
return useWhiteIcon ? R.drawable.logo_a_transparent : R.drawable.logo_notifc;
}
But here my issue is that when the application is running in foreground and visible, it will take my logo_a_transparent and will get desired result (screenshot - first icon in the notification bar).
But when we are pausing the application and an FCM push came, It takes my app icon (android:icon="#drawable/ic_launcher") as notification icon became white (screenshot - second icon in the notification bar).
Replacing app icon as transparent will work, But not a correct solution.
Add this line in your menifestfile set your resource as your choice add this one
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#mipmap/ic_notification" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="#android:color/transparent" />
With FCM, you can send two types of messages to clients applicatin
1) Notification messages,
2) Data messages
Here fcm doumentation
Notification Message calls onMessageReceived() only when the application is foreground. Notification messages are delivered to the notification tray when the app is in the background that's automatically handled by Android system rather than calling onMessageReceived(), The system uses app icon as notification icon that's why icon became white in background push. The android application needs not to be transparent.
In the case of Data Message whether the app is in the background or the foreground it will always be handled by onMessageReceived().
Data Message
{ "to" : "Ahd8fsdfu78sd...", "data" : {
"Name" : "...",
"body" : "...",
}
}
So I should use a data-only message payload or Messages with both notification and data payloads, so my onMessageReceived() can handle this and correct notification icon will displayed.
Fix at firebase 12.0.0. Just update your build.gradle to 12.0.0
https://firebase.google.com/support/release-notes/android#20180320
I'm trying to add special actions to a notification such that I can use my smartwatch to remote control the app.
That's my current code:
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentTitle("Control Notification");
builder.setContentText("With this notification I should be able to control the app with my watch.");
builder.setSmallIcon(R.drawable.ic_launcher);
Intent actionIntent = new Intent(this, MainActivity.class);
actionIntent.putExtra("action", true);
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0, actionIntent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.addAction(R.drawable.ic_launcher, "action", resultPendingIntent);
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(0, builder.build());
The problem is that each time I fire the action with my watch a new activity is opened on my phone. But I want to reuse the old activity. What do I have to change?
By the way: If you have any other tips or improvements concerning my code feel free to tell me.
The simplest way to achieve it is to declare your activity as a singleInstance in your AndroidManifest.xml file. You need to add android:launchMode="singleInstance" in related activity tag.
But it really depends on what exactly do you want to achieve. Using singleInstance launch mode it will reorder any existing instance of this activity to the front (so it will be removed from the old place in your stack).
Tell if it's OK for your structure:)
From what I have read it seems that code like this would require the app to be running in a thread until the notification fires. I need the notification to fire at a later date and time so the user sees the notification just like any other notification and then clicks it and it opens of an activity, passing in some data so the app knows what to do.
How can I make this notification fire days later without the app running the whole time?
Do I use wait to accomplish this?
long millis = 60000;
myNotification.wait(millis);
Here is my code which fires immediately
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(getActivity())
.setSmallIcon(R.drawable.star)
.setContentTitle("How was " + me.getString("EventTitle") + "?")
.setContentText("Click here to leave your review");
Intent resultIntent = new Intent(getActivity(), SetupActivity.class);
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
getActivity(),
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
int mNotificationId = me.getInt("EventID");
// Gets an instance of the NotificationManager service
NotificationManager mNotifyMgr =
(NotificationManager) getActivity().getSystemService(getActivity().NOTIFICATION_SERVICE);
// Builds the notification and issues it.
mNotifyMgr.notify(mNotificationId, mBuilder.build());
As A--C wrote, use AlarmManager to schedule a PendingIntent to be invoked at your desired time. You will probably use an RTC_WAKEUP alarm, meaning "the time is based on System.currentTimeMillis(), like Calendar uses" and "let's wake up the device out of sleep mode". Use a broadcast PendingIntent, and your Notification code can go into the onReceive() method, if you do not need to do any disk or network I/O to get the information to use for the Notification itself.
Note that in Android 4.4 the rules for AlarmManager changed a bit. You will want to use setExact() on Android 4.4+ and set() on earlier Android versions.
I am triying to do the following:
My app has an AsyncTask that eventually creates an AlertDialog to request the user to isert a code. This can happend when the app is in the foreground, so I launch a notification to inform the user and my idea is that once he clicks the notification, the main activity with the AlertDialog is shown.
Nevertheless what is happening is that once the user clicks on the notification, just the activity where the AlertDialog is supposed to be is shown and I get a WindowLeaked exception probably caused by the Dialog.
There is the code that I am using to launch the notification (from the method onProgressUpdate of the AsyncTask):
public void launch_notification(){
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(context.getString(R.string.opening_request_notification_title))
.setContentText(context.getString(R.string.opening_request_notification_text));
/* The intent must be created with an specific content and then frozen to be used
later using a pending intent.
*/
Intent notificationIntent = new Intent(context, Main.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
notificationBuilder.setContentIntent(pendingIntent);
notificationBuilder.setAutoCancel(true);
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
}
Any idea will be welcome.
Thanks a lot :)
Better to create a separate Activity(example DialogActivity) and in your manifest set for DialogActivity.
Your notification creation seems fine and you invoke the method from onProgressUpdate which is also fine.
So there must be something wrong with your activity and the way it handles the dialog.
If you could provide your Main class we could know for sure, but what I guess is happening that in your AsyncTask you show some sort of dialog, perhaps a progress dialog.
If that is the case then when you get the notification (on progress update) and you click it you start Main activity again, so you end up creating another instance of main activity, and hence the leaking window.
Try adding the flag FLAG_ACTIVITY_CLEAR_TOP.
As the API states:
If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.
Hope that this will help you out.