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 alarm ← AlarmManager.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:
Problem
Android 14 (API 34) moved
USE_FULL_SCREEN_INTENTbehind 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
fullScreenActionstill 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_INTdoesn'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.dumpsys packagestill reportsUSE_FULL_SCREEN_INTENT: granted=truewhile the app-op denies it.getNotificationSettings()currently reportsauthorizationStatusandandroid.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 nativeNotificationManagercall.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
fullScreenIntenttoAndroidNotificationSettings, beside the existingalarmfield, populated fromNotificationManager.canUseFullScreenIntent():Semantics mirror the
alarmprecedent exactly:ENABLED— granted at install, always honouredcanUseFullScreenIntent()trueENABLEDcanUseFullScreenIntent()falseDISABLEDENABLED— the same fallbackalarmalready usesThis is the same shape as
alarm←AlarmManager.canScheduleExactAlarms(): one boolean special-access check, oneAndroidNotificationSettingfield, 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 whengetNotificationSettings()exists to answer exactly that.Also adding an
openFullScreenIntentSettings()companion (mirroringopenAlarmPermissionSettings()). Deliberately left out to keep the change focused: launchingSettings.ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENTis 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 indumpsys notification, whiledumpsys packagestill showed the permission as granted.We've been running the one-hunk native change in production via
patch-packagesince then. I have a full PR ready — native + types + all fourAndroidNotificationSettingsconstruction sites + Jest and Robolectric coverage + a CHANGELOG entry — and will open it againstdevif 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, butCONTRIBUTING.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:
NotificationManager.canUseFullScreenIntent()— added in API 34