Skip to content

fix(native): stop reporting a granted notification permission for a muted Android app - #655

Open
pal-tamas wants to merge 1 commit into
mainfrom
worktree-android-notifications-enabled
Open

fix(native): stop reporting a granted notification permission for a muted Android app#655
pal-tamas wants to merge 1 commit into
mainfrom
worktree-android-notifications-enabled

Conversation

@pal-tamas

Copy link
Copy Markdown
Owner

Summary

INotifications asked only whether the app held POST_NOTIFICATIONS, and below API 33 — where no
such permission exists — short-circuited to Granted outright:

private NotificationPermission CurrentPermission() =>
    !OperatingSystem.IsAndroidVersionAtLeast(33)
    || activity.CheckSelfPermission(Android.Manifest.Permission.PostNotifications) == Permission.Granted
        ? NotificationPermission.Granted
        : NotificationPermission.Default;

But the per-app notification toggle in Settings is independent of the permission, exists on every
supported version, and turning it off makes NotificationManager.Notify a silent no-op. So a user who
muted the app got Granted from PermissionAsync(), ShowAsync returned without throwing, and nothing
ever appeared — with nothing in the API saying otherwise.

AreNotificationsEnabled is the one call that sees that toggle. It exists from API 24 — the android
head's own SupportedOSPlatformVersion — so it covers the whole supported range with no version guard, and
it's reached through the existing AndroidNotifications.Manager helper.

Decisions worth flagging

  • A muted app reports Denied, not Default. The way back is the Settings screen, not a prompt —
    which is exactly what Denied means in the web contract this backend mirrors ("blocked until the user
    changes the setting"). Default would tell a caller a request is still worth making.
  • RequestPermissionAsync returns it too, rather than claiming a grant no prompt could produce. It was
    answering Granted unconditionally below API 33, before it ever consulted the current state; the muted
    check now runs first.
  • Behaviour change: ShowAsync on a muted app now throws InvalidOperationException, like any other
    ungranted permission, where it previously returned and quietly showed nothing. That is this backend's
    documented contract ("a denied permission throws"), and the silent version is what made the bug
    invisible in the first place.

Testing

  • dotnet format clean, CI=true dotnet build Rask.slnx -warnaserror -m:1 clean, full unit suite green,
    browser E2E 57/57 — run twice, since a single clean run can hide the two-build-mode obj/ hazard
    fix(playground): wait for the editor, and stop the E2E gate breaking its own publish #652 just fixed.
  • Android compiles only in CI's native jobs (no android workload locally), so those are the gate
    here — as for every Android-side change. There is no unit-test seam: Platforms/Android/** is excluded
    from the net10.0 TFM that Rask.Native.Tests builds against.
  • Not verified on a device. The behaviour is inferred from the code and Android's documented semantics,
    the same basis on which the bug was filed.

Related

The identical gap in the IPermissions native backend was closed in #644, whose
NativePermissionQuery.NotificationState comment points at this file — so once both land, the two APIs
agree about the same app instead of contradicting each other.

Closes #649.

…uted Android app

INotifications asked only whether the app HELD POST_NOTIFICATIONS, and below API 33 --
where no such permission exists -- short-circuited to Granted outright. But the per-app
notification toggle in Settings is independent of the permission, has existed since API
19, and turning it off makes NotificationManager.Notify a SILENT no-op.

So a user who muted the app got Granted from PermissionAsync(), ShowAsync returned
without throwing, and nothing ever appeared. Nothing in the API said otherwise.

AreNotificationsEnabled is the one call that sees that toggle, and it exists from API 24
-- the android head's own SupportedOSPlatformVersion -- so it covers the whole supported
range without a version guard. It is now checked first.

A muted app reports Denied rather than Default: the way back is the Settings screen, not
a prompt, which is exactly what Denied means in the web contract this backend mirrors
("blocked until the user changes the setting"). RequestPermissionAsync returns it too,
instead of claiming a grant no prompt could produce -- it was answering Granted
unconditionally below API 33, before it ever consulted the current state.

Behaviour change: ShowAsync on a muted app now throws InvalidOperationException, like
any other ungranted permission, where it previously returned and quietly showed nothing.
That is the documented contract of this backend ("a denied permission throws"), and the
silent version is what made the bug invisible.

The equivalent gap in the IPermissions native backend was closed in #644; the comment
there points here, so the two now agree about the same app.

Android compiles only in CI's native jobs (no android workload locally), so those are
the gate for this one.

Closes #649.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

INotifications reports Granted on Android when the user has notifications switched off

1 participant