You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+8Lines changed: 8 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,13 @@
1
1
# Changelog
2
2
3
+
## 0.1.9 - 2026-06-02
4
+
5
+
- Android: eliminate the `IllegalArgumentException: Invalid window token (never added or removed already)` crash from `WindowlessWindowManager.relayout` on Android 12 (API 31) — same crash class as v0.1.6 fixed for Android 11 (API 30), but re-surfacing on API 31 because v0.1.6's `INTERNAL_SYSTEM_WINDOW` pre-check was scoped `SDK_INT == 30` only. AOSP enforces the same `INTERNAL_SYSTEM_WINDOW` permission gate for SCVH's `addToDisplay` path on Android 12 (API 31) and Android 12L (API 32), so `host.setView()` throws `SecurityException` on those releases too — and `ViewRootImpl.setView` queues a `TraversalRunnable` via `requestLayout()` BEFORE the throw, so by the time the catch block runs there's a runnable in the SCVH's Choreographer queue that fires at the next vsync (TRAVERSAL phase) against a token that was never registered with the WWM. Reproduced 1:1 on the Pixel 6 / Android 12 (API 31) emulator with the user-reported stack trace. Two-layer fix:
6
+
- Extended the `INTERNAL_SYSTEM_WINDOW` pre-check to `SDK_INT in 30..32` (Android 11, 12, 12L). On those releases SCVH is skipped entirely, no `setView` attempt, no queued runnable, no crash. AOSP relaxed the requirement starting in API 33 (Android 13), so SCVH and the SurfaceFlinger-direct alpha toggle keep working unmodified on every Android 13+ device — confirmed on Pixel_9 / Android 16 (API 37) where the maestro regression suite still passes 9/9.
7
+
- New `failScvhAttach(host, reason)` helper invoked from all five SCVH attach recovery branches in `tryAttachCoverViaScvh` (setView, null surfacePackage, initial setAlpha, setChildSurfacePackage, addView). It now SYNCHRONOUSLY calls `unscheduleScvhTraversals(host)` to cancel any TraversalRunnable already queued by the failed `setView` BEFORE returning to the caller — main-thread synchronous, drains the queue before the next vsync fires. The previous `deferredReleaseScvh` (Choreographer animation phase → `mainHandler.post`) was structurally too late: the queued runnable runs in the TRAVERSAL phase, strictly before any Handler message scheduled during the same vsync. This synchronous cancel is the structural defence that protects every API where SCVH might unexpectedly fail (not just the API 30..32 range covered by the pre-check) — observed value: cold-boot Pixel emulator quirks on Android 14 where SCVH intermittently fails, and any future Android version that might re-introduce a similar restriction.
8
+
9
+
`minSdkVersion=23`, public API, and iOS behavior unchanged.
10
+
3
11
## 0.1.8 - 2026-06-01
4
12
5
13
- Android: complete the Samsung One UI Recents-cover fix from v0.1.7. The instance-based `exclude2 = coverContent` exclusion in `topmostHostViewFor` only filtered the *current* cover content; on Samsung One UI (Galaxy A05 / SM-A057F, Android 14, One UI 6/7), rapid `setColor` / `setImage` / `enable` JS calls during `LockCover` mount trigger 2-3 sequential attach cycles (`ensurePreMounted` → `refreshCoverContentIfMounted`), and the previous attach's `FreezableFrameLayout` lingers briefly in `WindowManagerGlobal.mViews` after teardown. The walk picked the stale instance as "topmost", `addCover` tried to attach as a sub-window of an invalidated token, and `WindowManager.addView` threw `BadTokenException: Unable to add window — token … is not valid; is your activity running?` on the third attach in the burst. The result: cover never appeared in the Recents thumbnail. Fix: add a class-based filter in `CoverWindowAttachment.topmostHostViewFor` that rejects any `FreezableFrameLayout` regardless of instance, so stale entries from previous attach cycles can't be mistaken for the topmost host. `FreezableFrameLayout` was made `internal` (package-visible) to keep the type reachable from `CoverWindowAttachment`. The instance-match `exclude2 = coverContent` is preserved as a fast-path. On every non-Samsung device the SCVH-hosted content never appears in `WindowManagerGlobal.mViews` to begin with, so the new filter is a no-op. Verified end-to-end on Samsung Galaxy A05 (cover paints in Recents with `#5F8AFA` background and splash icon, no `BadTokenException`), Pixel_9 emulator (9/9 maestro flows green, same baseline as v0.1.6), and Favvy_Android_30 / API 30 (5× home/app-switcher + 10× rapid toggle stress, zero crashes, API 30 `INTERNAL_SYSTEM_WINDOW` pre-check still fires).
Log.w(TAG, "attachCover scvh: API 30 + INTERNAL_SYSTEM_WINDOW not granted; SCVH would throw at setView, disabling SCVH for this session")
919
+
Log.w(TAG, "attachCover scvh: API ${Build.VERSION.SDK_INT} + INTERNAL_SYSTEM_WINDOW not granted; SCVH would throw at setView, disabling SCVH for this session")
920
920
scvhDisabled =true
921
921
returnfalse
922
922
}
@@ -939,43 +939,13 @@ class HybridCover : HybridCoverSpec() {
939
939
try {
940
940
host.setView(content, width, height)
941
941
} catch (e:Throwable) {
942
-
Log.w(TAG, "attachCover scvh: setView failed (${e.javaClass.simpleName}): ${e.message}; disabling SCVH for this session")
943
-
scvhDisabled =true
944
-
// Defer the release: a SCVH whose `setView` (or follow-up step)
945
-
// partially failed often still has a window registered in its
946
-
// internal `WindowlessWindowManager` plus a TraversalRunnable
947
-
// queued on its ViewRootImpl. Releasing inline removes the WWM
948
-
// token before that runnable fires next vsync, which throws
949
-
// `IllegalArgumentException: Invalid window token` from
950
-
// `Looper.loop` — the exact crash reported on cold-booted
951
-
// emulators where `setView` hits `SecurityException: Requires
0 commit comments