Notification bar icon turns white in Android from FCM - java

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

Related

Android PendingIntent not launching activity after opened from background from notification

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);
}

Launch screen from native background service

I have a simple Flutter app that start a native background service using MethodChannel. This native background service notify my Flutter app using BasicMessageChannel<String> to display text when a particular native information is catched. All of this work perfectly when my app is in foreground. When an other app is in foreground, I can't see the text without having to switch to my app.
I want that my native service can display a particular Flutter screen even if an other application is running in foreground.
It can be perceived as not user friendly, but this is an message of utmost importance.
Any suggestion or solution will be welcome !
Note : Native service is for the moment only available in Java for Android, I'm working on C# for IOS side.
On Android you need to display a high priority notification. This displays the slide-down notification panel which will appear over the lock screen or another app. Since you are using native code already, you can create this notification there, or send a message to the Dart side (as you are doing, using MethodChannel) where it can use the flutter_local_notifications plugin to display it. When the user click the notification, your flutter app is brought to the foreground. In Java you might use code similar to this:
// Create an intent which triggers the fullscreen notification
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.setAction("SELECT_NOTIFICATION");
Class mainActivityClass = getMainActivityClass(context);
intent.setClass(context, mainActivityClass);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Build the notification as an ongoing high priority item to ensures it will show as
// a heads up notification which slides down over top of the current content.
final Notification.Builder builder = new Notification.Builder(context, CHANNEL_ID);
builder.setOngoing(true);
// Set notification content intent to take user to fullscreen UI if user taps on the
// notification body.
builder.setContentIntent(pendingIntent);
// Set full screen intent to trigger display of the fullscreen UI when the notification
// manager deems it appropriate.
builder.setFullScreenIntent(pendingIntent, true);
// Setup notification content.
int resourceId = context.getResources().getIdentifier("app_icon", "drawable", context.getPackageName());
builder.setSmallIcon(resourceId);
builder.setContentTitle("Your notification title");
builder.setContentText("Your notification content.");
MyPlugin.notificationManager().notify(someId, builder.build());
Then, for Android 8.1 or higher, add the following to your MainActivity class, found under the android/app/src/main/java/packageName/ folder
GeneratedPluginRegistrant.registerWith(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(true);
setTurnScreenOn(true);
}
(This shows the Flutter app even when the screen is locked.)
Flutter only has one activity, so the above code will bring that Flutter activity to the foreground (note that you don't always see the notification, but sometimes you do - if you set it to autoCancel then touching it clears it). It's up to you to build the correct screen in Flutter, which you can do as you send the notification. Use Navigator.push or equivalent to change the page that Flutter is showing.

Firebase Cloud Messaging Notification only shows when I open the "notification tab"

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

Android NotificationCompat.Builder works with three buttons but not four

I have a notification which includes buttons to control a media player. As implemented below, everything works fine.
Notification notification = builder
.setContentText(contentText)
.setSmallIcon(icon)
.setWhen(System.currentTimeMillis())
.setContentIntent(pendingIntent)
.setContentTitle(
getResources().getString(R.string.notification_title))
.addAction(R.drawable.ic_action_previous, "", previousPendingIntent)
// Adding this causes uglyness
// .addAction(R.drawable.ic_action_rewind20, "", jumpBackPendingIntent)
.addAction(playPauseIcon, "", playPausePendingIntent)
.addAction(R.drawable.ic_action_next, "", nextPendingIntent)
.build();
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(uniqueid, notification);
However, when I comment out the line
.addAction(R.drawable.ic_action_rewind20, "", jumpBackPendingIntent)
The third buttons gets kicked out.
The Android documentation on this is pretty sparse. Nothing in the addAction docs implies that there's a limit.
Clearly all of the buttons could fit in the notification. What am I missing?
Full Source Code
Update adneal's link to the latest code here as an answer:
A notification in its expanded form can display up to 3 actions, from
left to right in the order they were added.

Notification DeleteIntent broken on later versions of Android

In our app OneBusAway Android (open-source on Github), we need to be notified when the user dismisses a particular reminder notification, so we don't post another reminder notification for the same event (how long until their bus arrives).
We're doing this by listening for an Intent in our app, registered as the DeleteIntent with the Notification. When the user dismisses the notification (either by swiping it away, or tapping the clear button in the notification window), our app should receive that Intent.
From testing, it seems that with the current version on Google Play (and the current master branch on Github), the DeleteIntent is never received in our application in the following versions of Android:
Android 4.4.3
Android 4.4.4
However, the exact same code DOES work (i.e., the Intent registered as the DeleteIntent is received by the app) on:
Android 2.3.3
Android 2.3.6
Android 4.1.1
Android 4.1.2
I've looked at the following SO posts that deal with DeleteIntent, and none of the solutions listed work on Android 4.4.3 and 4.4.4:
Notification Auto-Cancel does not call DeleteIntent
Android - DeleteIntent, how to use?
Notification deleteIntent does not work
https://stackoverflow.com/questions/24218626/how-to-detect-notification-cancel-event-in-android-not-deleteintent
https://stackoverflow.com/questions/22769523/why-my-deleteintent-is-not-working-on-my-notification
Android deleteIntent not working? What's wrong with my code?
Custom actions using implicit intents between applications
The current working master branch uses a Service to listen for the Intent. However, based on some of the above posts, I did tweak some of the code to be more in line with working examples that use a BroadcastReceiver to listen for the Intent.
The code using the BroadcastReceiver is in the following Github branch:
https://github.com/CUTR-at-USF/onebusaway-android/tree/issue104-RepeatingReminders
Below are excerpts for what my current version looks like (that still works on Android 4.1.2 and lower, but not 4.4.3 or 4.4.4), along with links to Github source:
Creating the notification
https://github.com/CUTR-at-USF/onebusaway-android/blob/issue104-RepeatingReminders/onebusaway-android/src/main/java/com/joulespersecond/seattlebusbot/tripservice/NotifierTask.java#L131
private Notification createNotification(Uri alertUri) {
//Log.d(TAG, "Creating notification for alert: " + alertUri);
Intent deleteIntent = new Intent(mContext, AlarmReceiver.class);
deleteIntent.setAction(TripService.ACTION_CANCEL);
deleteIntent.setData(alertUri);
return new NotificationCompat.Builder(mContext)
.setSmallIcon(R.drawable.ic_stat_notification)
.setDefaults(Notification.DEFAULT_ALL)
.setOnlyAlertOnce(true)
.setDeleteIntent(PendingIntent.getBroadcast(mContext, 0,
deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT))
.setAutoCancel(true)
.build();
}
Title and other dynamic notification info are set a few lines later (and reset later, if the notification remains undismissed):
#SuppressWarnings("deprecation")
private void setLatestInfo(Notification notification,
String stopId,
String routeId,
long timeDiff) {
final String title = mContext.getString(R.string.app_name);
final PendingIntent intent = PendingIntent.getActivity(mContext, 0,
new ArrivalsListActivity.Builder(mContext, stopId).getIntent(),
PendingIntent.FLAG_UPDATE_CURRENT);
notification.setLatestEventInfo(mContext,
title,
getNotifyText(routeId, timeDiff),
intent);
}
TripService contains the constants for the action:
public static final String ACTION_CANCEL =
"com.joulespersecond.seattlebusbot.action.CANCEL";
AlarmReceiver
https://github.com/CUTR-at-USF/onebusaway-android/blob/issue104-RepeatingReminders/onebusaway-android/src/main/java/com/joulespersecond/seattlebusbot/AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
private static final String TAG = "AlarmReceiver";
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "In onReceive with intent action " + intent.getAction());
...
}
}
AndroidManifest
https://github.com/CUTR-at-USF/onebusaway-android/blob/issue104-RepeatingReminders/onebusaway-android/src/main/AndroidManifest.xml
<receiver android:name=".AlarmReceiver">
<!-- These action names must match the constants in TripService -->
<intent-filter>
<action android:name="com.joulespersecond.seattlebusbot.action.SCHEDULE" />
<action android:name="com.joulespersecond.seattlebusbot.action.POLL" />
<action android:name="com.joulespersecond.seattlebusbot.action.CANCEL" />
</intent-filter>
</receiver>
With the above, on Android 4.4.3/4.4.4, the AlarmReceiver never sees the Intent when the user dismisses the notification.
I also tried adding a MIME type, as specified in Custom actions using implicit intents between applications, but that didn't work on Android 4.4.3/4.4.4 either:
Intent deleteIntent = new Intent(mContext, AlarmReceiver.class);
deleteIntent.setAction(TripService.ACTION_CANCEL);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
deleteIntent.setDataAndTypeAndNormalize(alertUri, TripService.REMINDER_MIME_TYPE);
} else {
deleteIntent.setDataAndType(alertUri, TripService.REMINDER_MIME_TYPE);
}
return new NotificationCompat.Builder(mContext)
.setSmallIcon(R.drawable.ic_stat_notification)
.setDefaults(Notification.DEFAULT_ALL)
.setOnlyAlertOnce(true)
.setDeleteIntent(PendingIntent.getBroadcast(mContext, 0,
deleteIntent, 0))
//.setLights(0xFF00FF00, 1000, 1000)
//.setVibrate(VIBRATE_PATTERN)
.build();
REMINDER_MIME_TYPE is application/vnd.com.joulespersecond.seattlebusbot.reminder
Manifest for using the MIME type:
<receiver android:name=".AlarmReceiver">
<!-- These action names must match the constants in TripService -->
<intent-filter>
<action android:name="com.joulespersecond.seattlebusbot.action.SCHEDULE" />
<action android:name="com.joulespersecond.seattlebusbot.action.POLL" />
<action android:name="com.joulespersecond.seattlebusbot.action.CANCEL" />
<data android:mimeType="application/vnd.com.joulespersecond.seattlebusbot.reminder" />
</intent-filter>
</receiver>
I also tried not using the support library (i.e., using Notification.Builder instead of NotificationCompat.Builder), but that didn't change anything either.
Any ideas why this isn't working on Android 4.4.3/4.4.4?
More info is shown in the Github issue for this problem.
EDIT
I've also replicated this issue in a small Github project "DeleteIntentDemo":
https://github.com/barbeau/DeleteIntentDemo
Instructions to reproduce are in the README for this project.
EDIT 2
This appears to be due to a bug in Android in Notification.setLatestEventInfo() - I've reported it here:
https://code.google.com/p/android/issues/detail?id=73720
Please see #CommonsWare's answer for the workaround.
EDIT 3
My AOSP patch to fix this issue has now been merged so this problem won't appear for legacy apps in future releases of Android:
https://code.google.com/p/android/issues/detail?id=73720#c4
However, in the above AOSP thread is it emphasized that one should no longer be using Notification.setLatestEventInfo() - instead, use Notification.Builder to create a new Notification.
In your sample project, if you remove the following line, the deleteIntent works on a Nexus 4 running 4.4.4:
setLatestInfo(getActivity(), notification, routeId);
I suspect that this call is wiping out your deleteIntent. It may work to re-apply your deleteIntent to the Notification as part of your setLatestInfo() processing.
You must have a different problem because I'm able to receive the deleteintent in several 4.3 and 4.4 emulators.
I wanted to test your "simple" project but it uses Android Studio, so I made my own simpler test.
Steps to reproduce:
-Create an Activity and set the launch mode to singleInstance in the manifest.
-In the handler of a button or menu item, launch a notification:
Intent deleteIntent = new Intent(this, MainActivity.class);
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(android.R.drawable.ic_dialog_alert)
.setOnlyAlertOnce(true)
.setContentTitle("Notification delete intent test")
.setContentText("Please dismiss this notification by swipping or deleting it. A Toast will be shown if the deletion intent works.")
.setDeleteIntent(PendingIntent.getActivity(this, 0, deleteIntent, 0))
.setAutoCancel(true)
.build();
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.notify((int)System.currentTimeMillis(), notification);
-Override onNewIntent to show a toast or log a message when the notification is cancelled:
#Override
public void onNewIntent(Intent intent){
Toast.makeText(this, "Notification deleted!", Toast.LENGTH_LONG).show();
}
To dismiss the notification either swipe or press the clear button. It wont work pressing over it because autocancel is not considered an explicit user action and hence the delete intent wont be delivered.

Categories