Giter Site home page Giter Site logo

Comments (8)

aritchie avatar aritchie commented on June 11, 2024 1

Can you share your android manifest

from shiny.

aritchie avatar aritchie commented on June 11, 2024 1

This one is going to require some fiddling. Android 14 (13 a bit) changes the way the alarm permission works.

from shiny.

aritchie avatar aritchie commented on June 11, 2024 1

It's still an issue because I haven't fixed it. I'll get to this when I can, but it isn't a 30 second fix.

Fixes at this point are set for 4.0 which will be .NET8+ only

from shiny.

aritchie avatar aritchie commented on June 11, 2024

Previous versions of local notifications used shiny jobs which caused delays. V3 uses the alarm which needs a permission request. Try the extension off INotificationManager called RequestRequiredAccess(Notification notification)

from shiny.

munkii avatar munkii commented on June 11, 2024

I tried calling RequestRequiredAccess with a notification that had ScheduleDate set and I got NullReferenceException. I copied the extension method so I could run it locally.

var request = AccessRequestFlags.Notification;
if (notification.RepeatInterval != null)
    request |= AccessRequestFlags.TimeSensitivity;

if (notification.ScheduleDate != null)
{
    var channelId = notification.Channel ?? Channel.Default.Identifier;
    var channel = notificationManager.GetChannel(channelId)!;

    if (channel!.Importance == ChannelImportance.High)
        request |= AccessRequestFlags.TimeSensitivity;
}

if (notification.Geofence != null)
    request |= AccessRequestFlags.LocationAware;

return await this.notificationManager
    .RequestAccess(request)
    .ConfigureAwait(false);

The call to RequestAccess sees the following callback to MainActivity.OnRequestPermissionsResult

  1. requestCode = 4
  2. permissions = ["android.permission.POST_NOTIFICATIONS" "android.permission.SCHEDULE_EXACT_ALARM"]
  3. grantResults = [0 -1]

In one of my debug scenarios the channel had not been created. That throws a NullReferenceException when trying to read channel!.Importance. I do however agree I should not be calling this without checking the channel has been created. I am just pointing out that the method should probably check too.

Once the code runs on a device with the Channel I get an AccessState of Restricted.If I remove the Channel then the AccessRequestFlags.TimeSensitivity flag is not set and I get AccessState of Available.

from shiny.

anchorit3 avatar anchorit3 commented on June 11, 2024

Hi, @munkii, @aritchie
I spend some time on investigation on Shiny 3.3.3 / dev branch of source code and MAUI but behavior should be really similar also for Xamarin and my conclusions are that there is couple things:

  1. in manifest probably should be max api 33 for SCHEDULE_EXACT_ALARM (now with Shiny.Templates is set to 32)
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" android:maxSdkVersion="33" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
  1. for api 34 we should check permissions on different way like android documentation suggest + request user to open special access settings in case when permission was not granted yet (on api 34 default is not granted, unfortunately I don't have good idea how to implement it in library)
 if (!this.Alarms.CanScheduleExactAlarms())
{
    var intent = new Android.Content.Intent(Android.Provider.Settings.ActionRequestScheduleExactAlarm);
    Application.Current.Context.StartActivity(intent);
}
  1. implementation of Send(Notification notification) in Platforms/Android/NotificationManager.cs code.
    After scheduling notification I checked pending notifications and was always 0 on android:
 var list = await notificationManager.GetPendingNotifications();
 var pendingNotificationsCount = list.Count(); // result is 0, but I scheduled notifications in future :(

so I checked implementation of GetPendingNotifications() which is:

public Task<IList<Notification>> GetPendingNotifications()
       => Task.FromResult((IList<Notification>)this.repository.GetList<AndroidNotification>().OfType<Notification>().ToList());

then if pending notifications are coming from repository I checked place where potentially AndroidNotification should be stored in repository which is Send(Notification notification):

public async Task Send(Notification notification)
{
    notification.AssertValid();
    var android = notification.TryToNative<AndroidNotification>();

    (...)

    if (notification.ScheduleDate == null && notification.Geofence == null)
    {
        var native = builder.Build();
        this.manager.NativeManager.Notify(notification.Id, native);
    }
    else
    {
        // ensure a channel is set
        notification.Channel = channel!.Identifier;
        this.repository.Set(notification);

        if (notification.ScheduleDate != null)
            this.manager.SetAlarm(notification);
    }
}

then we can see that into repository we store generic Notification type instead of AndroidNotification so I stored it as well. I added after this.repository.Set(notification); :

//re-asign android variable because we did manipulation from the moment when it was defined
android = notification.TryToNative<AndroidNotification>();
this.repository.Set(android);

and magic just happened - Scheduled Notifications started to works!

I'm not sure how it should be, maybe this.repository.Set(notification) should be removed or maybe not or maybe something else should be changed in other files (I dont know how the implementation of notifications looks like in other files and if generic type need to be stored or no or maybe AndroidNotificationProcessor is looking for wrong stuff in repository).

However I hope it can help you to understand better problem and solve it in plugin :)

from shiny.

aritchie avatar aritchie commented on June 11, 2024

@anchorit3 while I appreciate the effort. Most of the work is done in the 4.0 branch. The issue isn't really with the "making it happen", but with how much of a mess the permissions have gotten now due to this additional permission. I'm working on that part, but the plugin will do all of the permissions properly in the future.

from shiny.

munkii avatar munkii commented on June 11, 2024

This is still an issue for us even when using 3.3.3.

I can ask the Android AlarmService if i can schedule exact alarms via the canScheduleExactAlarmsMethod and that returns true.

AlarmManager alarmManager = (AlarmManager)GetSystemService(AlarmService);
Method canScheduleExactAlarmsMethod = alarmManager.Class.GetMethod("canScheduleExactAlarms");
bool canScheduleExactAlarms = (bool)canScheduleExactAlarmsMethod.Invoke(alarmManager);

However when it comes time to send the notification and I call Shiny I get AccessState.Restricted

var result = await this.remindersService.CheckNotificationsPermission(AccessRequestFlags.Notification | AccessRequestFlags.TimeSensitivity);

if (result != Shiny.AccessState.Available)
{
    this.notificationPermissionRequestedAndDenied = true;
}

public async Task<Shiny.AccessState> CheckNotificationsPermission(AccessRequestFlags accessRequestFlags = AccessRequestFlags.Notification)
{
    return await this.notificationManager.RequestAccess(accessRequestFlags);
}

I looked at the implmentation of NotifcationManager RequestAccess and had a look at starting the Android.Provider.Settings.ActionRequestScheduleExactAlarm activity myself. Whilst it does start it gives me as the user now way to add us to the allowed set of apps.

Are these exact notifications best left alone for now. Should wait for 4.0? Will 4.0 be MAUI only?

from shiny.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.