feat(player): make native Android video the default
The two defects that were holding the flip back are fixed and verified on a
device, which is the standard this default has been held to since DR-161 shipped
a verified sub-path over an unverified one:
- returning from background audio restarts the renderer that is actually on
screen, instead of only ever reloading the <video> element (DR-196)
- the letterbox bars are painted, instead of retaining whatever was last in
the framebuffer (DR-194)
Evidence: handoff to audio-only at 69:54 returning to video playing at 70:18,
and clean bars across playback, the control bar and a rotation round-trip.
An explicit stored choice still wins in both directions, so anyone who turned the
flag off keeps it off — hence the null check on the stored value rather than a
bare === "true", which would silently re-enable it for people who opted out.
The Settings copy no longer tells users to leave it off; it now describes the
toggle as the fallback to the built-in web player.
The flag keeps its "experimental" name because it remains a suppressor of Rust's
backend choice, never a promoter: turning it on cannot produce a native backend
where Rust says HTML5.
This commit is contained in:
@@ -50,30 +50,37 @@ const NATIVE_VIDEO_ATTR = "data-native-video";
|
||||
*
|
||||
* The picture is genuinely fixed and device-verified — `WebView transparent =
|
||||
* true` and `Marking media ready` now appear in logcat with video on screen,
|
||||
* the pair DR-172 went looking for and could not find. **The default is still
|
||||
* off**, because turning it on surfaced a different gap: the background-audio
|
||||
* handoff (UR-040) can only *return* through the HTML5 element.
|
||||
* `applyPendingForegroundSeek` bails on `!videoElement`, the HLS re-init effect
|
||||
* bails on `!useHtml5Element`, and `handleCanPlay` — the event that owns the
|
||||
* post-handoff position and play state — is an element event that never fires
|
||||
* natively. So coming back from background audio leaves playback dead.
|
||||
* the pair DR-172 went looking for and could not find. The default nonetheless
|
||||
* stayed **off** for a further release, because turning it on surfaced a
|
||||
* different gap: the background-audio handoff (UR-040) could only *return*
|
||||
* through the HTML5 element, so coming back from background audio left playback
|
||||
* dead. That was the same shape of mistake as DR-161 — a verified sub-path
|
||||
* shipped as a default over an unverified one — so the flip waited (DR-190).
|
||||
*
|
||||
* That is the same shape of mistake as DR-161: a verified sub-path shipped as a
|
||||
* default over an unverified one. The evidence standard this branch set for the
|
||||
* picture applies to the handoff too, so the flip waits for it (DR-190).
|
||||
* - **on** now. The two defects that were holding it back are fixed and
|
||||
* verified on a device: the handoff return restarts the renderer that is
|
||||
* actually on screen rather than only ever reloading the `<video>` element
|
||||
* (DR-196), and the letterbox bars are painted instead of retaining whatever
|
||||
* was last in the framebuffer (DR-194). The evidence standard this default
|
||||
* has been held to since DR-161 is met for both: audio handoff at 69:54
|
||||
* returning to video playing at 70:18, and clean bars across playback, the
|
||||
* control bar and a rotation round-trip.
|
||||
*
|
||||
* An explicit stored choice still wins in both directions, so anyone who turned
|
||||
* it on keeps it on.
|
||||
* it off keeps it off — hence the `null` check rather than a bare `=== "true"`,
|
||||
* which would silently re-enable it for people who opted out.
|
||||
*
|
||||
* TRACES: UR-003, UR-004 | DR-188
|
||||
*/
|
||||
function load(): boolean {
|
||||
if (typeof localStorage === "undefined") return false;
|
||||
if (typeof localStorage === "undefined") return true;
|
||||
try {
|
||||
return localStorage.getItem(STORAGE_KEY) === "true";
|
||||
const stored = localStorage.getItem(STORAGE_KEY);
|
||||
// Never chosen → on. Chosen → honour it, in both directions.
|
||||
return stored === null ? true : stored === "true";
|
||||
} catch {
|
||||
// Private-mode / disabled storage — default to the path whose handoff works.
|
||||
return false;
|
||||
// Private-mode / disabled storage — same default as a fresh install.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,9 +108,11 @@ function createExperimentalNativeVideoStore() {
|
||||
}
|
||||
|
||||
/**
|
||||
* User opt-in for the native Android video path. **Defaults to off** — see
|
||||
* `load()`. The name says "experimental" because the flag remains a suppressor
|
||||
* of Rust's backend choice, not a promoter of it.
|
||||
* User preference for the native Android video path. **Defaults to on** — see
|
||||
* `load()`. The name still says "experimental" because the flag remains a
|
||||
* suppressor of Rust's backend choice, not a promoter of it: turning it off
|
||||
* forces the webview element, turning it on never produces a native backend
|
||||
* where Rust says HTML5.
|
||||
*/
|
||||
export const experimentalNativeVideo = createExperimentalNativeVideoStore();
|
||||
|
||||
|
||||
@@ -746,9 +746,8 @@
|
||||
Decode video with the device's hardware decoder instead of the
|
||||
built-in web player, for better performance and battery life,
|
||||
and so picture-in-picture shows the video rather than the app.
|
||||
The picture works, but background audio does not come back from
|
||||
the lockscreen on this path yet — leave it off unless you are
|
||||
helping test it.
|
||||
On by default. Turn it off to fall back to the built-in web
|
||||
player if a video misbehaves.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user