Skip to content

Commit ff28990

Browse files
nqmgamingclaude
andcommitted
fix(install): check the prompt can post before committing to it
Once the headless path finishes the activity there is no window left, so a prompt that fails to post would leave the install with nothing on screen. The check now happens before the parse is stashed, and a failure falls back to the dialog with the parse restored intact. No change to how the prompt is posted. An earlier attempt deferred the post until after the activity finished, on the theory that a heads-up is suppressed for the app currently in front. That theory was wrong — see the commit message below for what it actually is — and the delay only added a window in which the process could die with the prompt never posted. The reason the prompt does not pop up like a message on this device is not in this code at all: Samsung replaces heads-up cards with the edge glow whenever Edge lighting is on. A notification posted by the shell itself gets the same treatment, logged as "no Heads up : edgelighting enabled app", and turning edge_lighting off makes the refusal disappear. InstallerX Revived uses the same IMPORTANCE_HIGH channel with no extra API, so it behaves identically here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 0752dc2 commit ff28990

2 files changed

Lines changed: 20 additions & 13 deletions

File tree

app/src/main/java/app/pwhs/universalinstaller/presentation/install/DialogInstallActivity.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -291,12 +291,14 @@ class DialogInstallActivity : ComponentActivity() {
291291
return@LaunchedEffect
292292
}
293293

294-
val entry = viewModel.stashPendingInstall()
294+
// Checked before stashing: a prompt that cannot be posted would strand the install
295+
// with nothing on screen, and the dialog is the only fallback left.
296+
val entry = if (promptNotifier.canPost()) viewModel.stashPendingInstall() else null
295297
if (entry == null || !promptNotifier.prompt(entry)) {
296-
// Notifications are off, or there was nothing to stash. Either way the user must
297-
// still be able to answer, so show the dialog rather than dropping the install.
298-
entry?.let { viewModel.restorePendingInstall(it) }
299-
entry?.let { PendingInstallStore.consume(it.id) }
298+
entry?.let {
299+
viewModel.restorePendingInstall(it)
300+
PendingInstallStore.consume(it.id)
301+
}
300302
skipInitialParse = entry != null
301303
fallbackToDialog()
302304
return@LaunchedEffect

app/src/main/java/app/pwhs/universalinstaller/presentation/install/InstallPromptNotifier.kt

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,18 @@ class InstallPromptNotifier(
9494
}
9595
}
9696

97+
/**
98+
* Whether a prompt can be posted at all. Checked before the caller commits to the headless
99+
* path, since after that there is no window left to fall back to.
100+
*/
101+
fun canPost(): Boolean {
102+
if (!nm.areNotificationsEnabled()) return false
103+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return true
104+
return ContextCompat.checkSelfPermission(
105+
context, Manifest.permission.POST_NOTIFICATIONS,
106+
) == PackageManager.PERMISSION_GRANTED
107+
}
108+
97109
fun cancel(pendingId: String) = nm.cancel(notificationId(pendingId))
98110

99111
/** Stable id per pending install so two queued prompts don't collapse into one. */
@@ -138,14 +150,6 @@ class InstallPromptNotifier(
138150
)
139151
}
140152

141-
private fun canPost(): Boolean {
142-
if (!nm.areNotificationsEnabled()) return false
143-
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return true
144-
return ContextCompat.checkSelfPermission(
145-
context, Manifest.permission.POST_NOTIFICATIONS,
146-
) == PackageManager.PERMISSION_GRANTED
147-
}
148-
149153
private fun ensureChannel() {
150154
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
151155
val channel = NotificationChannel(
@@ -167,5 +171,6 @@ class InstallPromptNotifier(
167171
*/
168172
const val CHANNEL_ID = "install_prompt_v2"
169173
const val NOTIF_ID_BASE = 43000
174+
170175
}
171176
}

0 commit comments

Comments
 (0)