StatusBarNotification how to get data or resend intent?
Asked Answered
D

3

13

My Apps receives Push Notification via Firebase. Now there a 3 distinct situations that can happen when the notification arrives:

  1. The app is in the foreground
  2. The app is in the background
  3. The app is not running

Situation 1 is no problem. The notification is received in the app ok. Situation 2 and 3 work fine as long as you tap the notification in the drawer. In Situation 2 and 3 when the app icon is tapped instead of the drawer icon the app does not receive any notification at all. I've tried to get the active notifications from the StatusBar and that works but I can not either retrieve the data from the Extras or resend the notification to the waiting push notification service. Here's the experimental code to get the Notifications.

        NotificationManager notificationManager = (NotificationManager)Application.Context.GetSystemService(Context.NotificationService);

        var notifications = notificationManager.GetActiveNotifications()
            .Where(notif => notif.PackageName == Application.Context.PackageName);

        foreach (var notification in notifications)
        {
            Log.Info(TAG, "OnActivityResumed: Notification in active in Status Bar: {0}", notification.Notification.ToString());

            var data = notification.Notification.Extras.GetString("data");

            Log.Debug("Notifier", "Data received: {0}", data);

            //if (data != null)
            //{
            //    Settings.Notification = JsonConvert.DeserializeObject<LoginNotificationParameter>(data);
            //}
        }

        // Canceling all notifications
        notificationManager.CancelAll();

Questions:

  1. Is it correct behavior that the app does not receive any intents when a notification is in the drawer?
  2. If so how to I handle situations 2 and 3 when the user tapps the app icon instead of the drawer notification?

I see this data in het Notification when printing all the Extras Key Values:

06-28 16:34:13.174 20792 20792 I Notifier: OnActivityResumed: Notification is active in Status Bar: Notification(pri=0 contentView=null vibrate=null sound=content://settings/system/notification_sound defaults=0x0 flags=0x10 color=0x00000000 vis=PRIVATE semFlags=0x0 semPriority=0)
06-28 16:34:13.191 20792 20792 I Notifier: KeyIn: Extras Key: android.title Data: Login
06-28 16:34:13.191 20792 20792 I Notifier: KeyIn: Extras Key: android.subText Data:
06-28 16:34:13.191 20792 20792 I Notifier: KeyIn: Extras Key: android.template Data: android.app.Notification$BigTextStyle
06-28 16:34:13.192 20792 20792 I Notifier: KeyIn: Extras Key: android.showChronometer Data: false
06-28 16:34:13.192 20792 20792 I Notifier: KeyIn: Extras Key: android.text Data: Er is een inlogverzoek voor u ontvangen.
06-28 16:34:13.194 20792 20792 I Notifier: KeyIn: Extras Key: android.progress Data: 0
06-28 16:34:13.194 20792 20792 I Notifier: KeyIn: Extras Key: android.progressMax Data: 0
06-28 16:34:13.195 20792 20792 I Notifier: KeyIn: Extras Key: android.appInfo Data: ApplicationInfo{a27f281 nl.natuurnetwerk.notifier}
06-28 16:34:13.195 20792 20792 I Notifier: KeyIn: Extras Key: android.showWhen Data: true
06-28 16:34:13.195 20792 20792 I Notifier: KeyIn: Extras Key: android.largeIcon Data:
06-28 16:34:13.195 20792 20792 I Notifier: KeyIn: Extras Key: android.bigText Data: Er is een inlogverzoek voor u ontvangen.
06-28 16:34:13.195 20792 20792 I Notifier: KeyIn: Extras Key: android.infoText Data:
06-28 16:34:13.195 20792 20792 I Notifier: KeyIn: Extras Key: android.originatingUserId Data: 0
06-28 16:34:13.196 20792 20792 I Notifier: KeyIn: Extras Key: android.progressIndeterminate Data: false
06-28 16:34:13.196 20792 20792 I Notifier: KeyIn: Extras Key: android.remoteInputHistory Data:
Dipody answered 28/6, 2017 at 13:30 Comment(2)
Are you looking to update data in your app with the notification?Anthelion
The function of the app is to verify a login from a website. When a user logs into a specific website with UserId/Password a notificationn is sent to the app. When the app opens it starts scanning for a QR code that is shown after login on the website. The information in the notification must be equal to the information in the QR code. When that fits the website continues to its home page. Otherwise the login is refused.Dipody
D
7

Ok, this works for me for all app states I can think of:

using Android.App;
using Android.Content;
using Android.OS;
using MvvmCross.Droid.Platform;
using MvvmCross.Droid.Support.V4;

namespace Notifier.Android.Classes.Services
{
    /// <summary>
    /// This class receives all Firebase intents.
    /// </summary>
    [BroadcastReceiver(Enabled = true, Permission = "com.google.android.c2dm.permission.SEND")]
    [IntentFilter(new[] { "com.google.android.c2dm.intent.RECEIVE" }, Categories = new string[] { "com.yourdomain.yourapp" })]
    public class FirebaseBroadcastReceiver : MvxWakefulBroadcastReceiver
    {
        public override void OnReceive(Context context, Intent intent)
        {
            var setup = MvxAndroidSetupSingleton.EnsureSingletonAvailable(context);
            setup.EnsureInitialized();

            var service = new Intent(context, typeof(FirebaseBroadcastReceiver));

            PowerManager.WakeLock sWakeLock;
            var pm = PowerManager.FromContext(context);
            sWakeLock = pm.NewWakeLock(WakeLockFlags.Full, "FirebaseBroadcastReceiver");
            sWakeLock.Acquire();


            if (intent.Extras != null)
            {
                // Your code to handle the intent
            }

            sWakeLock.Release();

            StartWakefulService(context, service);
        }
    }
}
Dipody answered 4/7, 2017 at 6:16 Comment(0)
D
1

I've tried this:

    private void HandlePendingNotifications()
    {
        NotificationManager notificationManager = (NotificationManager)Application.Context.GetSystemService(Context.NotificationService);

        var notifications = notificationManager.GetActiveNotifications()
            .OrderByDescending(notif => notif.PostTime)
            .Where(notif => notif.PackageName == Application.Context.PackageName);

        var notification = notifications.FirstOrDefault();

        if (notification != null)
        {
            Log.Debug(TAG, "OnActivityResumed: Notification is active in Status Bar: {0}", notification.Notification.ToString());

            NotificationManagerCompat nm = NotificationManagerCompat.From(this);

            notification.Notification.Sound = null;
            notification.Notification.Vibrate = null;

            // nm.Cancel(notification.Id);
            nm.Notify(0, notification.Notification);
        }

        //Timer timer = new Timer((state) =>
        //{
        //    // Canceling all notifications
        //    notificationManager.CancelAll();
        //    timer = null;
        //}, null, 2000, 2000);
    }

But for some reason the notification is sent but never arrives at my app.

Dipody answered 29/6, 2017 at 8:58 Comment(2)
The newly sent notification is shown in the drawer but tapping on it does not activate my app.Dipody
After the Notify() there are 2 notifications in the drawer. The original one and the one I sent. The original does activate my app. The second one does not.Dipody
K
1

Extends FirebaseMessagingService and override the onMessageReceived and onDeletedMessages callbacks. To automatically open an application / activity when a notification is received, you need to use a data (something like {"data" : { "some_key" : "some_value"}}) attribute in your payload, which guarantees to always invoke the FirebaseMessagingService.onMessageReceived() method.

Please note that opening an activity / app on notification without user's interaction is really bad and should be avoided.

Kevyn answered 4/7, 2017 at 6:28 Comment(2)
@Paul Sinnema: My answer is for android, you adjust the answer with equivalent classes available in Xamarin.Kevyn
That is exactly how I implemented it. The problem was that when the app is in the background and the user taps the icon instead of the tray notification no Notification is received and we would have to fetch it ourselves somehow. The WakefulBroadcastReceiver as shown in my own answer solves that problem just fine.Dipody

© 2022 - 2024 — McMap. All rights reserved.