Search code examples
c#androidxamarinmobilesamsung-mobile

Xamarin gets Permission Denial when setting badge number on Galaxy 8 & 9


I have an app that shows the notification number in the little red dot on the app icon. This works fine on all models except the Samsung Galaxy S9. I have tried many solutions but always get the error

Permission Denial: writing com.sec.android.provider.badge.BadgeProvider uri content://com.sec.badge/apps from pid=32464, uid=10233 requires com.sec.android.provider.badge.permission.WRITE, or grantUriPermission()

The project is a Xamarin Android project in Visual Studio 2017, below is the code that works with all models except S9

In the manifest

<uses-permission android:name="com.sec.android.provider.badge.permission.READ" />
<uses-permission android:name="com.sec.android.provider.badge.permission.WRITE" />

The C#

        try
        {
            var context = Android.App.Application.Context;

            // This is the content uri for the BadgeProvider
            var uriPath = "content://com.sec.badge/apps"; //"com.sec.android.app.launcher"; 
            Android.Net.Uri uri = Android.Net.Uri.Parse(uriPath); //new Uri("content://com.sec.badge/apps");

            ICursor cursor = context.ContentResolver.Query(uri, new string[] { "_id" }, "package=?", new string[] { context.PackageName }, null);

            if (cursor == null || !cursor.MoveToFirst())
            {
                ContentValues cv = new ContentValues();
                cv.Put("package", context.PackageName);
                cv.Put("class", context.PackageManager.GetLaunchIntentForPackage(context.PackageName).Component.ClassName);
                cv.Put("badgecount", count);
                context.ContentResolver.Insert(uri, cv); //Errors here
            }
            else
            {
                int idColumnIndex = cursor.GetColumnIndex("_id");

                ContentValues cv = new ContentValues();
                cv.Put("badgecount", count);
                context.ContentResolver.Update(uri, cv, "_id=?", new string[] { cursor.GetInt(idColumnIndex).ToString() });
            }

        }
        catch (System.Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message); 
        }

Like I said, this all works fine with earlier models but errors with the newer models. Is there something that needs to be added to permissions or am I missing something else?


Solution

  • I have a fix to my problem. You now need to use a NotificationChannel with your NotificationManager. I have created a small test app with one button. In the button click, I call the code below. I haven't moved this to my live apps yet but it is working good in this test app.

    First, add a const to use for the id parameter for the NotificationChannel

    public const string CLICKS_CHANNEL = "com.yourcompany.SamsungBadgeTest.clicks";
    

    Now:

    1. Move the declaration of the NotificationManager to be above the NotificationBuilder
    2. Create the NotificationChannel
    3. Call the manager's CreateNotificationChannel passing the channel as a parameter
    4. Make your Notification.Builder
    5. Build()

          try
          {
              //This is declared at the class level and initially set to 0
              //Incrementing with each button click
              clickCount++;
      
              int defaults = 0;
              defaults |= (int)NotificationDefaults.Sound;
              defaults |= (int)NotificationDefaults.Lights;
              defaults |= (int)NotificationDefaults.Vibrate;
      
              var notificationManager = (NotificationManager)GetSystemService(Context.NotificationService);
      
              var chan = new NotificationChannel(CLICKS_CHANNEL, "Button Click", NotificationImportance.Default)
              {
                  LockscreenVisibility = NotificationVisibility.Private
              };
      
              notificationManager.CreateNotificationChannel(chan);
      
              var notificationBuilder = new NotificationCompat.Builder(this, CLICKS_CHANNEL)
                  .SetAutoCancel(true)
                  .SetContentText("You've received new messages.")
                  .SetContentTitle("A New Message")
                  .SetNumber(clickCount)
                  //You need to add a icon to your project and get it here
                  .SetSmallIcon(Resource.Drawable.ic_stat_button_click)
                  .SetBadgeIconType(NotificationCompat.BadgeIconSmall)
                  .SetDefaults(defaults); //.Build();
      
              notificationManager.Notify(0, notificationBuilder.Build());
          }
          catch(System.Exception ex)
          {
              System.Diagnostics.Debug.WriteLine(ex.Message);
          }
      

    Don't forget to add this to your Manifest

    <uses-permission android:name="com.sec.android.provider.badge.permission.READ" />
    <uses-permission android:name="com.sec.android.provider.badge.permission.WRITE" />