Skip to content

[Feature] Expose the Android 14+ full-screen-intent grant on getNotificationSettings() #64

Description

@KAMRONBEK

Problem

Android 14 (API 34) moved USE_FULL_SCREEN_INTENT behind a user-revocable special app access. For apps outside the calling/alarm categories the Play Store revokes it at install time; apps installed before the device upgraded to 14 keep it; and the user can flip it at any point under Settings → Apps → Special app access → Full screen notifications.

When it is not granted, a notification posted with fullScreenAction still succeeds. The promise resolves, the notification appears in the shade, nothing throws — the full-screen UI is silently dropped. From JS there is no way to tell the two outcomes apart:

  • Build.VERSION.SDK_INT doesn't answer it — the state is per-app and per-user, not per-OS-version. Install channel, install date, upgrade path and later user action all move it.
  • The manifest permission isn't a signal either: dumpsys package still reports USE_FULL_SCREEN_INTENT: granted=true while the app-op denies it.
  • getNotificationSettings() currently reports authorizationStatus and android.alarm, both of which stay green.

The only reliable signal is NotificationManager.canUseFullScreenIntent() (API 34), which has no binding in this library — and cannot be added from JS, because it requires a native NotificationManager call.

The practical effect for a calling app: an incoming call rings, but never takes over the lock screen, and the app cannot explain why or offer the one-tap fix. It can only guess.

Proposed solution

Add fullScreenIntent to AndroidNotificationSettings, beside the existing alarm field, populated from NotificationManager.canUseFullScreenIntent():

const settings = await notifee.getNotificationSettings();

if (settings.android.fullScreenIntent === AndroidNotificationSetting.DISABLED) {
  // Still ring — but tell the user why the lock screen stayed dark, and
  // offer a hand-off to Settings.ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT.
}

Semantics mirror the alarm precedent exactly:

Condition Value
API < 34 ENABLED — granted at install, always honoured
API ≥ 34, canUseFullScreenIntent() true ENABLED
API ≥ 34, canUseFullScreenIntent() false DISABLED
iOS / web ENABLED — the same fallback alarm already uses

This is the same shape as alarmAlarmManager.canScheduleExactAlarms(): one boolean special-access check, one AndroidNotificationSetting field, no new method on the public API surface.

Platform

Android

Alternatives considered

A separate notifee.canUseFullScreenIntent() method. More API surface for the same fact, and it splits "what am I allowed to do" across two call sites when getNotificationSettings() exists to answer exactly that.

Also adding an openFullScreenIntentSettings() companion (mirroring openAlarmPermissionSettings()). Deliberately left out to keep the change focused: launching Settings.ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT is already doable from JS with any intent launcher, so it isn't a gap. Detection is the part JS cannot do. Happy to add it as a follow-up if you'd prefer the pair to be symmetric.

Patching locally. What we do today, via patch-package. It works, but every consumer shipping a calling or alarm app needs the same patch, and it rots silently on each upgrade.

Additional context

We hit this shipping an Android calling app on notify-kit: the ring notification posted fine on Android 14 but never took the lock screen, with no error anywhere to explain it. The tell turned out to be a missing fullscreenIntent= line in dumpsys notification, while dumpsys package still showed the permission as granted.

We've been running the one-hunk native change in production via patch-package since then. I have a full PR ready — native + types + all four AndroidNotificationSettings construction sites + Jest and Robolectric coverage + a CHANGELOG entry — and will open it against dev if you're happy with the shape.

One scope note: this necessarily touches packages/react-native/android/src/main/java/app/notifee/core/Notifee.java. The issue template still says the native core isn't modified in this fork, but CONTRIBUTING.md (post-archival) says core changes are now fully allowed where the bridge isn't the right place — and here it can't be, since the value only exists behind a native call. Flagging it in case that template line is still the intent.

References:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions