From 5bcaca7c519d5e378a95b7e2e6504e3c68451c94 Mon Sep 17 00:00:00 2001 From: ScreenTinker Date: Fri, 12 Jun 2026 22:21:50 -0500 Subject: [PATCH] fix(player): OTA install silently fails on Android 14+ (explicit PendingIntent) UpdateChecker.tryPackageInstaller built the INSTALL_COMPLETE status PendingIntent with FLAG_MUTABLE and an implicit intent. On Android 14+ (target SDK 34) that combination is disallowed - getBroadcast() throws, the inner catch swallows it, and the PackageInstaller session is never committed. Result: every OTA silently fails to install on a 14+ device (download succeeds, version never changes). Make the intent explicit via setPackage(), keeping FLAG_MUTABLE so PackageInstaller can still write EXTRA_STATUS back. Emulator-proven on Android 16 (API 36): "Package installer session committed" and the update applies. Distinct from the relaunch bug - this is install-on-14+. Part of #96. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../com/remotedisplay/player/service/UpdateChecker.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/android/app/src/main/java/com/remotedisplay/player/service/UpdateChecker.kt b/android/app/src/main/java/com/remotedisplay/player/service/UpdateChecker.kt index 46694f4..c9e29d3 100644 --- a/android/app/src/main/java/com/remotedisplay/player/service/UpdateChecker.kt +++ b/android/app/src/main/java/com/remotedisplay/player/service/UpdateChecker.kt @@ -221,9 +221,15 @@ class UpdateChecker(private val context: Context) { } } + // #96 (install bug): the status PendingIntent must stay FLAG_MUTABLE so + // PackageInstaller can write EXTRA_STATUS back into it - but on Android 14+ + // (target SDK 34+) a FLAG_MUTABLE PendingIntent with an *implicit* intent is + // disallowed and getBroadcast() throws, silently aborting every OTA on 14+. + // Make the intent explicit (setPackage) so mutable is allowed; it also keeps + // the broadcast to our own RECEIVER_NOT_EXPORTED receiver. val pendingIntent = android.app.PendingIntent.getBroadcast( context, sessionId, - Intent("com.remotedisplay.player.INSTALL_COMPLETE"), + Intent("com.remotedisplay.player.INSTALL_COMPLETE").setPackage(context.packageName), android.app.PendingIntent.FLAG_MUTABLE ) session.commit(pendingIntent.intentSender)