diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 35dceab..c03445c 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -43,6 +43,14 @@ android { compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 + // ScheduleEval uses java.time (Instant/LocalDate/ZoneId), which is API 26 — but minSdk is + // 24. Without desugaring, per-item dayparting/expiry threw NoClassDefFoundError on Android + // 7.0/7.1, which are still common on cheap signage sticks and older TV boxes. Because that + // is an Error and not an Exception, the evaluator's deliberate fail-open guard did not + // catch it: the playlist update aborted before content downloaded, and the cold-start path + // then cleared the playlist cache — so the screen sat on "waiting for content" and a reboot + // did not help. + isCoreLibraryDesugaringEnabled = true } kotlinOptions { @@ -63,6 +71,7 @@ android { } dependencies { + coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4") // AndroidX implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.appcompat:appcompat:1.6.1") diff --git a/android/app/src/main/java/com/remotedisplay/player/player/ScheduleEval.kt b/android/app/src/main/java/com/remotedisplay/player/player/ScheduleEval.kt index e9cdc4d..56261ac 100644 --- a/android/app/src/main/java/com/remotedisplay/player/player/ScheduleEval.kt +++ b/android/app/src/main/java/com/remotedisplay/player/player/ScheduleEval.kt @@ -43,7 +43,12 @@ object ScheduleEval { val nowMin = zdt.hour * 60 + zdt.minute val date = zdt.toLocalDate() blocks.any { blockMatches(it, dow, nowMin, date) } - } catch (e: Exception) { + } catch (e: Throwable) { + // Throwable, not Exception. A missing java.time on an old API level surfaces as + // NoClassDefFoundError — an Error — which sailed straight through a catch(Exception) + // and turned this "fail open, a blank screen is worse than an over-running promo" + // contract into its exact opposite: nothing played at all. Desugaring (see + // build.gradle.kts) is the real fix; this makes the guard mean what it says. true // fail open } }