Support Topics Documentation Slack YouTube Blog

Obtaining custom notification header in Android

Hi @milen-marinov

Yes, you are right. The Android system reuses PendingIntents. That is why we create unique Intent each time by setting unique requestCode for it (notificationId * 3). So the system cannot reuse intents and creates new notification with new extras every time.
FLAG_UPDATE_CURRENT - is a

Flag indicating that if the described PendingIntent already exists, then keep it but replace its extra data with what is in this new Intent.
https://developer.android.com/reference/android/app/PendingIntent#FLAG_UPDATE_CURRENT

It means that if you send two notifications in a row with different extras, the extras in the notification that comes first will be replaced with a new one, from the last notification.

Here is a schema to be more clear:

  1. Notification 1 comes with extras 1.
  2. Notification 2 comes with extras 2.
  3. System detects that these two notifications has equal Intents. Because you set the flag FLAG_UPDATE_CURRENT, it modifies the second notification in the following way:

keep it but replace its extra data with what is in this new Intent.

It means that exras 1 in notification 1 will be replaced by extras 2.

  1. So now you have notification 1 with extras 2 and notification 2 with extras 2.
  2. If you click on notification 1 after this, you receive extras 2 that is not a correct behavior.

Can you please reproduce that scenario I’ve described and confirm it?

Also I will appreciate if you can check PendingIntents for equality and check if notificationIds is different for two different notifications in a debug session.

Best Regards,
Maksym

Hi @Maksym_Khobotin,

Thanks for the clarification! I now understand fully what is happening! Here are the logs from my test:

=== Debug session 1 ===
2019-08-11 15:26:25.488 10876-13125/org.helpapaw.helpapaw D/BackendlessFCMService: Bundle[{ios-category=kNotificationCategoryNewSignal, google.delivered_priority=normal, google.sent_time=1565526388424, google.ttl=2419200, google.original_priority=normal, messageId=message:F5349594-8AB8-4DEF-8774-29D7163E317E, ios-alert=Л1, ios-badge=1, ios-sound=default, from=960611584456, signalId=C882A24F-48DD-944E-FF98-0D4EA3CBC700, google.message_id=0:1565526388432993%56b7c464f9fd7ecd, message=Л1, BL_APPLICATION_ID=BDCD56B9-351A-E067-FFA4-9EA9CF2F4000}]
2019-08-11 15:28:52.842 10876-13125/org.helpapaw.helpapaw D/BackendlessFCMService: notificationId: 0
2019-08-11 15:29:56.546 10876-13125/org.helpapaw.helpapaw D/BackendlessFCMService: Bundle[{ios-category=kNotificationCategoryNewSignal, google.delivered_priority=normal, google.sent_time=1565526599324, google.ttl=2419200, google.original_priority=normal, messageId=message:EFB80473-BB97-4044-92B6-07DE6931D073, ios-alert=Л2, ios-badge=1, ios-sound=default, from=960611584456, signalId=D766E85F-DB30-2431-FFCA-052E784DC600, google.message_id=0:1565526599330682%56b7c464f9fd7ecd, message=Л2, BL_APPLICATION_ID=BDCD56B9-351A-E067-FFA4-9EA9CF2F4000}]
2019-08-11 15:29:56.860 10876-13125/org.helpapaw.helpapaw D/BackendlessFCMService: notificationId: 1
2019-08-11 15:31:13.982 10876-13125/org.helpapaw.helpapaw D/BackendlessFCMService: Bundle[{ios-category=kNotificationCategoryNewSignal, google.delivered_priority=normal, google.sent_time=1565526676845, google.ttl=2419200, google.original_priority=normal, messageId=message:56664A5E-304D-46E9-8E2E-9CEA2D5ED139, ios-alert=Л3, ios-badge=1, ios-sound=default, from=960611584456, signalId=EB0F218F-589E-19A9-FF9D-B0B35BF55B00, google.message_id=0:1565526676852475%56b7c464f9fd7ecd, message=Л3, BL_APPLICATION_ID=BDCD56B9-351A-E067-FFA4-9EA9CF2F4000}]
2019-08-11 15:31:14.288 10876-13125/org.helpapaw.helpapaw D/BackendlessFCMService: notificationId: 2
=== Debug session 2 ===
2019-08-11 15:32:42.704 13685-14095/org.helpapaw.helpapaw D/BackendlessFCMService: Bundle[{ios-category=kNotificationCategoryNewSignal, google.delivered_priority=normal, google.sent_time=1565526765602, google.ttl=2419200, google.original_priority=normal, messageId=message:23ADE9B4-B587-40E4-AA1A-968C8E93ACF7, ios-alert=Л4, ios-badge=1, ios-sound=default, from=960611584456, signalId=BDD0DB0F-4C18-E9BF-FFE4-27F6792B3000, google.message_id=0:1565526765606769%56b7c464f9fd7ecd, message=Л4, BL_APPLICATION_ID=BDCD56B9-351A-E067-FFA4-9EA9CF2F4000}]
2019-08-11 15:32:43.121 13685-14095/org.helpapaw.helpapaw D/BackendlessFCMService: notificationId: 0

As you can see notificationId is restarted in each debug session. Looking at the code:
private static AtomicInteger notificationIdGenerator;

The field is static which means its value is kept between instances of BackendlessFCMService. However, when the whole app is killed this field is destroyed, too. So, next time you start the app the counter starts again from 0. This behaviour is not limited to debugging as the app might be killed manually by the user, automatically by the system, etc. Indeed, my tests confirm that manually killing and starting the app resets the counter.
I would suggest using a different mechanism for generating unique notificationIds. As in practice the SDK never updates sent notifications (which is the reason notificationIds exist) you can use a random int or maybe base it on the notification’s timestamp.

Best Regards,
Milen Marinov

Hi, @milen-marinov

It’s very strange behaviour.
The notificationId is generated by notificationIdGenerator. And its value is saved to shared preferences each time the service stops in onDestroy method. You can look at this code here:

So even if I force-stop the application, the value of notificationId is saved and then restored from Android Shared Preferences.
I can only come up with one scenario, when the value can be resetted - if you clear the application data. In this case id counter resets and starts counting from 0.
I tried to reproduce this issue many times, but the counter didn’t reset any single time. Only if I clear the app data on my phone - it resets (but this is expected behavior in this case).

How do you restart your application? Which steps do you follow between debug sessions?
What do you mean by

manually killing and starting the app

?

Also do you test this behavior with different android versions?

I will be glad to hear your answers and to assist you further!

Best Regards,
Maksym

Hi @Maksym_Khobotin,

About your question:

In the debug scenario:

  1. Press Debug in the IDE
  2. Press Stop in the IDE
  3. Press Debug in the IDE

In the manual restart scenario:

  1. Start app from launcher
  2. Tap Task Manager key and swipe away the app
  3. Start app from launcher

I cannot easily test if onDestroy is called in the manual restart scenario. I just tested the debug one and onDestroy is not called when you press Stop. However, as this only happens when debugging, the strange behaviour is something that can be ignored (if you know about it and that it only happens during debugging).

Best Regards,
Milen Marinov

Hi @milen-marinov!

I finally reproduced your issue! It only happens on devices with Android 9. Seems like Android changed the Service logic for the new version of OS. We are now working on this issue and will let you know once it will be fixed.
Internal ticket: 19360.
Thank you a lot for pointing out this problem. We really appreciate it!

Best Regards,
Maksym

1 Like

Hi @Maksym_Khobotin,

That’s great! Thanks a lot!

Best Regards,
Milen Marinov

Hey @milen-marinov

Can you please try the use-case again with version 5.3.1 of Backendless SDK for Android? Please let us know the results

Anton

Hello @anton-govorushkin,

Checked it with 5.3.1 but unfortunately the behaviour is unchanged!

Best Regards,
Milen Marinov

Oups, sorry @milen-marinov :slight_smile:

I hurried to ask for it, fix is already made but will be available in 5.3.2 in a few days! Sorry for disturbing

Anton