From df598a396197e08d03c140b65639c4edb1aa17a3 Mon Sep 17 00:00:00 2001 From: Paul Hitt Date: Thu, 10 Sep 2026 08:03:42 -0400 Subject: [PATCH] Say when Android is refusing to let a call ring The notification was built correctly all along: CATEGORY_CALL, PRIORITY_MAX, ongoing, autoCancel off, full-screen intent. Android was refusing it. USE_FULL_SCREEN_INTENT: default; rejectTime=+2m52s ago Since Android 14 that permission is auto-granted only to apps the system already treats as calling apps. Declared and not granted, an incoming call is demoted to an ordinary heads-up: about two seconds at the top, then gone, which reads as the call notification being broken. The system refuses silently, so nothing anywhere said so. Notification settings now checks canUseFullScreenIntent and offers the one screen that can grant it. The fuller fix is a self-managed ConnectionService, which makes this a calling app in the system's eyes and needs no permission prompt at all. That is a larger change than telling somebody the truth today. Co-Authored-By: Claude Opus 5 --- .../messenger/app/NotificationSection.kt | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/app/src/main/kotlin/io/flamenet/messenger/app/NotificationSection.kt b/app/src/main/kotlin/io/flamenet/messenger/app/NotificationSection.kt index 6253bf0..3d0c925 100644 --- a/app/src/main/kotlin/io/flamenet/messenger/app/NotificationSection.kt +++ b/app/src/main/kotlin/io/flamenet/messenger/app/NotificationSection.kt @@ -1,5 +1,10 @@ package io.flamenet.messenger.app +import android.provider.Settings +import android.os.Build +import android.net.Uri +import android.content.Intent +import android.app.NotificationManager import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -75,6 +80,49 @@ fun ColumnScope.NotificationSection() { Spacer(Modifier.height(Space.xs)) + // A ringing call needs a permission the manifest cannot grant itself. + // + // Since Android 14, USE_FULL_SCREEN_INTENT is auto-granted only to apps the + // system already treats as calling apps. Declared and not granted, an + // incoming call is demoted to an ordinary heads-up: it shows for about two + // seconds and collapses, which reads as the call notification being broken. + // The system refuses silently, so the only way anybody learns is here. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + val manager = context.getSystemService(NotificationManager::class.java) + if (manager?.canUseFullScreenIntent() == false) { + Spacer(Modifier.height(Space.sm)) + Text( + "Calls will not ring full screen", + style = MaterialTheme.typography.titleSmall, + modifier = Modifier.testTag("notify-fsi-title"), + ) + Text( + "Android is holding back the permission that lets an incoming call " + + "take over the screen, so a call shows as a banner for a couple of " + + "seconds and then goes. Grant it and calls ring properly.", + fontSize = 12.sp, + color = Palette.SecondaryText, + ) + Spacer(Modifier.height(Space.xs)) + KitSecondaryButton( + text = "Let calls ring", + onClick = { + runCatching { + context.startActivity( + Intent( + Settings.ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT, + Uri.fromParts("package", context.packageName, null), + ).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), + ) + } + }, + tag = "notify-fsi-grant", + ) + } + } + + Spacer(Modifier.height(Space.xs)) + // Says what turning it on costs, and does not pretend the default is merely // cautious. Text(