Compare commits

...

623 commits

Author SHA1 Message Date
Silent1566
9ade2ca0e3 C67: commit Android 6 PiP compat contract test
Verification: .\gradlew.bat :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.utils.Android6PictureInPictureCompatTest -> BUILD SUCCESSFUL in 3m 10s

Scope: only app/src/testMobile/java/com/fongmi/android/tv/utils/Android6PictureInPictureCompatTest.java. Branch android6 created from dev2 5a5d07822f; dev2 pointer unchanged. task_guard.sh not run: no usable bash in this Windows environment (WSL HCS unavailable).
2026-10-14 17:08:33 +08:00
Silent1566
5a5d07822f C70: use API 23 compatible leanback history progress
Verification: :app:compileLeanbackArmeabi_v7aDebugJavaWithJavac BUILD SUCCESSFUL; :app:assembleLeanbackArmeabi_v7aDebug BUILD SUCCESSFUL; Android 6 API 23 cover-install Success; HomeActivityCurrent PID 12363; no AndroidRuntime/CustomActivityOnCrash errors; leanback UI visible with history progress

Task-Guard: C70-leanback-api23-history-progress
2026-10-14 16:07:27 +08:00
Silent1566
0cb3ab46e0 C69: allow leanback release API 23 manifest merge
Verification: Leanback release manifest verification passed: :app:processLeanbackArmeabi_v7aReleaseMainManifest succeeded and merged manifest retains minSdkVersion 23.

Task-Guard: C69-leanback-chaquo-release-minsdk
2026-10-14 14:41:34 +08:00
Silent1566
6bcde995a0 C68: allow leanback debug API 23 manifest merge
Verification: Failing target fixed and verified: :app:processLeanbackArmeabi_v7aDebugMainManifest passed; :app:assembleLeanbackArmeabi_v7aDebug passed; APK reports sdkVersion 23 and apksigner verification passed.

Task-Guard: C68-leanback-chaquo-minsdk
2026-10-14 14:36:16 +08:00
Silent1566
d7ff425781 C67: bound HLS playlist reads for Android 6 playback
Verification: Android 6.0.1 playback test: IJK via MpvHlsProxy played over 2 minutes, PID 10226 stable, Java Heap ~179 MB, no fatal OOM; focused unit tests and release APK verification passed.

Task-Guard: C67-player-api23-playback-oom
2026-10-14 14:00:14 +08:00
Silent1566
4bd4da1d69 C67: document Android 6 playback OOM diagnosis
Verification: Reviewed Android 6 crash/thread logs and memory samples; documented the approved bounded HLS playlist fix

Task-Guard: C67-player-api23-playback-oom
2026-10-14 12:04:48 +08:00
Silent1566
1e5578bef5 C67: fix Android 6 history progress API crash
Verification: Focused Android6HistoryProgressCompatTest passed; mobile armeabi-v7a release build passed; APK AA29E4503C721D327340732FCE02C37D2A01DF45B409145263BB4DF234C01CA9 installed with -r -d on MuMu Android 6; HistoryActivity opens without crash and playback back path has no stopForeground NoSuchMethodError

Task-Guard: C67-player-api23-history-progress
2026-10-14 11:13:52 +08:00
Silent1566
69e2ee4639 C67: fix Android 6 stopForeground API crash
Verification: Focused Android6StopForegroundCompatTest passed; mobile armeabi-v7a release build passed; APK 123990D19FE338072BAC17070F54B271B156EC42935CCC0A9A1C5C09F2589CCF installed with -r -d on MuMu Android 6

Task-Guard: C67-player-api23-stop-foreground
2026-10-14 10:47:06 +08:00
Silent1566
9045c40c4f C67: fix Android 6 playback PiP API crash
Verification: focused Android6PictureInPictureCompatTest passed; leanback compile passed; Android 6 overlay-install playback/tap scenario passed with empty related crash buffer

Task-Guard: C67-player-api23-pip
2026-10-14 10:12:04 +08:00
Silent1566
db3764dd0b C67: support Android 6 with Python disabled
Verification: Final focused JVM tests passed; final APK C2EAE5FD406C10A107E179605921B1914115DFF8A30F8393AA7BA22B992EAF75 has minSdk 23 and v1/v2 signatures; MuMu Android 6 overwrite-install, startup, persisted config, qingyunian search, and empty crash buffer passed

Task-Guard: C67-android6-minsdk
2026-10-14 01:23:58 +08:00
Silent1566
a51e4085f5
Merge pull request #442 from Silent1566/dev3
dev3:合并 beta 最新代码(无新提交)并复评修正硬解自动软解回落的开关门控与硬解判据
2026-10-13 08:39:23 +08:00
Silent1566
b3393c6092
Merge pull request #441 from Silent1566/dev2
merge: dev2 合并 beta 最新代码(PR#440)并复评 TV 横幅按 320x180dp 出图
2026-10-13 08:39:07 +08:00
Silent1566
fc790db709 docs(c66): 记录 dev3 合并评审交付坐标(修正提交 434fb60fe8 / recovery tag / 推送 / PR #442)
Verification: 文档-only 闭包提交:记录 C66 交付坐标(提交 434fb60fe8 / recovery tag / 推送 origin/dev3 / PR #442)

Task-Guard: C66-dev3-doc-coordinates
2026-10-13 00:39:44 +08:00
Silent1566
434fb60fe8 merge: 合并 origin/beta 最新代码(无新提交)并复评修正硬解自动软解回落的开关门控与硬解判据
Verification: Leanback ARM64 编译 + 6 个测试类 28/28 通过(BUILD SUCCESSFUL in 47s, exit 0);零丢失缺失 0 / 逐字节一致 5042;零复活交集 6 条经逐条核查全为样板行

Task-Guard: C66-beta-merge-review-dev3-20261013
2026-10-13 00:38:03 +08:00
Silent1566
4913d6ff23 docs(c65): 记录 dev2 交付坐标(合并提交 b6c36bdf1a / recovery tag / 推送 / PR #441)
纯文档收尾:把 C65 任务文档的 Recovery anchor 由「下一步:创建 PR」更新为本任务的
实际交付坐标,使这份持久化执行状态与实际结果一致。

- 合并提交:b6c36bdf1a37fa7d4334efe20c1cd20672f32450(双父 c0ba017885 + 37bca76737)
- 恢复标签(本地):recovery/C65-beta-merge-review-dev2-20261012/20261012160732-b6c36bdf1a37
- 推送:origin/dev2 快进 8b5f8e9026..b6c36bdf1a
- PR:#441(dev2 -> beta,OPEN / MERGEABLE,只创建不合并)

无代码、资源、构建或行为改动,因此不重跑测试。

Verification: 交付坐标已逐条核对:gh pr view 441 => state=OPEN, isDraft=false, baseRefName=beta, headRefName=dev2, mergeable=MERGEABLE;git rev-list --left-right --count origin/dev2...HEAD => 0 0(已推送且无分叉);git tag --list 'recovery/C65*' 命中 recovery/C65-beta-merge-review-dev2-20261012/20261012160732-b6c36bdf1a37;本次为纯文档改动,无代码/资源/构建行为变化,故不重跑测试

Task-Guard: C65-delivery-coords-dev2
2026-10-13 00:20:07 +08:00
Silent1566
b6c36bdf1a merge: 合并 origin/beta 最新代码(PR#440 已把 dev2 并入 beta)并复评 dev2 已提交未推送的 TV 横幅高清化改动
合并:git merge --no-commit --no-ff origin/beta(37bca767373804c381ffbe3e8f565ebf33b4b281,
Merge pull request #440 from Silent1566/dev2),0 冲突;MERGE_HEAD 即 beta tip。
合并基点为上一轮的合并提交 8b5f8e9026。

本轮结构性特点:beta 相对合并基点未新增任何内容,合并是内容中性的。
- git diff --name-status 8b5f8e9026 origin/beta => 空
- 合并后索引树 git write-tree = a186f1c817
- dev2 tip 树 c0ba017885^{tree}  = a186f1c817
两者哈希相同,即本次合并只把 beta tip 记入 dev2 历史(消除 1 behind),不改变任何一个文件。
原因是上一轮 PR #440 已把 dev2(8b5f8e9026)并入 beta,beta 侧唯一增量就是那个合并提交本身。

零复活 / 零丢失(三层证据;用户明确要求远端已移除/回退的提交不得顺带提交上去):
1. 净差异:git diff --name-status origin/beta dev2 仅 c0ba017885 自身的 7 个路径。
2. beta 侧改动:git diff --name-status 8b5f8e9026 origin/beta 为空 => beta 未删除、未修改任何
   内容,结构上不可能复活。
3. 路径状态:上述 7 个路径在 beta 树中全部为 M(既有文件)、无 A => 不存在「把已删文件加回来」
   的形态。另回溯 beta 历史上触及这 7 个路径的 23 个单亲提交,逐条 numstat 均为前向新增/改写,
   无删除交集。

复评(1 轮通过,未发现缺陷):对象为 dev2 已提交未推送的 c0ba017885
「fix(tv): TV 横幅按 320x180dp 出图,消除启动器放大导致的字标锯齿」,改动集 7 路径
(5 档 mipmap-*/ic_banner.png + AppBrandingContractTest.java + scripts/gen_app_icon.py),
实质是把 BANNER_SIZES 由 160x90/240x135/320x180/480x270/640x360 px(=160x90 dp)
上调为 320x180/480x270/640x360/960x540/1280x720 px(=320x180 dp)。核查结论:
1. dp 尺寸与同族入口自洽:AndroidManifest 的 history 别名用矢量 @drawable/ic_banner_history,
   声明为 320dp x 180dp;改动前同一 App 两个启动器入口的横幅 dp 尺寸并不一致(矢量 320x180 dp、
   位图 160x90 dp),位图侧才是异类。仓库自身即为佐证,不必只依赖外部文档。
2. 机理与用户症状吻合:位图按 160x90 dp 出图时,每一档密度交给启动器的位图都只有磁贴 dp 尺寸的
   一半,启动器只能统一放大 2 倍,字标必然出锯齿——正是用户报的「分辨率不够、锯齿很严重」。
   改为 320x180 dp 后每档 1:1。
3. 生成器确在目标分辨率绘制:render_banner(w,h) 的布局求解全部发生在最终像素尺寸上
   (_render_mark 按目标 O 直径直接绘制、_render_text 先探针量墨迹再定字号),无图层被放大。
4. 补测关闭一处验证缺口:提交记录的「5 档实测」只列了像素尺寸,放大后的档位从未实测过
   (C35 原始评审只测过 160x90 dp 那一版)。本次用生成器自身的
   make_gradient(max(w,h)).resize((w,h), LANCZOS) 复现背景并与已提交 PNG 逐像素求差,
   掩膜即真实墨迹:5 档全部完全不透明、含真实墨迹、落在四边各 6.1% 安全区内、宽高比精确 16:9。
   xhdpi 墨迹宽/宽 0.8781 相对安全区 0.8780 仅溢出 0.04 px,在求解器自身 total<=safe_w+0.5
   余量内,属亚像素舍入而非越界。
5. 放大档位是独立渲染而非放大:墨迹像素数随档位按面积增长但始终略低于纯面积倍率
   (0.9950 / 0.9770 / 0.9821 / 0.9893);若为插值放大应≈1.0 甚至更高。
6. 字节级确定性:新 mdpi/hdpi/xhdpi 与旧 xhdpi/xxhdpi/xxxhdpi 逐字节一致
   (9639 / 16295 / 24216 B),净新增 xxhdpi 960x540 与 xxxhdpi 1280x720 两档。
7. 无残留引用:本次真正淘汰的 160x90/240x135 在 app/src 与 scripts 零命中。
8. 代价:5 档横幅合计 60930 -> 155319 B(+92 KiB);运行期只解码匹配密度的那一档,
   xhdpi 单张 ARGB_8888 约 0.23 -> 0.92 MB,对启动器磁贴可接受。

非阻塞观察(记录不修):do_preview() 仍以 320x180 出预览,改动后它已是最小档而非代表档;
脚本注释把 xhdpi 320x180 px 描述为「API<=25 旧式兜底最小尺寸」属规范转述,本环境无法复核
(文档页为 JS 渲染壳、Web 检索不可用),记为未复核表述,改动正确性不依赖它。

Verification: 合并 0 冲突且内容中性(合并后索引树 = dev2 tip 树 = a186f1c817b656c213c17b87da2111b3e3c86efa;git diff --name-status 8b5f8e9026 origin/beta 为空,零复活/零丢失三层证据通过);./gradlew :app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.setting.AppBrandingContractTest => BUILD SUCCESSFUL (7m41s),报告 tests=13 failures=0 errors=0 skipped=0;横幅补测(复现背景逐像素求差)5 档全部不透明/含真实墨迹/在 6.1% 安全区内/精确 16:9,墨迹面积倍率 0.9950/0.9770/0.9821/0.9893 均 <1.0 证独立渲染;新 mdpi/hdpi/xhdpi 与旧 xhdpi/xxhdpi/xxxhdpi 逐字节一致

Task-Guard: C65-beta-merge-review-dev2-20261012
2026-10-13 00:07:29 +08:00
Silent1566
3c230bac1e merge: 合并 webhtv/webhtv 分支 Silent1566 的 3 个硬解自动软解回落提交并修订 Exo 解码合同
Verification: Leanback ARM64 Java 编译 :app:compileLeanbackArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL exit 0 (5m57s);解码模式定向测试 :app:testLeanbackArm64_v8aDebugUnitTest 覆盖 CompatFfmpegVideoRendererSourceTest + MpvHardwareDecodePolicyTest + ExoAudioCodecSelectorTest,9 tests / 0 failures / 0 errors,BUILD SUCCESSFUL exit 0 (1m21s);合并后 3 个文件相对源提交 590942503a 的新逻辑逐字节一致(无 +/- 命中 needsSoftDecode/hasHardwareVideoDecoder/softDecodeFallbackAttempted 等新增符号);设备复测未执行(无现场源 URL),边界见 docs/C65-player-hwdec-auto-soft-fallback-merge-20261012.md 第5节

Task-Guard: C65-player-hwdec-auto-soft-fallback-merge-20261012
2026-10-12 23:54:41 +08:00
Silent1566
c0ba017885 fix(tv): TV 横幅按 320x180dp 出图,消除启动器放大导致的字标锯齿
用户反馈横屏图标(Android TV banner)分辨率不够、锯齿严重。横幅此前按官方
xhdpi 最小尺寸 320x180 px(即 160x90 dp)出图,而启动器磁贴按 dp 绘制:
1080p/xhdpi 磁贴要 640x360 px、4K 要 1280x720 px,启动器只能把位图放大,
字标因此出现锯齿。

改为每档按 320x180 dp 出图(mdpi 320x180 起,xxxhdpi 1280x720),即官方
最小尺寸的 2 倍:启动器要么 1:1 取用、要么缩小,两条路径都不再放大。
图像内容未改动——新的 mdpi/hdpi/xhdpi 与旧的 xhdpi/xxhdpi/xxxhdpi 逐字节
一致,仅新增 xxhdpi 960x540 与 xxxhdpi 1280x720 两档更大的图,APK 约 +94 KB。

Verification: bash ./gradlew :app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.setting.AppBrandingContractTest => 13 tests, 0 failures, 0 errors(含 tvBannerIsProvidedPerDensityAtFullResolution 按新尺寸逐档断言 + 16:9);5 档横幅实测 320x180/480x270/640x360/960x540/1280x720;新 mdpi/hdpi/xhdpi 与旧 xhdpi/xxhdpi/xxxhdpi 逐字节一致

Task-Guard: tv-banner-hidpi
2026-10-12 23:09:12 +08:00
Silent1566
590942503a fix(player): 修正硬解回软解对 Dolby Vision 等改写 mime 渲染器的误判
hasHardwareVideoDecoder 原先只要平台未列出该 mime 的硬件解码器就返回 false。
但 MediaCodecSelector.DEFAULT 即 MediaCodecUtil::getDecoderInfos,其内部
getDecoderInfosInternal -> getCodecMimeType 只匹配真正声明该 mime 的编解码器,
因此非原生 Dolby Vision 设备上 video/dolby-vision 返回空列表;而 ExoUtil 的
DV5 GPU 渲染器与 Dolby Vision HDR10 回退渲染器仍会把该轨判定为 FORMAT_HANDLED
(内部改写为 video/hevc 交给硬件 HEVC 解码)。needsSoftDecode 于是把这条本已
硬解的 Dolby Vision 轨误判为"硬解无硬件通路",强制切到软解并重建播放器。

改为:只有平台确实列出了该 mime 的解码器且全部为软件解码器时才返回 false;
空列表表示平台不声明该 mime,可能由应用自有渲染器接管,按"未证实"处理,不再
改变用户可见的解码模式。AVS3 等"完全无解码器"场景仍由 needsSoftDecode 的
decodable == null 分支触发软解,行为不变。

同时修正 ExoUtil 中"硬解绝不注册软件回退"的注释:该约束只适用于扩展渲染器
(FFmpeg);getVideoCodecSelector 保留平台软件解码器作为最后兜底是有意为之,
且正是 PlayerManager 判定需要切软解的信号,两者必须保持一致。

Verification: 编译 :app:compileLeanbackArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL exit 0
Task-Guard: PLAYER-HWDEC-REVIEW-FIX-01

Verification: 编译 :app:compileLeanbackArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL exit 0;证据链:MediaCodecSelector.DEFAULT = MediaCodecUtil::getDecoderInfos(严格 mime 匹配),getDecoderInfosInternal 经 getCodecMimeType 只匹配声明该 mime 的编解码器,故非原生 DV 设备上 video/dolby-vision 返回空列表;ExoUtil DV HDR10 回退渲染器(1102-1108)与 ExoDv5GpuRenderer 仍以 video/hevc 判定该轨 FORMAT_HANDLED。未做设备实测(本次无可用设备)。

Task-Guard: PLAYER-HWDEC-REVIEW-FIX-01
2026-10-12 22:52:10 +08:00
Silent1566
bd24f9d53d fix(player): 硬解无硬件解码器时自动切换软解模式
Verification: 编译 :app:compileLeanbackArm64_v8aDebugJavaWithJavac exit 0;设备 NX627J(127.0.0.1:5563) 覆盖安装后新进程以硬解起播 4K HEVC,自动切换为软解:日志 decode=software、decoder=OMX.google.hevc.decoder、firstFrameMs=2894;OSD 按钮由硬解变为软解,诊断面板 配置 EXO/软解/软解降负载 EXO跳帧滤波低分辨,画面正常渲染(36:10/44:08),重缓冲由 6 次降至 2 次

Task-Guard: PLAYER-HWDEC-MODE-ALIGN-01
2026-10-12 21:56:43 +08:00
Silent1566
37bca76737
Merge pull request #440 from Silent1566/dev2
merge: 合并 beta 最新代码(PR#439)并复评详情页季集交接改动
2026-10-12 21:44:11 +08:00
Silent1566
edb1cf8eaa fix(player): 硬解无硬件解码器时不再丢弃视频轨并自动回落软解
Verification: 编译 :app:compileLeanbackArm64_v8aDebugJavaWithJavac exit 0;设备 NX627J(127.0.0.1:5563) 覆盖安装 leanbackArm64 debug 后,硬解模式诊断面板显示 decoder OMX.google.hevc.decoder、配置 EXO/硬解、3840x1920 HEVC 画面正常渲染(30:03/44:08),未触发自动软解回落

Task-Guard: PLAYER-HWDEC-FALLBACK-01
2026-10-12 21:24:42 +08:00
Silent1566
8b5f8e9026 merge: 合并 origin/beta 最新代码(PR#439 dev4 对话框取色修复)并复评 dev2 已提交的季集交接改动
合并:git merge --no-commit --no-ff origin/beta(b0b7f1d78b5e394c0c9635a8b9c71b4417b06e25,
Merge pull request #439 from Silent1566/dev4),0 冲突;MERGE_HEAD 即 beta tip。
纳入 beta 侧 4 个提交(含 dev4 的 fix(theme): TV 对话框面板与前景取自同一张色表 及两份文档)。

零复活 / 零丢失(三层证据):
1. 合并树 ≡ beta tip + dev2 自身 4 路径:git diff --name-only origin/beta 仅 4 个 dev2 文件。
2. 零丢失(blob 级):beta tip 5047 个文件逐个比对合并结果树,缺失 0、逐字节一致 5043,
   差异仅 dev2 自己的 4 个路径;且 beta 相对 merge-base 从未改过这 4 个路径。
3. 零复活(严格判据,按「文件+行」):beta 历史上 27 个单亲回退提交共删除 4472 条
   (文件,行) 记录,与 dev2 自身新增的 282 条记录求交集 = 0。

复评(2 轮)发现并修复 3 项真实问题,全部落在 dev2 已提交的季集交接改动上:
1. F1(阻塞)单季兜底会覆盖用户显式「保持原始剧集列表」(MANUAL_FLAT):解析器只在
   MANUAL_FLAT 时返回 Status.FLAT,旧实现对非 RESOLVED 一律不绑定;兜底只要 TMDB 恰有一个
   正片季就绑定,播放页会挂 TMDB 集标题并经 TmdbEpisodeSorter.sort 原地重排选集,
   还与详情页(该模式 availableSeasonNumbers 返回空、不画卡片)表现相反。
2. F2(重要)单季兜底会覆盖解析器「已看到相反证据」的 AMBIGUOUS:TMDB 只有第 1 季而源站剧名/
   集名明确指向第 2 季时,解析器故意返回 title_season_missing_from_tmdb /
   explicit_season_missing_from_tmdb / title_and_source_season_conflict 拒绝绑定,
   兜底会无视证据把第 1 季标题静默挂到第二季源列表。
   F1+F2 同一处修复:兜底前加来源白名单,只对 Source.REQUEST(请求季不在 TMDB)与
   Source.NONE(源站路径显式关闭启发式)生效,其余来源一律不兜底。
3. F3(重要)单季兜底会把 MULTI_SLICE 的分段结论降级成单季路径:切片路径以 null 作为季号
   一致性校验的期望值,兜底返回非 null 会让调度侧改走单季绑定、执行侧的切片校验又必然否决,
   整个分段(含特别篇)一集都绑不上。修复:兜底前先判 MULTI_SLICE。
并同步修复 seedSeasonEpisodes 的注释与实现不符(「不会发起网络请求」在内存未命中时不成立)。

复评第 2 轮(修复后复审):MULTI_SLICE 守卫与来源白名单按 TmdbSeasonResolver.resolve 的
全部 source/reason 逐条推演,确认既不过宽(不再覆盖 FLAT 与带相反证据的 AMBIGUOUS)也不过窄
(REQUEST + requested_season_missing_from_tmdb 与 NONE + heuristic_guessing_disabled 两条
本次要救的路径仍能兜底);代次校验自洽(MULTI_SLICE 两侧都期望 null,RESOLVED 两侧都取
selectedSeason);无新增阻塞问题。

验证:双 flavor 编译 + 双 flavor AndroidTest 编译 + 全量 JVM 套件。

Verification: 双 flavor Java 编译 + 双 flavor AndroidTest 编译 BUILD SUCCESSFUL;双 flavor 全量 JVM 套件:leanback 4214 tests / 8 failures / 3 skipped、mobile 5026 / 7 / 3;相对合并前(leanback 4211/8/3、mobile 5026/7/3)增量仅 leanback +3 例 = beta 带入的 TvDialogPaletteModeTest 3 例且全绿,失败集合与既有环境基线(docs/C58-beta-merge-review-dev2-20261011.md:leanback 7 类 8 例、mobile 6 类 7 例;根因 core.autocrlf=true 的 CRLF 检出使含裸 \n 的守卫断言失配,以及 Windows renameTo 语义)同类同数、零新增;TmdbDetailCacheTest 14 例在两 flavor 全绿;合并零复活严格判据(文件+行)交集 0、零丢失 blob 级比对缺失 0 且逐字节一致 5043/5047

Task-Guard: C64-beta-merge-review-dev2-20261012
2026-10-12 20:40:16 +08:00
Silent1566
d5ceea9682 fix(tv): 详情页已解析季集随详情快照交接给播放页,并补单季剧季号兜底
播放页的选集卡片依赖 Episode.tmdbEpisode,而该字段只有播放页自己再取一次分季才会写入。
详情页跳转前已经取过同一季(否则它自己也画不出卡片),数据却被丢弃,于是详情页有卡片、
播放页退化成纯文本按钮;那次重复请求失败时表现更明显。

改动:
1. TmdbDetailCache 新增 5 参 put 与 Entry.getSeasonEpisodes():季集数据随详情快照交接,
   构造与读取都做防御性拷贝,过滤负季号与空季。
2. TmdbDetailActivity 跳转播放时把 tmdbSeasonEpisodes 一并交出。
3. TmdbUIAdapter 新增 seedSeasonEpisodes():把快照预填进 seasonEpisodeCache,键与
   seasonEpisodes() 的读取键同源;load(item, vod) 与 load(item, vod, cached) 两条入口都调用。
4. loadSource() 在 applySourceBundle 之后补一次 scheduleStartupEpisodeLoad():内嵌分季数据
   只写缓存不会给 Episode 挂 tmdbEpisode,不补绑定则内嵌 payload 的站点在播放页永远是纯文本选集。
5. currentEpisodeMetadataSeason() 增加 soleOrdinarySeason() 兜底:恰好一个正片季时不再因
   解析器返回 AMBIGUOUS 就放弃逐集绑定。

复评 2 轮发现并修复 3 项真实问题(已落地并加回归锁):
1. F1(阻塞)兜底会覆盖用户显式「保持原始剧集列表」(MANUAL_FLAT):解析器只在 MANUAL_FLAT
   时返回 Status.FLAT,旧实现对非 RESOLVED 一律不绑定;新兜底只要 TMDB 恰有一个正片季就绑定,
   播放页会挂 TMDB 集标题并经 TmdbEpisodeSorter.sort 原地重排选集,还与详情页(该模式
   availableSeasonNumbers 返回空、不画卡片)相反。
2. F2(重要)兜底会覆盖解析器「已看到相反证据」的 AMBIGUOUS:TMDB 只有第 1 季而源站剧名/集名
   明确指向第 2 季时,解析器故意返回 title_season_missing_from_tmdb /
   explicit_season_missing_from_tmdb / title_and_source_season_conflict 拒绝绑定,兜底会无视
   证据把第 1 季标题挂到第二季源列表。
   F1+F2 同一处修复:兜底加来源白名单,只对 Source.REQUEST(请求季不在 TMDB)与 Source.NONE
   (源站路径显式关闭启发式)生效,其余来源一律不兜底。
3. F3(重要)兜底会把 MULTI_SLICE 的分段结论降级成单季路径:切片路径以 null 作为季号一致性
   校验的期望值,兜底返回非 null 会让调度侧改走单季绑定、执行侧的切片校验又必然否决,整个
   分段(含特别篇)一集都绑不上。修复:兜底前先判 MULTI_SLICE。

测试:TmdbDetailCacheTest 由 6 例扩到 14 例(交接快照携带、防御性拷贝、空季与负季号过滤、
内层不可变、无季集返回 null,以及 3 条消费端源码守卫)。mobile 源集已存在同名
TmdbUIAdapterTest,共享源集不能再建同名类,故消费端守卫并入本文件。

验证:双 flavor Java 编译 BUILD SUCCESSFUL;双 flavor 全量 JVM 套件 leanback 4211 tests /
8 failures / 3 skipped、mobile 5026 / 7 / 3,失败集合与本机既有环境基线
(docs/C58-beta-merge-review-dev2-20261011.md:leanback 7 类 8 例、mobile 6 类 7 例)同类同数、
零新增;根因是 core.autocrlf=true 检出为 CRLF 而守卫断言使用裸 \n,以及 Windows renameTo 语义,
与本次改动无关。新增 8 例在两 flavor 全绿。

已知限制(不在本轮范围,留待合并步骤处理):源站 payload 分支(VideoActivity 的 RENDERABLE
分支走 loadSource)不消费交接快照,对「payload 只带季集数、不带 episodes」的站点,详情页已取过的
季会被丢弃,播放页补绑定会再发一次同季请求;修复需要改 scope 外的 VideoActivity(leanback + mobile)。

Verification: 双 flavor Java 编译 BUILD SUCCESSFUL;双 flavor 全量 JVM 套件:leanback 4211 tests/8 failures/3 skipped、mobile 5026/7/3,失败集合与既有环境基线(C58 文档 leanback 7 类 8 例、mobile 6 类 7 例)同类同数、零新增(根因:core.autocrlf=true 的 CRLF 检出使裸 \n 守卫断言失配、Windows renameTo 语义);新增 TmdbDetailCacheTest 14/14 双 flavor 全绿(含 3 条消费端源码守卫);复评 2 轮修复 F1(MANUAL_FLAT 被兜底覆盖,阻塞)/F2(带相反证据的 AMBIGUOUS 被覆盖)/F3(MULTI_SLICE 被降级),并补 8 条回归锁用例

Task-Guard: EPISODE-CARD-HANDOFF-20261012
2026-10-12 19:44:54 +08:00
Silent1566
b0b7f1d78b
Merge pull request #439 from Silent1566/dev4
dev4:合并 beta 最新代码(PR#438 Android 7 兼容修复)并复评 TV 对话框取色同源修复
2026-10-12 13:05:49 +08:00
Silent1566
139f2ab5d1 docs(c63): 记录 dev4 合并评审交付坐标(合并提交 a25ac9dd72 / recovery tag / 推送 / PR #439) 2026-10-12 13:03:15 +08:00
Silent1566
a25ac9dd72 merge: 合并 origin/beta 最新代码(PR#438 dev1 Android 7 兼容修复)并复评 dev4 已提交未推送的 TV 对话框取色修复
把远端 beta 最新 tip 92a0ca0bbe5(PR #438)合入 dev4,自动合并无冲突,0 未解决冲突。
beta 本轮增量 11 个提交、10 个路径:Android 7(API 24/25)真机排查确认的三个缺陷修复
——ViewCompat 守卫 setImportantForAutofill、LabRunner 用 exitValue() 替代
Process.isAlive()、MpdSanitizer 改用 API 1 的 StringBuffer matcher 重载——外加 3 个
契约测试与 2 篇文档。不执行 cherry-pick;beta 本轮未删除任何路径,两条分支的删除面
均为空,不存在被顺带重新提交的回退内容。

复评 dev4 已提交未推送的 4c5f4dc8421(TV 对话框面板与前景取自同一张色表):
applyFromPreferences(activity) 现在把同一个 Activity context 交给 frozenPalette 与
resolveWith,baseline/current 不可能再分叉;全仓生产调用方只有 leanback/mobile 的
BaseActivity 与 FollowingActivity,均传 this;resolveFromPreferences()/refresh() 无
生产调用方,null 分支保持原语义;App.java 在进程启动期即应用强制夜间模式,时序正确。

三轮评审未发现必修缺陷。验证:leanback 定向 192 例、mobile 定向 180 例,
0 failure / 0 error;双 flavor androidTest 源集编译 BUILD SUCCESSFUL。

评审记录见 docs/C63-beta-merge-review-dev4-20261012.md。
2026-10-12 13:01:18 +08:00
Silent1566
4c5f4dc842 fix(theme): TV 对话框面板与前景取自同一张色表
resolvedDark()/compiledDarkPalette() 之前用进程级应用上下文加原始系统夜间位判
深浅,而 AppCompatDelegate 的强制夜间模式只改写它代理的 Activity 资源(API < 31
不改写应用上下文)。TV 侧 applyNightModeToApp() 又按产品默认强制 MODE_NIGHT_YES,
于是系统日间的电视上「新增点播」面板取到日间表、同屏前景取到夜间表:实测 info
1.06:1、输入框提示 1.39:1、描边按钮文字 1.41:1。

改为按真正 inflate 的 Activity 上下文取表,baseline 与 current 同步对齐(无
Activity 的入口保持原行为)。同一台模拟器前后对照:info 10.48:1、提示 7.93:1、
描边按钮 7.86:1、主按钮 7.5:1;修复后日间模式渲染与夜间模式渲染逐字节相同。
2026-10-12 12:26:10 +08:00
Silent1566
92a0ca0bbe
Merge pull request #438 from Silent1566/dev1
merge(dev1): 合并 beta(PR#437)并复评 Android 7 支持改动(补齐回归锁 + 订正文档)
2026-10-12 11:14:44 +08:00
Silent1566
04b32d4e14 docs(c62): 记录交付坐标(双父合并提交 11578a6ee / recovery tag / 推送 / PR #438)
收尾补记:合并提交两个父(8daf00907 + af9a18fa4 = 当时 beta tip)、origin/dev1 已同步、PR #438 状态 OPEN/未合并/文件集 10 项与本地净差异逐项一致、收尾复核 beta tip 未推进。

Verification: 收尾补记:双父合并提交 11578a6ee(父1 8daf00907 / 父2 af9a18fa4 = beta tip)已推送 origin/dev1;PR #438 已创建(state=OPEN、mergedAt=null、mergeable=MERGEABLE、changedFiles=10),PR 文件集与 git diff --name-only origin/beta HEAD 逐项一致;收尾 fetch 后 beta tip 仍为 af9a18fa4;工作区仅 .scratch-goal/;本轮无生产代码行为改动

Task-Guard: C62-beta-merge-review-dev1-20261012-coords
2026-10-12 11:11:51 +08:00
Silent1566
11578a6eee merge: 合并 origin/beta 最新代码(PR#437 dev4 屏显对比度修复)并复评 dev1 已提交未推送的 Android 7 支持改动
复评(2 轮)发现并修复 3 项真实问题:
1. 三处 Android 7 修复缺少已提交的回归锁:新增 3 个用例类共 6 例(源码守卫 + 语义用例),并用 4 处变异验证可转红;
2. 订正 android7 文档中 MpdSanitizer 的影响机制:NoSuchMethodError 属 Error,MpdSanitizer.sanitize() 与 Source.fetch() 的 catch(Exception) 都捕不到(后者只包住 extractor 调用),原文「被捕获后静默返回未处理 URL」不成立;
3. 订正该文档的 NewApi 计数(51 处/25 处 API 26,非 52/23)与用例数口径(9197 系两 flavor 合计,leanback 单任务实测 4191)。

验证:双 flavor 编译 + AndroidTest 编译 + 全量 JVM 套件 leanback 4203/0、mobile 5018/0(各 +12,可逐项解释);UI token 门禁 PASS(violations 零新增);零复活三层证据通过(合并树 ≡ beta tip + dev1 自身 6 路径,严格复活行 0,beta 侧 0 文件丢失)。

Verification: 双 flavor Java 编译 + 双 flavor AndroidTest 编译 BUILD SUCCESSFUL;全量 JVM 套件 leanback tests=4203 failures=0 errors=0、mobile tests=5018 failures=0 errors=0(相对 C61 基线 4191/5006 各 +12,= 本轮 6 个回归锁用例 + beta PR#437 带入 6 例);变异验证:4 处缺陷形态变异使 6 例中 4 例转红,恢复后 sha256 一致且全绿;javap 产物核对 Process#isAlive=0、Matcher(StringBuffer) 重载=10、ViewCompat.setImportantForAutofill=2;scripts/check_ui_tokens.sh PASS violations=1(零新增);零复活三层证据:合并树 ≡ beta tip + 6 个 dev1 路径、严格复活行 0、beta 5039 文件中 5034 逐字节一致且 0 丢失;git diff --check EXIT=0

Task-Guard: C62-beta-merge-review-dev1-20261012
2026-10-12 11:10:13 +08:00
Silent1566
8daf00907e docs(android7): add real Android 7.1.2 device verification
Add section 9 recording the end-to-end validation on the real Android 7.1.2
(API 25) device at 192.168.50.3:5587, which confirms the audit's core findings
against real hardware rather than symbol analysis alone:

- the shipped libmpv.so cannot be dlopened on API 25 (cannot locate symbol
  vkGetPhysicalDeviceQueueFamilyProperties2) while the identical command
  succeeds on API 28
- the device's own libvulkan.so exports none of the six required Vulkan 1.1
  entry points (193 ARM / 191 x86 exports inspected)
- control experiments separate the Vulkan dependency from environmental noise
- on API 25 the pre-fix View#setImportantForAutofill is absent while
  ViewCompat.setImportantForAutofill returns early, confirming the fix

Also note the houdini translation-layer artifact (St3__1 namespace) so future
native-library triage on translated devices uses the target-architecture
linker instead of an x86 app_process probe.

Verification: real Android 7.1.2 (API 25) device verification, documented in the audit's new section 9: (1) decisive A/B - the shipped v7a libmpv.so dlopened via the device's own ARM linker fails with 'cannot locate symbol vkGetPhysicalDeviceQueueFamilyProperties2' on API 25 but loads OK on API 28 with the identical command; (2) the device's own /system/lib/arm/libvulkan.so (193 exports) and /system/lib/libvulkan.so (191 exports) export none of the 6 required Vulkan 1.1 symbols; (3) control experiments confirm the probe is valid (OK on API 28) and the failure is Vulkan-specific (a probe without the Vulkan dependency loads OK on API 25); (4) A/B on the fixed defect: on API 25 'View#setImportantForAutofill' is absent (NoSuchMethodException) while ViewCompat.setImportantForAutofill exists and returns early without touching the API-26 method; (5) leanback/armeabi-v7a debug APK built and installed via scripts/build_arm64_debug_install.sh and cold-started with 0 FATAL EXCEPTION / NoSuchMethodError. Documentation-only commit; no production code changed.

Task-Guard: ANDROID7-REALDEVICE-EVIDENCE
2026-10-12 10:24:29 +08:00
Silent1566
af9a18fa47
Merge pull request #437 from Silent1566/dev4
dev4:合并 beta 最新代码(PR#434 焦点环主题 / PR#435 停播 / PR#436 更新判定与数据库完整性)并复评屏显对比度与 Custom CSP 主题修复
2026-10-11 17:29:28 +08:00
Silent1566
29c2810638 docs(android7): align summary wording with the three fixed defects
The header and section 5 conclusions still described a single unfixed
Java-layer defect. Update them to state that three real defects were found and
fixed, leaving the libmpv.so Vulkan 1.1 / BIND_NOW blocker as the only
remaining Android 7 gap.

Verification: documentation-only wording correction: the header conclusion and the section 5 summary now state that three real defects were found and fixed (two of which crashed on Android 7) instead of implying a single remaining Java-layer defect. The only remaining Android 7 blocker is the bundled libmpv.so Vulkan 1.1/BIND_NOW issue. No production code changed.

Task-Guard: ANDROID7-AUDIT-SUMMARY-FIX
2026-10-11 17:28:04 +08:00
Silent1566
0b036f9d01 docs(android7): close out the three fixed defects and restate the MPV blocker
Record the per-fix verification evidence for the ViewCompat API guard, the
LabRunner.isAlive API-1 helper, and the StringBuffer Matcher overloads, plus
the aggregate lint error reduction from 254 to 236. The remaining Android 7
blocker is unchanged: the bundled libmpv.so references Vulkan 1.1 core entry
points that the platform libvulkan.so only exports from API 28, combined with
BIND_NOW eager binding.

Verification: documentation-only closure update: the audit document now records all three fixed defects with their individual verification evidence (ViewCompat API guard for the Git cloud/Remote trust dialog crash, LabRunner.isAlive API-1 helper replacing Process#isAlive, and StringBuffer Matcher overloads replacing the API-34 StringBuilder overloads), the aggregate lint error reduction 254->236, and restates the single remaining Android 7 blocker (bundled libmpv.so requiring API-28 Vulkan 1.1 entry points with BIND_NOW eager binding). No production code changed in this commit.

Task-Guard: ANDROID7-AUDIT-DOC-CLOSURE
2026-10-11 17:27:15 +08:00
Silent1566
8bb62a7906 fix(mpd): use API-1 StringBuffer Matcher overloads instead of API 34
MpdSanitizer passed StringBuilder buffers to Matcher#appendReplacement and
Matcher#appendTail. Those overloads only exist since API 34 and no desugaring
backports java.util.regex, so on every device below API 34 the call threw
NoSuchMethodError. Source.fetch() catches Exception and silently returned the
unsanitized URL, so MPD frame-rate/AdaptationSet-id repair quietly did nothing
(instead of crashing playback).

Switch all five buffers to StringBuffer, whose overloads have existed since
API 1 and behave identically here (single-threaded local use).

Verification: MpdSanitizer: all 5 Matcher#appendReplacement and 5 appendTail call sites switched from the StringBuilder overload (API 34) to the StringBuffer overload (API 1), which is semantically identical for these single-threaded local buffers and matches the existing LabRunner.expandNested pattern; javap on the compiled class shows 0 appendReplacement(StringBuilder)/appendTail(StringBuilder) and 5+5 StringBuffer variants; :app:compileLeanbackArm64_v8aDebugJavaWithJavac + :app:compileMobileArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL; lint NewApi errors for those symbols gone and total lint errors dropped 246->236; scripts/build_arm64_debug_install.sh --flavor leanback --abi arm64-v8a built and installed over the existing package on 192.168.50.3:5555; decisive device runtime test: invoking MpdSanitizer.sanitize() on an invalid-frameRate MPD and an invalid-AdaptationSet-id MPD now returns OK with changed=true, whereas the same probe against the pre-fix APK threw java.lang.NoSuchMethodError: appendReplacement(Ljava/lang/StringBuilder;Ljava/lang/String;)

Task-Guard: ANDROID7-MPDSANITIZER-MATCHER-API34
2026-10-11 17:26:29 +08:00
Silent1566
656d3dcbc8 fix(android7): replace Process#isAlive (API 26) with an API-1 compatible check
LabRunner.isRunning/runningCount/runningKeys and three LabTerminalActivity
call sites used Process#isAlive(), which only exists since API 26. Those paths
run from LabAutoStart on app startup (and from the lab list adapters), so an
Android 7 user with an installed lab entry crashed with NoSuchMethodError.
That error is an Error rather than an Exception, so LabAutoStart's
catch (Exception ignored) could not absorb it.

Add LabRunner.isAlive(Process) built on exitValue(), which throws
IllegalThreadStateException exactly while the process is still running, and
route every call site through it. Semantics match the API-26 method and the
helper is available from API 1.

Verification: LabRunner/LabTerminalActivity: replaced all 6 Process#isAlive() (API 26) call sites with a new LabRunner.isAlive(Process) helper that uses exitValue()/IllegalThreadStateException (API 1) with identical semantics, verified by a standalone JVM probe (running process -> IllegalThreadStateException -> alive; finished process -> exitValue returns -> not alive); javap on compiled classes shows 0 remaining java/lang/Process;.isAlive invocations; :app:compileLeanbackArm64_v8aDebugJavaWithJavac and :app:compileMobileArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL; full :app:testLeanbackArm64_v8aDebugUnitTest suite passes (9197 tests, 0 failures) including the existing lab tests; lint NewApi errors for java.lang.Process#isAlive gone and total lint errors dropped 252->246; scripts/build_arm64_debug_install.sh --flavor leanback --abi arm64-v8a built and installed over the existing package on 192.168.50.3:5555, and a cold start (which runs LabAutoStart at +3s) left the process alive with zero FATAL EXCEPTION/NoSuchMethodError in logcat

Task-Guard: ANDROID7-LAB-PROCESS-ISALIVE
2026-10-11 17:16:42 +08:00
Silent1566
22fe625814 docs(android7): correct libmitv.so row (32-bit ARM lib inside arm64 APK)
The flagged symbols in assets/libmitv.so are ARM compiler-runtime helpers
(__aeabi_*, _Unwind_*) resolved by the platform at runtime, and the file is
a 32-bit ARM object shipped from the third-party forcetech AAR rather than a
minimum-API problem. Record that distinction accurately.

Verification: documentation-only precision fix: corrected the assets/libmitv.so row after verifying with 'file' that the library is 32-bit ARM (EABI5) shipped inside the arm64-v8a APK from the third-party forcetech-release.aar; its undefined symbols are ARM compiler-runtime helpers provided by the platform at runtime, not an API-level issue. No production code changed.

Task-Guard: ANDROID7-API24-SUPPORT-DOC2
2026-10-11 17:03:01 +08:00
Silent1566
9564c3e58d docs(android7): record device proof and full release-APK native re-check
Append the decisive end-to-end evidence for the ViewCompat fix (Git cloud
dialog opens and renders on the dev1 device with no fatal exception) and the
complete per-symbol audit of all 54 native libraries in the shipped release
APK, which confirms libmpv.so remains the only true Android 7 blocker.

Verification: documentation-only update to docs/android7-support-audit-2026-10-11.md recording (a) the end-to-end device proof for the ViewCompat fix (Git cloud dialog opened and rendered on 192.168.50.3:5555, zero FATAL EXCEPTION for the session) and (b) the full 54-native-library re-check of the shipped Release/apk/mobile-arm64_v8a.apk, where only libmpv.so (API>=28 Vulkan 1.1 + BIND_NOW), libexo_dovi_renderer.so (API>=26, Java-guarded) and assets/libmitv.so (runtime-provided ARM EABI symbols) are flagged; no production code changed in this commit

Task-Guard: ANDROID7-API24-SUPPORT-DOC
2026-10-11 17:01:12 +08:00
Silent1566
4e4bfffcb6 fix(android7): guard View#setImportantForAutofill (API 26) behind ViewCompat
GitCloudDialog.buildView() and RemoteTrustDialog.input() called
View#setImportantForAutofill(int) directly. TextInputEditText,
AppCompatEditText, EditText and TextView do not declare that method, so it
resolved to android.view.View#setImportantForAutofill, which only exists
since API 26. Both call sites run unconditionally while the dialog is
created, so opening the Git cloud or Remote trust settings dialog on
Android 7.0/7.1 threw NoSuchMethodError and crashed.

Route both call sites through androidx.core.view.ViewCompat, which returns
early when SDK_INT < 26 and delegates to the very same framework method on
API >= 26, leaving behavior on supported API levels unchanged.

Also add docs/android7-support-audit-2026-10-11.md with the full minimum-API
audit: declared minSdk 24, dependency floors (max 24), per-symbol native
library check, runtime-downloaded node/python components, and the remaining
Android 7 blocker (bundled libmpv.so references Vulkan 1.1 core entry
points that the platform libvulkan.so only exports from API 28, combined
with BIND_NOW eager binding).

Verification: compileLeanbackArm64_v8aDebugJavaWithJavac + compileMobileArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL; javap on compiled classes shows invokestatic androidx/core/view/ViewCompat.setImportantForAutofill (SDK_INT<26 early-return, API>=26 delegates to the identical framework call) replacing android/view/View#setImportantForAutofill (API 26); lint NewApi errors for that symbol gone (254->252 total errors); scripts/build_arm64_debug_install.sh --flavor leanback --abi arm64-v8a built and installed over the existing package on 192.168.50.3:5555; cold start via monkey LEANBACK_LAUNCHER left the process alive with no FATAL/NoSuchMethodError in logcat; audit document docs/android7-support-audit-2026-10-11.md records the full API-24 investigation incl. the libmpv.so Vulkan-1.1/BIND_NOW blocker

Task-Guard: ANDROID7-API24-SUPPORT
2026-10-11 16:58:03 +08:00
Silent1566
4b35e0720c docs(c58): 记录 dev4 合并评审交付坐标(合并提交 3e657bef0d / recovery tag / 推送 / PR #437)
Verification: docs-only: record PR #437 OPEN (mergedAt null, changedFiles 29, MERGEABLE), merge commit 3e657bef0d with parents e0c067cba7 + 8ed903ac2a, recovery tag recovery/beta-sync-review-dev4-20261011-r2/20261011082700-3e657bef0d97, push e0c067cba71..3e657bef0d9, PR files match git diff origin/beta HEAD 29/29

Task-Guard: c58-dev4-coords
2026-10-11 16:39:42 +08:00
Silent1566
3e657bef0d merge: 合并 beta 最新代码(PR#435/#436 停播/更新判定/数据库完整性)并复评 dev4 屏显对比度改动
Verification: origin/beta=8ed903ac2a75bf76b46ab04e17059a30070d4b63; merge commit parents e0c067cba7 + beta tip; zero conflicts after resolving 5 theme resources to beta latest; index tree f66c980de84b53b4b50c8ec9f59813c67d99cdeb; zero beta deletions and zero beta files missing from index (5030/5030); net diff app/docs only; CustomCsp/theme contrast fixes; C59 update ordering, C60 Room integrity recovery, playback stop regressions; leanback+mobile targeted tests and dual flavor Java/AndroidTest compilation BUILD SUCCESSFUL; diff check clean; Gradle stop+clean done

Task-Guard: beta-sync-review-dev4-20261011-r2
2026-10-11 16:26:57 +08:00
Silent1566
8ed903ac2a
Merge pull request #436 from Silent1566/dev1
merge: 合并 origin/beta 最新代码(PR#435 dev2 退出播放页必定停播)并复评修复 C59/C60 的更新判定与注释缺陷
2026-10-11 14:11:01 +08:00
Silent1566
565fac1fd2 docs(c61): 补记收尾复核(beta tip 未推进、临时资源清理、无 active 守卫会话)
- git fetch origin --prune 后 origin/beta 仍为 00ad80114fa971c32de3a74f072e33714b9f488e,git merge-base --is-ancestor origin/beta HEAD 为真
- /tmp/c61/** 已删除;.codex/task-state/current 无 active 会话
- PR #436 复核:state=OPEN、mergedAt=null、mergeable=MERGEABLE、changedFiles=9、文件集与本地净差异逐项一致

Verification: 收尾复核记录:git fetch 后 origin/beta 仍为 00ad80114f 且仍是 HEAD 祖先(合并基点未推进);MERGE_HEAD 已清除;git status --porcelain 仅受保护的 .scratch-goal/;/tmp/c61 已清理;无 active 守卫会话;PR #436 state=OPEN / mergedAt=null / mergeable=MERGEABLE / changedFiles=9 且文件集与 git diff --name-only origin/beta HEAD 逐项一致

Task-Guard: C61-beta-merge-review-dev1-20261011-final
2026-10-11 14:05:00 +08:00
Silent1566
a49b83b261 docs(c61): 订正验证增量表(beta 带入 +2、本轮 F1 锁定用例 +1,合计仍 +19)
实测 dev2 的 97c7ae68a 只在 PlaybackOwnershipSourceTest 新增 2 个 @Test,本轮 F1 锁定用例新增 1 个:
4172 + 12 (C59) + 4 (C60) + 2 (beta) + 1 (C61) = 4191,mobile 同式 = 5006,与 JUnit XML 实测一致。

Verification: 订正 C61 文档的验证增量表(实测 beta 侧 dev2 提交只新增 2 个用例、本轮 F1 锁定用例 +1,合计仍 +19;leanback 4191/0/0、mobile 5006/0/0 与 JUnit XML 实测一致);PR #436 文件集仍与 git diff --name-only origin/beta HEAD 逐项一致

Task-Guard: C61-beta-merge-review-dev1-20261011-coords2
2026-10-11 14:03:16 +08:00
Silent1566
adcb47375f docs(c61): 记录 dev1 合并评审交付坐标(双父合并提交 8b54e0e97 / recovery tag / 推送 / PR #436)
- 合并提交 8b54e0e97c 双父:56372b7dba(合并前 dev1)+ 00ad80114fa(beta tip)
- recovery tag recovery/C61-beta-merge-review-dev1-20261011/20261011140009-8b54e0e97c0a
- 推送 5ad9025f9..8b54e0e97 dev1 -> dev1,origin/dev1 == dev1
- PR #436 state=OPEN / mergedAt=null / mergeable=MERGEABLE / changedFiles=9,文件集与 git diff --name-only origin/beta HEAD 逐项一致(只创建,未合并)

Verification: 坐标闭环:PR #436(dev1 -> beta)state=OPEN、mergedAt=null、mergeable=MERGEABLE、changedFiles=9;PR 文件集与 git diff --name-only origin/beta HEAD 逐项一致(diff 无输出);合并提交 8b54e0e97 为双父(第二父 = 00ad80114 = 当时 beta tip);git merge-base --is-ancestor origin/beta HEAD 为真;MERGE_HEAD 已清除;git rev-parse origin/dev1 == dev1

Task-Guard: C61-beta-merge-review-dev1-20261011-coords
2026-10-11 14:01:24 +08:00
Silent1566
8b54e0e97c merge: 合并 origin/beta 最新代码(PR#435 dev2「退出播放页必定停播」)并复评 dev1 已提交未推送的 C59/C60
合并:git merge --no-commit --no-ff origin/beta(00ad80114fa971c32de3a74f072e33714b9f488e,Merge pull request #435 from Silent1566/dev2),0 冲突;纳入 beta 侧 5 个提交(含 dev2 的 fix(playback): 退出播放页必定停播与两份 C58 文档)。零复活/零丢失:beta tip 5025 个文件逐个 blob 比对,缺失 0、逐字节一致 5021,差异仅 dev1 自己的 C59/C60 路径;行级严格判据(407 个单亲回退提交的 53889 条删除行 ∩ dev1 新增 432 行)复活行数 0。

复评(2 轮)发现并修复 2 项真实缺陷:

- F1(判定方向错误,可导致自动降级):AppVersion.isNewer 原文把「长度不同的两个可用构建时间戳」当成不可比较并直接判定目标为更新,负对照实测 isNewer("v5.6.0-beta-20261009175522", "v5.6.0-202609221328") = true,即 14 位秒级时间戳的装机版本会把更早的 12 位渠道包当作更新推荐,与 BUILD_STAMP 的 \d{12,14} 及 buildStamp() javadoc 声明的 yyyyMMddHHmm[ss] 相矛盾。修复:新增 STAMP_LENGTH/padStamp(),把分钟级时间戳补齐为该分钟第 0 秒后比较,只有真正缺失时间戳才回退历史语义;新增用例 AppVersionBuildStampTest#stampsOfDifferentLengthsAreStillOrdered 锁定,修复后同一探针返回 false 且 10 条探针断言全部通过。
- F2(注释与实现矛盾):AppDatabase 的 IntegrityRecoveringOpenHelperFactory 与 quarantine() 注释称「不可读的数据库文件被保全而非删除、原文件留在磁盘上」,但实现会清理 -wal/-shm/-journal,且 renameTo 失败时删除主库文件。注释改为如实描述(主库改名保全 + 边车文件清理 + 无法改名时删除),行为零改动。

验证:bash ./gradlew :app:compile{Leanback,Mobile}Arm64_v8aDebugJavaWithJavac :app:compile{Leanback,Mobile}Arm64_v8aDebugAndroidTestJavaWithJavac :app:test{Leanback,Mobile}Arm64_v8aDebugUnitTest => BUILD SUCCESSFUL in 7m 8s;leanback 4191 tests / 0 failures / 0 errors / 2 skipped,mobile 5006 / 0 / 0 / 2(相对 C58 基线 4172/4987 各 +19 = C59 +12、C60 +4、合并带入的 PlaybackOwnershipSourceTest +3);bash scripts/check_ui_tokens.sh => UI_TOKEN_STATUS PASS,violations=1 与基线一致(零新增)。

未使用真机:本轮对生产代码的改动为 1 处判定分支 + 2 处注释,不改变正常升级方向与数据库打开/迁移路径,被复评的 C59/C60 已由用户在同一机位(192.168.50.3:5555,Android 9)按四种场景实机验收。

Verification: 合并 origin/beta 00ad80114(0 冲突,MERGE_HEAD=beta tip,双父合并提交);零复活行级严格判据=0(407 个单亲回退提交 / 53889 删除行 ∩ dev1 新增行 432 行 = 56 行交集,全部存在于 beta tip);零丢失=beta tip 5025 文件逐个 blob 比对,缺失 0、新增仅 dev1 自己的 5 个新文件;复评 2 轮,第 1 轮发现 F1(AppVersion.isNewer 跨长度时间戳误判为更新,负对照实测 isNewer(14位,更早的12位)=true)与 F2(AppDatabase 注释与实现矛盾)并修复,第 2 轮复审通过;双 flavor Java 编译 + 双 flavor AndroidTest 编译 + 双 flavor 全量 JVM 套件 BUILD SUCCESSFUL(leanback 4191/0/0、mobile 5006/0/0,相对 C58 基线 4172/4987 各 +19,可逐项解释:C59 +12、C60 +4、合并带入 beta 的 PlaybackOwnershipSourceTest +3);UI token 门禁 PASS(violations=1 与基线一致,零新增)

Task-Guard: C61-beta-merge-review-dev1-20261011
2026-10-11 14:00:09 +08:00
Silent1566
56372b7dba fix(db): Room 数据完整性校验失败不再导致启动崩溃循环,改为保全坏库后重建
同一用户反馈(Android 9 盒子装完即闪退)背后还有第二个独立缺陷:两个 APK
声明相同 versionCode 但数据库 schema 不同时,Room 会在**打开数据库时**抛
IllegalStateException: Room cannot verify the data integrity,崩溃点为
RoomConnectionManager.checkIdentity -> supportOpenHelperCallback.onOpen。
因为发生在打开期,Application/Activity 调用点无法捕获,实测每次启动必然崩溃,
与盒子日志反复出现的 E/AndroidRuntime + Force finishing HomeActivity + has died 一致。
实测本次 stable(edf04f9) 数据库 VERSION=45、beta(841a570) VERSION=48,
而两者 versionCode 同为 560,正是该失败的触发条件。

修复:经 Room.databaseBuilder().openHelperFactory() 接入
IntegrityRecoveringOpenHelperFactory,在打开期只针对 Room 的 identity 失败介入——
把不可读的库文件改名保全为 tv.incompatible-<时间戳>(wal/shm/journal 一并清理,
隔离副本最多 2 份),再用全新 helper 重建库;重试只允许一次。
非 identity 的打开失败原样抛出,不改变既有行为(已用随机字节损坏库做负对照)。

Verification: JVM focused test: ./gradlew :app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.db.AppDatabaseIntegrityRecoverySourceTest => BUILD SUCCESSFUL, 4 tests / 0 failures / 0 errors / 0 skipped. Device verification on Android 9 (192.168.50.3:5555, sdk=28) after 'bash scripts/build_arm64_debug_install.sh --flavor leanback --abi arm64-v8a --serial 192.168.50.3:5555' (overwrite install, same debug signature): (1) fresh database => FATAL=0, boot OK; (2) same versionCode with mismatching identity_hash, which crashed with FATAL IllegalStateException before the change => FATAL=0, boot OK, 'integrity check failed, rebuilding tv' logged, broken file preserved as tv.incompatible-20261011130235/132735 and it still contains the pre-recovery Keep row; (3) v45 database with user data migrating to the new build => FATAL=0, guard NOT triggered, all rows preserved (Keep 2 / History 60 / Config 1 / Site 1 / Track 1 / Device 1 / TmdbSeasonProgress 1 / PlaybackDeleteTombstone 1); (4) negative control with a non-identity corrupt database (random bytes) => handled by androidx.sqlite itself ('Corruption reported by sqlite ... deleting the database file'), app booted, guard did NOT intervene (recovery log count 0, no incompatible file), proving the guard stays limited to Room's identity failure.

Task-Guard: C60
2026-10-11 13:30:41 +08:00
Silent1566
d8c9bdc650 fix(update): 只有严格更新的构建才提示升级,切断 stable/beta 互相覆盖安装死循环
用户反馈 Android 9 盒子装完即闪退并反复下载 update.apk 覆盖安装。核实日志确认
targetSdk 本来就是 28;日志里的 FragmentManager$FragmentLifecycleCallbacks /
ValueAnimator$DurationScaleChangeListener CNFE 来自 me.jessyan.autosize 的可选探测,
被记录后跳过(同一镜像 leanback 包每次启动都有这 16 行且正常启动),
androidx.window.extensions 在清单中 required=false,均非崩溃原因。

真实死循环根因:Update.hasUpdate() 用 code != VERSION_CODE || !isCurrent(name) 判定,
把"不同"当成"更新"。本次 stable(v5.6.0-202609221328) 与 beta(v5.6.0-beta-202610091755)
清单 versionCode 同为 560,而 getPreferredUpdate() 优先选 stable,于是 beta 装机时被推荐
安装更旧的 stable 包,装完又反过来推荐 beta,两个渠道无限互相覆盖。

改为仅严格更新才算更新:更高 versionCode 才算更新,更低 versionCode 永不当作更新,
同 versionCode 时按发布标签尾部的构建时间戳(yyyyMMddHHmm[ss])判新旧,相同或缺少可比
时间戳时不更新(缺时间戳沿用历史语义,以免本地/非标构建失去升级能力)。

Verification: JVM focused unit tests: ./gradlew :app:testLeanbackArm64_v8aDebugUnitTest --tests AppVersionBuildStampTest --tests UpdateOrderingTest --tests UpdateChannelTest --tests UpdaterFutureTest => BUILD SUCCESSFUL, 21 tests / 0 failures / 0 errors / 0 skipped. Regression locked with the real channel manifest literals v5.6.0-202609221328 (stable) vs v5.6.0-beta-202610091755 (beta): an older manifest with the same versionCode is no longer reported as an update, a newer one still is. Root cause evidence: both channel manifests carry code=560 while their APKs ship different Room VERSION (45 vs 48), so the previous 'different means newer' rule made the two channels overwrite each other in a loop.

Task-Guard: C59
2026-10-11 13:07:31 +08:00
Silent1566
00ad80114f
Merge pull request #435 from Silent1566/dev2
merge: dev2 合并 beta 最新代码(PR#434 主题焦点环族)并复评已提交未推送的「退出播放页必定停播」修复
2026-10-11 12:21:34 +08:00
Silent1566
2275a50e71 docs(c58): 记录 dev2 交付坐标(合并提交 8f20fab65a / recovery tag / beta tip 3148f030df)
Verification: 文档坐标补记:合并提交 8f20fab65a(双父 c27f34b950 + 3148f030df)、阶段二 recovery tag、beta tip 3148f030df 已复核未再前进;本轮无生产代码改动,无需重新构建

Task-Guard: C58-beta-merge-dev2-coordinates
2026-10-11 11:58:15 +08:00
Silent1566
8f20fab65a merge: 合并 origin/beta 最新代码(PR#434 dev1 主题焦点环族 11 提交)并复评 dev2 已提交未推送的「退出播放页必定停播」修复
Verification: 以新 beta tip 重新合入:git merge --no-commit --no-ff origin/beta 0 冲突(MERGE_HEAD=3148f030df),索引树 c681b54c == git merge-tree --write-tree 自动合并结果树;净差异仅 dev2 自身 3 路径、--diff-filter=D 为空;零复活:47 条 beta 真移除路径在合并结果树命中 0、66 条与净差异交集 0、关键词命中 0;dev2 两改动文件 blob 逐字节未变;双 flavor 编译 4/4 BUILD SUCCESSFUL;全量 JVM 套件 leanback 4174/8 失败/7 类、mobile 4989/7 失败/6 类,失败类集合与文档基线同族(0 新增失败);PlaybackOwnershipSourceTest 双 flavor 18/18 通过(含两条新增契约用例)

Task-Guard: C58-beta-merge-dev2-beta434
2026-10-11 11:57:39 +08:00
Silent1566
c27f34b950 docs(c58): 复评 dev2 已提交未推送提交(退出播放页必定停播)并确认无需合并,双 flavor 全量验证通过
Verification: 本轮无需合并(origin/beta tip fb4fd7d99c 即 dev2 HEAD 97c7ae68ab 的父提交,git merge-base --is-ancestor origin/beta dev2 EXIT=0);双 flavor 编译 4/4 BUILD SUCCESSFUL;双 flavor 全量 JVM 套件 leanback 4150/8 失败、mobile 4985/7 失败,失败类集合与 C57 文档基线逐类一致(0 新增失败,+2 例为本次新增契约测试);PlaybackOwnershipSourceTest 双 flavor 18/18 通过(含两条新增用例);零复活:66 条 beta 移除路径与本次 2 个 PR 路径交集 0、关键词命中 0、diff-filter=D 为空;git diff --check 退出码 0;推送为快进 34a93e243f..97c7ae68ab

Task-Guard: C58-beta-merge-review-dev2
2026-10-11 11:48:16 +08:00
Silent1566
e0c067cba7 merge: 合并 beta 最新代码并复评 dev4 屏显对比度改动
Verification: origin/beta=fb4fd7d99ca1547ea624f3d5f1b7f3cd81b880a5 unchanged on final fetch; merge-tree equals index tree b52c5aedfbb06824fa36f8d920a59e646e170c30; zero conflicts; net diff app/docs only; CustomCsp theme fix and regression tests; leanback/mobile focused tests; dual flavor Java and AndroidTest Java compilation; diff check; Gradle stop and clean successful

Task-Guard: beta-sync-review-dev4-20261011
2026-10-11 11:39:32 +08:00
Silent1566
3148f030df
Merge pull request #434 from Silent1566/dev1
merge(dev1→beta): 合并 beta 最新代码(PR#432 电池块 / PR#433 加载圈族)并复评 dev1 全部已提交未推送的主题改动
2026-10-11 11:36:50 +08:00
Silent1566
5ad9025f93 docs(c58): 记录 dev1 合并评审交付坐标(合并提交 2ee22ce21 双父 / recovery tag / PR #434)
回填 docs/C58-beta-merge-review-dev1-20261011.md 的「交付坐标」与「闭环记录」:
- 合并提交 2ee22ce21655791e87164468c3c94d4db761601c,双父(649275b76 合并前 dev1 + fb4fd7d99 beta tip)
- recovery tag recovery/C58-beta-merge-review-dev1-20261011/20261011112617-2ee22ce21655
- 推送 913ae81d1..2ee22ce21,origin/dev1 == 本地 HEAD
- PR #434 已创建(base beta / head dev1,只创建未合并):state=OPEN、mergedAt=null、mergeable=MERGEABLE、changedFiles=83
- PR 文件集与 git diff --name-only origin/beta HEAD 逐项一致(83/83)
- 提交后严格复活行数 0;MERGE_HEAD 已清除;工作区干净

Verification: 文档回填:交付坐标(合并提交 2ee22ce216 双父 / recovery tag / 推送结果 / PR #434)+ 闭环记录(beta tip 未前进复核、双父结构验证 git rev-list --parents -n1 = 2ee22ce21 649275b76 fb4fd7d99、PR state=OPEN mergedAt=null mergeable=MERGEABLE changedFiles=83、PR 文件集与 git diff --name-only origin/beta HEAD 逐项一致 83/83);本轮为 docs-only 改动,无代码变化

Task-Guard: C58-beta-merge-review-dev1-20261011-coords
2026-10-11 11:27:48 +08:00
Silent1566
2ee22ce216 merge: 合并 origin/beta 最新代码(PR#432/#433:mobile 电池块 + 加载圈族修复)并复评 dev1 全部已提交未推送的主题改动
合并:origin/beta tip fb4fd7d99(13 个提交,含 PR#432 dev4 播放器控制栏电池块、PR#433 dev2 加载圈族 4 个 fix 与 OSD 重缓冲计数修复),0 冲突。合并结果相对 beta tip 净差异 82 路径,全部来自 dev1 自身(TV 焦点环统一 + 播放页单一高亮色)。

零复活三层证据:beta 侧 13 个提交无任何删除/回退(--diff-filter=DR 为空);对 beta 历史上 be1b02e06「revert: remove dynamic theme color system」的 2388 条删除行与 dev1 新增行求交(31 行通用脚手架)后逐行核对是否在 beta tip 任何文件中都不存在,严格复活行数 0;关键移除目标(assets/themes、mobile 主题对话框、主题测试)在合并结果中均不存在。注意 5682f2b05「剔除 PR #353」不在 beta 历史(仅 remove-pr353-theme-changes 分支),同样检查复活行数 0。

零丢失:beta 侧 15 个变更文件中 13 个完整保留,2 个自动合并点(TmdbDetailActivity.java / VideoActivityLayoutTest.java)逐 hunk 复核为 dev1 改动与 beta 内容共存,无 beta 内容丢失。唯一删除 selector_cache_button_focus.xml 是 dev1 自己的主题环改造(合并后全仓库零悬空引用)。

复评(3 轮)dev1 的 11 个未推送提交与 82 路径净差异,修复 3 类真实缺陷:
- F1 错别字「深箭玻璃」应为「深靛玻璃」,8 处(ThemeTokens/ThemeResolver/attrs/webhtv_tokens/colors/values-night tokens/leanback styles/selector_control_sheet_button),与仓库既有 13 个文件的「深靛」用词统一。
- F2 attrs.xml 与 webhtv_attrs.xml 的注释声称环色经「视频亮场景 + 固定玻璃两类极端背景夹取」,与 ThemeResolver.PLAYER_RING_BACKDROPS 的实际实现(仅 3 档固定深玻璃、注释明确写纯白视频刻意不在约束里)互相矛盾,2 处,已改写为与实现一致。
- F3 TmdbDetailActivity 悬空 javadoc:focusStroke() 的文档被新方法 focusRingWidthPx() 插入后成为孤立注释,已把文档移回 focusStroke() 正上方。

观察项(按 AGENTS.md §2 只报告不擅自扩大范围):TmdbPersonActivity 仍写死 FOCUS_STROKE_DP=3(宽度未接线 token)、EpisodeDetailDialog 同类悬空 javadoc;二者与 beta tip 逐字节相同,不在本轮净差异内,属 beta 侧既存状态。

Verification: 双flavor Java + 双flavor AndroidTest Java 编译 BUILD SUCCESSFUL;双flavor 全量 JVM 单测 leanback 4172 tests/0 failures、mobile 4987 tests/0 failures(与修复前逐项一致,增量相对 C56 基线 +26/+7 可解释);UI_TOKEN_STATUS PASS(violations=1 零新增、contrast failures=0);零复活严格判据(beta 回退提交 be1b02e06 删除行 ∩ dev1 新增行 31 行逐行核对,复活行数=0);零丢失(beta 侧 15 个变更文件全部保留,2 个自动合并点逐 hunk 复核为共存);git diff --cached --check 退出码 0、冲突标记 0

Task-Guard: C58-beta-merge-review-dev1-20261011
2026-10-11 11:26:17 +08:00
Silent1566
649275b762 fix(theme): 播放页只留一种高亮色(芯片宿主分层修正 + 深色表视频层环取近白)
Verification: testLeanback: TvFocusRingContractTest(17 条)+NativeEnhancedPlaybackStyleFocusTest 通过;testMobile: VideoActivityLayoutTest 通过;com.fongmi.android.tv.theme.* 通过(含 51 色 XML/frozen 色板一致性);scripts/check_ui_tokens.sh PASS(violations=1 基线, contrast failures=0);Robolectric 探针证明玻璃覆盖层:对话框子树 ?attr/tvFocusRing=#FF447BF5、页面内容区=#FF0B57D0、对话框内芯片栅格化描边=#FF447BF5;dev1 实机(深色表, 覆盖安装)数组分段芯片焦点环=#F5F7FF(旧 #7695C5 像素 0)、选集芯片=#F5F7FF、当前分段=#2CC56F、画面框=#F5F7FF

Task-Guard: video-playback-ring-unify
2026-10-11 10:50:34 +08:00
Silent1566
97c7ae68ab fix(playback): 退出播放页必定停播,堵住「退回详情页还有声音/通知栏仍显示播放中」
- stopPlayback(): 服务在而本页非归属方时改由服务侧 suspend() 停播并撤掉前台通知。旧实现只走
  mController.stop():控制器未连上时整次调用是空操作,播放器 IDLE(取流中退出)时会被会话
  stop 直接忽略,且这条路径从不撤前台通知。
- startPlayer(): 已决定退出(返回/通知栏停止)的播放页拒绝再次起播,避免迟到的换源/取流链路
  在服务里重新播放并挂上前台通知。
- 新增两条源码契约测试锁定上述语义。

Verification: mobile arm64_v8a debug 编译通过(compileMobileArm64_v8aDebugJavaWithJavac);:app:testMobileArm64_v8aDebugUnitTest --tests PlaybackOwnershipSourceTest 全类通过(含新增 exitingThePlayerPageAlwaysStopsThroughTheService / anExitingPlayerPageNeverStartsPlaybackAgain);ReaderPlaybackRoutingSourceTest#readerResultNeverFallsThroughToVideoPipeline 通过。ReaderPlaybackRoutingSourceTest 的两处 reader.html 契约失败与 PlayerPlaybackRegressionSourceTest 的 CRLF 多行字面量断言均为改动前既有失败(本机工作区为 CRLF 检出),与本次改动无关。

Task-Guard: EXIT-STOP-01
2026-10-11 10:06:39 +08:00
Silent1566
6be5c5ee40 feat(theme): 默认配色向上游对齐(TV 默认深色 + 白色焦点环 + 白色加载指示器)
用户要求:「默认主题配色靠近上游 Silent1566 分支,比如默认选中边框是白色、播放器加载中
效果是白色等,手机和电视版都注意一下」;随后补充:「电视版应该默认深色更好吧?」

上游基线(clone Silent1566 实测):TV 主题是 Theme.Material3.Dark.NoActionBar(强制深色、
windowBackground=#000000、colorPrimary=#FFFFFF),焦点环与播放器加载指示器都是 @color/white。
上游能用白环正因为它是深色底(21:1);本仓库 TV 是 DayNight 且默认落浅色表,
白环对 #F8FAFD 只有 1.05:1,会直接消失并被 ThemeContrast 的 focus/surface>=3:1 门拒绝。

改动:
- ThemeController.applyNightModeToApp():follow-system 分支按 flavour 分流 —— leanback 默认
  MODE_NIGHT_YES(与上游一致:电视多在暗环境观看,浅色亮底夜间刺眼;深色底上白环 17-18:1
  才成立),mobile 保持 MODE_NIGHT_FOLLOW_SYSTEM。显式浅色/深色仍然优先。
- values-night/webhtv_tokens.xml + ThemeTokens.dark():webhtv_color_focus -> #F5F7FF(近白)。
  不用纯白是因为 ThemeBinder 按「颜色->语义角色」精确匹配,而 webhtv_on_wallpaper 两张表
  恒为 #FFFFFF;焦点若取纯白会被 ThemeColorIndex 映射到 FOCUS,用户切主题时壁纸白字会被
  改写成焦点色(ThemeBaseWiringTest 实测抓出 replacementFor(#FFFFFF, light) 由 null 变 #0B57D0)。
  #F5F7FF 视觉上与纯白无异,对深色 surface 仍 17.29:1,且不与任何 dark 角色同值。
- {leanback,mobile}/res/layout/view_progress.xml:indicatorColor -> @color/white(与上游一致,
  两处都叠在视频上)。
- 顺带修掉本轮暴露的连带缺陷:追更页 primary/secondary 按钮的 backgroundTint 在
  focused/pressed 时取 following_button_focus(=webhtv_color_focus),而文本写死白色 ——
  浅色表下凑巧可读(6.39:1)掩盖了深色表下的 1.72:1(TV 默认深色后必然显形)。
  文本改为配对 on-色(webhtv_color_on_primary):浅色 6.39:1 / 深色 7.50:1。

新增契约测试(ThemeControllerContractTest 11/11):
- tvDefaultsToDarkWhileMobileKeepsFollowingTheSystem
- darkFocusRingIsNearWhiteButNeverPureWhite(防 binder 碰撞回归)
- followingButtonTextPairsWithItsFocusFill

验证:
- ThemeControllerContractTest 11/11
- :app:testLeanbackArm64_v8aDebugUnitTest 4169 tests / 0 failures
- :app:testMobileArm64_v8aDebugUnitTest 4984 tests / 0 failures
- scripts/check_ui_tokens.sh:violations=1(=基线)、hex_colors=0、contrast failures=0
- dev1 实机(覆盖安装,系统 cmd uimode night no 即白天):焦点环实测 #F5F7FF = 45484px、
  浅色表 #0B57D0 = 0px,确认 TV 在白天也默认走深色表

Verification: TV 默认深色(leanback follow-system -> MODE_NIGHT_YES);深色表 focus -> #F5F7FF(近白、对 surface 17.29:1、避开 binder 纯白碰撞);两版播放器加载指示器 -> @color/white;追更页按钮文本改配对 on-色(深色表 1.72:1 -> 7.50:1);新增 3 条契约测试;leanback 4169 + mobile 4984 tests 0 failures;check_ui_tokens violations=1(=基线);dev1 实机白天焦点环 #F5F7FF 45484px、浅色环 0px

Task-Guard: upstream-default-palette-align

Verification: TV 默认深色:ThemeController.applyNightModeToApp 的 follow-system 分支按 flavour 分流(leanback→MODE_NIGHT_YES,mobile→FOLLOW_SYSTEM),dev1 实机在系统 night=no(白天)下焦点环实测 #F5F7FF=45484px、浅色表 #0B57D0=0px;深色表 focus→#F5F7FF(近白,对 surface 17.29:1,且避开与 webhtv_on_wallpaper 纯白碰撞导致的 binder 误改写);两版 view_progress indicatorColor→@color/white;追更页两个文本 selector 由写死白改为 webhtv_color_on_primary(深色表 1.72:1→7.50:1);新增 ThemeControllerContractTest 3 条契约(11/11);leanback 4169 + mobile 4984 tests 0 failures;check_ui_tokens violations=1(=基线) hex_colors=0

Task-Guard: upstream-default-palette-align
2026-10-11 09:32:12 +08:00
Silent1566
fec5af7aa5 test(tv): 锁定屏显入口对比度链路
Verification: 用户截图链路已核对为 PlayerOsdDialog/adapter_player_osd;PlayerDisplaySettingSyncTest 7/7;leanback Java 编译与最终 Debug APK 构建 BUILD SUCCESSFUL;5561 adb install -r 成功且屏显弹窗源码契约与焦点节点复核通过;旧 display_option 误改已撤销;git diff --check 通过;Gradle、build 输出与临时资源已清理

Task-Guard: TV-DISPLAY-DIALOG-CONTRAST-20261011
2026-10-11 09:28:18 +08:00
Silent1566
bd78d7b528 fix(tv): 全面修复设置列表与焦点控件对比度
Verification: PlayerSettingsContrastTest 5/5;leanback theme/contrast/focus contracts BUILD SUCCESSFUL;mobile DialogGlassChipStyleTest 与 AdRuleManageDialogLayoutTest BUILD SUCCESSFUL;leanback/mobile Java compile BUILD SUCCESSFUL;最终 leanback Debug assemble BUILD SUCCESSFUL;5561 adb install -r 成功,屏显设置与播放器按钮截图实测文字/焦点/图标可读,核心对比度 10.48:1、7.93:1、7.04:1;git diff --check 通过;既存 UI token strict 唯一违规为未改动 item_following.xml;构建与临时资源已清理

Task-Guard: TV-PLAYER-SETTINGS-CONTRAST-20261010
2026-10-11 00:52:08 +08:00
Silent1566
8ba33b11fc revert: 全屏播放画面不加焦点环(用户纠正:控制栏需要,整个播放界面不需要)
用户纠正:「全屏播放器内部不需要选中效果呀」「控制栏需要但是怎么整个播放界面套了一个?」

上一提交 0209015d6 把内缩焦点环套在整个全屏播放界面上,属于对「看不出选中效果」
的过度解读。实际需要焦点环的是控制栏/OSD 按钮(那些本就有且已统一),
而全屏画面是沉浸观看态、不是可选控件,加环反而干扰观感。

本次完整 revert 0209015d6:
- VideoActivity.enterFullscreen() 恢复 mBinding.video.setForeground(null)
- TmdbDetailActivity.updatePlayerPanelFocus() 全屏/PiP 分支恢复清零描边后返回
- 同步移除同批次新增的两条契约测试(避免它们反过来要求错误行为)
- 4 个源文件与 7948c8e97 逐字节一致(git diff --quiet 验证)

分层结论(已写入 docs §16):
- 全屏播放画面:不需要焦点环
- 控制栏/OSD 按钮:需要(§14 已统一宽度 + 主题派生色)
- 内嵌(非全屏)播放面板:需要(§13 已对齐卡片圆角)

验证:TvFocusRingContractTest + TmdbDetailChipFillTest 通过;leanback 4166 + mobile 4981
tests 0 failures;check_ui_tokens violations=1(=基线);dev1 实机全屏播放环色像素 = 0
(确认画面无环),控制栏环不受影响

Task-Guard: revert-fullscreen-player-ring

Verification: git revert 0209015d6 完整回退:VideoActivity.enterFullscreen 恢复 setForeground(null)、TmdbDetailActivity 全屏/PiP 分支恢复清零描边;4 个源文件与 7948c8e97 逐字节一致(git diff --quiet 验证);新增两条契约测试已随之移除;TvFocusRingContractTest + TmdbDetailChipFillTest 通过;leanback 4166 + mobile 4981 tests 0 failures;check_ui_tokens violations=1(=基线);dev1 实机全屏播放 #0B57D0 像素 = 0(确认画面无环),控制栏 selector_video_item 环仍为 token 宽度 + tvPlayerRing 主题色

Task-Guard: revert-fullscreen-player-ring
2026-10-10 23:44:12 +08:00
Silent1566
0209015d62 fix(theme): 全屏播放不再失去焦点环,改为画面内侧内缩环
用户实机报告(附大窗形态播放截图):「这里没有选中效果,或者说看不出来」。

根因(像素级证据):用户截图 817x483 中播放面板四边完全没有描边色——边界从黑直接
过渡到紫灰壁纸(仅 1px #232228 抗锯齿),候选环色(#447BF5/#7695C5/#A8C7FA/白)
全部 0 像素,面板四角为直角。排查确认两个全屏入口都在无条件移除焦点环,而宿主在
这两种形态下仍然 focusable:
- VideoActivity.enterFullscreen(): mBinding.video.setForeground(null)
  全屏后 @id/video 仍 focused="true"(uiautomator dump 实测),环却被移除;
- TmdbDetailActivity.updatePlayerPanelFocus(): inlineFullscreen || inlinePiPLayout
  分支 setStrokeColor(0)+setStrokeWidth(0) 后 return,面板仍 focusable=true。
即「可以聚焦但零视觉反馈」。

修法(方案 A):两个入口都改为在画面内侧画一圈内缩焦点环,用 InsetDrawable 把描边
推离屏幕物理边缘,避免全屏时被切掉一半、也不侵入画面中央:
- 宽度取 @dimen/webhtv_focus_ring_width(全 TV 唯一来源)
- 颜色取 ThemeController.focusRingColor()(= ?attr/tvPlayerRing 同一来源,视频层主题派生色)
- 内缩 12dp / 圆角 8dp
新增 VideoActivity.fullscreenVideoRing() 与 TmdbDetailActivity.insetFocusRing()。

新增防回归契约:
- TvFocusRingContractTest.fullscreenPlayerPathsKeepAnInsetFocusRing(断言两个入口不得再
  用 setForeground(null)/清零分支移除环,且新环必须走 token 宽度 + 主题色 + InsetDrawable)
- TmdbDetailChipFillTest.fullscreenPlayerPanelDrawsAnInsetThemeFocusRing(栅格化全屏面板:
  焦点态必须画出内缩主题环、非焦点态无环、环不得触及屏幕物理边缘)

验证:
- TvFocusRingContractTest 19/19;TmdbDetailChipFillTest 3/3
- :app:testLeanbackArm64_v8aDebugUnitTest 4168 tests / 0 failures
- :app:testMobileArm64_v8aDebugUnitTest 4981 tests / 0 failures
- scripts/check_ui_tokens.sh:violations=1(=基线)、hex_drawables=0、contrast failures=0
- dev1 实机(覆盖安装同签名 Debug 包,全屏播放态):环色像素 0 → 17256;环 bbox
  x 24..1895 / y 24..1055(内缩 24px = 12dp);左/上边界剖面 #0B57D0 环带清晰可见

Verification: VideoActivity.enterFullscreen 与 TmdbDetailActivity 全屏/PiP 分支由「移除环」改为「画面内侧内缩主题环」(宽度 token + ThemeController.focusRingColor + InsetDrawable 12dp/8dp);新增 2 条防回归契约;leanback 4168 + mobile 4981 tests 0 failures;check_ui_tokens violations=1(=基线);dev1 实机全屏播放环像素 0→17256、bbox 内缩 24px

Task-Guard: inline-player-panel-focus-ring

Verification: 两个全屏入口由移除焦点环改为画面内侧内缩环:VideoActivity.enterFullscreen 用 fullscreenVideoRing()(InsetDrawable 12dp 内缩 + @dimen/webhtv_focus_ring_width + ThemeController.focusRingColor),TmdbDetailActivity 全屏/PiP 分支用 insetFocusRing();新增 TvFocusRingContractTest.fullscreenPlayerPathsKeepAnInsetFocusRing(19/19)与 TmdbDetailChipFillTest.fullscreenPlayerPanelDrawsAnInsetThemeFocusRing(3/3,栅格化断言焦点态有环/非焦点态无环/环不触物理边缘);leanback 4168 + mobile 4981 tests 0 failures;check_ui_tokens violations=1(=基线);dev1 实机全屏播放环色像素 0→17256、bbox x24..1895 y24..1055(内缩 24px=12dp)、边界剖面 #0B57D0

Task-Guard: inline-player-panel-focus-ring
2026-10-10 23:30:07 +08:00
Silent1566
7948c8e979 fix(theme): 修复对话框主题缺 tv* 属性导致的黑色边框,并收口代码挂环的硬编码宽度
用户实机报告两点:
1. 「现在选中播放器看不出选中的效果,好像是黑色的边框,不应该是统一的选中边框颜色吗?」
2. 「还有个性推荐等卡片的边框粗细没有改小没有统一」

缺陷一(上一轮引入的回归):selector_control_sheet_button(播放器控制面板按钮)的焦点环
从写死半透明白改成 ?attr/tvPlayerRing / ?attr/tvPlayerCurrentRing,但这两个属性当时只在
Theme.Base(= Theme.App)里绑定,而播放器控制面板(ControlDialog,BottomSheet)用的是
Material 默认 bottomSheetDialogTheme、Alert 对话框用的是 Theme.Material3.DayNight.Dialog.Alert
—— 两者都不继承 Theme.WebHTV。属性解析不到时 ?attr/xxx 静默退化为黑色/透明且不崩溃,
这就是「黑色边框」的来源(Robolectric 实测:Theme.WebHTV.Dialog / bottomSheetDialogTheme
下 tvPlayerRing = UNRESOLVED,修复后 = #FF447BF5)。

修法:Theme.WebHTV(基底)/ Theme.WebHTV.Dialog / ThemeOverlay.WebHTV.Dialog 三处都绑定
全部五项 tv* 属性;selector_control_sheet_button 补上缺失的 state_activated 分支
(部分入口用 ArrayAdapter.setActivated 表达「当前生效」,缺该分支就完全看不到选中环)。

缺陷二:前几轮统一的是 drawable 层的环宽,而一批控件是代码挂环(直接 setStrokeWidth /
GradientDrawable.setStroke),全部漏掉:TmdbRecommendationPresenter(FOCUS_WIDTH_DP=3)、
TmdbCardFocusHelper(FOCUS_STROKE_DP=3)、TmdbEpisodeAdapter(3)、TmdbVideoAdapter(2)、
InlineEpisodeAdapter(2)、TmdbDetailActivity(11 处 FOCUS_STROKE_DP=3)。
修法:全部改为从 @dimen/webhtv_focus_ring_width 读像素;TmdbCardFocusHelper.foregroundBorder
参数语义由 dp 改为 px(避免再次隐式写死);TmdbRecommendationPresenter 环色改走
ThemeController.focusRingColor(原来直接取颜色常量,绕过主题覆写通道)。

新增防回归契约:
- ThemeContractTest.everyReferencedTvFocusAttrIsAssignedByATheme:扫描全部 ?attr/tv* 引用,
  断言每个都被至少一个主题赋值,且基底主题自带全部五项(这类回归不崩溃、只有人眼能发现)
- TvFocusRingContractTest.noJavaCodeHardcodesAFocusRingWidth:扫描 9 个 Java 源,
  断言「按焦点分支设描边宽度」的真分支不含 dp 字面量/ *_DP 常量(实测扫到 12 处;
  实施中真的抓出一处漏改:TmdbDetailActivity.applyInlineEpisodeModeButtonState)
- TvFocusRingContractTest.noJavaCodeHardcodesAFocusRingColour

验证:
- ThemeContractTest 全绿;TvFocusRingContractTest 18/18
- :app:testLeanbackArm64_v8aDebugUnitTest 4166 tests / 0 failures
- :app:testMobileArm64_v8aDebugUnitTest 4981 tests / 0 failures
- scripts/check_ui_tokens.sh:violations=1(=基线)、hex_drawables=0、contrast failures=0
- dev1 实机(覆盖安装同签名 Debug 包):选集项焦点环实测 3px #447BF5(此前 3dp 写死色);
  Robolectric 复核 dialog_control#player 的 focus/selected/activated 三态分别为
  #FF447BF5 / #FF00A95A / #FF00A95A

Verification: 三个对话框主题补绑 tv* 五项 + control_sheet_button 补 state_activated 分支(黑框回归消失,实测 dialog_control#player activated 由无描边变为 #FF00A95A);6 个 Java 挂环位置改读 @dimen/webhtv_focus_ring_width(个性化推荐等卡片宽度统一);新增 3 条防回归契约;leanback 4166 + mobile 4981 tests 0 failures;check_ui_tokens violations=1(=基线);dev1 实机选集项环 3px #447BF5

Task-Guard: tv-ring-dialog-attr-recommendation

Verification: Theme.WebHTV/Theme.WebHTV.Dialog/ThemeOverlay.WebHTV.Dialog 三处补绑 tv* 五项(Robolectric 实测 dialog 主题 tvPlayerRing 由 UNRESOLVED→#FF447BF5);selector_control_sheet_button 补 state_activated 分支(dialog_control#player activated 由无描边→#FF00A95A);6 个 Java 代码挂环位置(TmdbRecommendationPresenter/TmdbCardFocusHelper/TmdbEpisodeAdapter/TmdbVideoAdapter/InlineEpisodeAdapter/TmdbDetailActivity 11 处)改读 @dimen/webhtv_focus_ring_width;新增 3 条防回归契约(tv 属性必被主题赋值、Java 不得写死环宽/环色);leanback 4166 + mobile 4981 tests 0 failures;check_ui_tokens violations=1(=基线) hex_drawables=0;dev1 实机选集项焦点环 3px #447BF5

Task-Guard: tv-ring-dialog-attr-recommendation
2026-10-10 21:56:12 +08:00
Silent1566
c3bb6a63d9 fix(theme): 播放页焦点/当前态环统一宽度并统一为受主题控制的派生色
用户实机报告(dev1):播放页按钮的边框太粗,按钮和播放器选中后的边框颜色也不统一。

根因(实机像素实测,非推测):
- selector_video_item(播放页 11 个文本按钮)焦点环写死 3dp,而同一屏的芯片族
  selector_chip(26+14 个 Control 按钮)是 1.5dp → 实机量到 6px vs 3px,「太粗」即 3dp 那族;
- 环色三套并存:芯片族写死 @color/white、文本按钮族 ?attr/tvFocusRing、当前态写死绿
  #2CC56F;且 shape_chip_activated/round_activated 完全没有描边。

关键约束(为什么不能直接换 ?attr/tvFocusRing):播放页控制条直接叠在视频上(背景
transparent,播放态黑色渐变被视频遮住),另一类宿主是固定深靛玻璃。实测白环对纯白视频
1.00:1、浅色表 FOCUS 深蓝 #0B57D0 对玻璃 1.83:1、写死绿对亮视频 2.25:1 —— 没有任何
调色板原色能同时在两类极端背景上达到 3:1。

方案(本轮经用户确认的「方案 A」):
- 新增 ThemeTokens.colorPlayerFocusRing / colorPlayerCurrentRing,由 ThemeResolver 用
  已有的 readableAccent 在 PLAYER_RING_BACKDROPS = {纯白视频 + 三档玻璃} 上夹取到
  MIN_PLAYER_RING_CONTRAST = 3.0(WCAG 2.2 SC 1.4.11 非文本门槛,与 outline/focus 同口径),
  保持用户槽的色相与彩度、只走明度;
- 新增主题属性 ?attr/tvPlayerRing / ?attr/tvPlayerCurrentRing(attrs.xml 声明 + 两个 flavor
  Theme.Base 绑定);
- 「当前播放/当前生效」环色提升为独立用户可编辑槽位 playerCurrent(ThemeProfile.SlotSet /
  ThemeEditor.Slot.PLAYER_CURRENT / Validator / ThemePreviewView 新增「播放器」分组 /
  ThemePresets 同步),满足用户「当前态独立一个设置,主题色彩中没有就添加」;
- 分层固化:视频层 → tvPlayerRing/tvPlayerCurrentRing;应用表面(含与详情页/手机版共用的
  selector_episode_card、selector_tmdb_*)→ tvFocusRing/tvCurrentRing。

派生值(编译期默认,写入 webhtv_tokens.xml):
  light  playerFocus #447BF5  playerCurrent #00A95A
  dark   playerFocus #7695C5  playerCurrent #00A95A

验证:
- TvFocusRingContractTest 16/16(新增播放页环「统一宽度 + 主题色」契约,以及
  playerRingColoursClearNonTextContrastOnVideoAndGlass 的实测对比度断言 +
  「调色板原色不可行」的回归钉子)
- NativeEnhancedPlaybackStyleFocusTest / ThemeContractTest / ThemeEditor* / ThemePresets* 全绿
  (色板资源数 49→51、新增槽位已全链路接线)
- :app:testLeanbackArm64_v8aDebugUnitTest 4163 tests / 0 failures
- :app:testMobileArm64_v8aDebugUnitTest 4980 tests / 0 failures
- scripts/check_ui_tokens.sh:violations=1(=基线)、hex_drawables=0、contrast failures=0
- dev1 实机(覆盖安装同签名 Debug 包)实测:焦点环带 6px(3dp)→3px(1.5dp)、当前态 3px(1.5dp);
  焦点环色 #447BF5、当前态 #00A95A,与派生值逐字节一致

Verification: 9 个播放页环 drawable 统一到 @dimen/webhtv_focus_ring_width 与 tvPlayerRing/tvPlayerCurrentRing;ThemeResolver 按「纯白视频+三档玻璃」夹取 ≥3:1 派生(light #447BF5/#00A95A、dark #7695C5/#00A95A);新增 playerCurrent 用户槽位全链路;TvFocusRingContractTest 16/16、leanback 4163 + mobile 4980 tests 0 failures、check_ui_tokens violations=1(=基线);dev1 实机覆盖安装后环带 6px→3px、环色与派生值逐字节一致

Task-Guard: tv-player-ring-unified

Verification: 9 个播放页环 drawable 统一宽度 token + tvPlayerRing/tvPlayerCurrentRing;ThemeResolver 在「纯白视频 + 三档玻璃」上 readableAccent 夹取 ≥3:1(light #447BF5/#00A95A、dark #7695C5/#00A95A,与 webhtv_tokens.xml 逐字节一致);新增 playerCurrent 用户槽位(Profile/Editor/Validator/PreviewView/Presets 全链路);TvFocusRingContractTest 16/16(含两类极端背景对比度断言与「调色板原色不可行」回归钉子)、NativeEnhancedPlaybackStyleFocusTest/ThemeContractTest/ThemeEditor*/ThemePresets* 全绿;leanback 4163 + mobile 4980 tests 0 failures;check_ui_tokens violations=1(=基线)、hex_drawables=0;dev1 覆盖安装实机:焦点环带 6px(3dp)→3px(1.5dp)、当前态 3px,环色 #447BF5/#00A95A 逐字节吻合

Task-Guard: tv-player-ring-unified
2026-10-10 20:17:47 +08:00
Silent1566
fb4fd7d99c
Merge pull request #433 from Silent1566/dev2
merge: dev2 合并 beta 最新代码(PR#427-#432)并复评加载圈族 6 个已提交未推送提交
2026-10-10 19:45:30 +08:00
Silent1566
34a93e243f docs(c57): 记录 dev2 交付坐标(合并提交 df7f7ff580 / recovery tag / beta tip 819003db8f) 2026-10-10 19:42:26 +08:00
Silent1566
df7f7ff580 merge: 合并 origin/beta 最新代码(PR#427-#432:小说朗读/去广告总时长/搜索下拉对比度/站点注入整页/mobile 电池块)并复评 dev2 加载圈族 6 个已提交未推送提交
Verification: 合并 origin/beta 819003db8f(0 冲突,MERGE_HEAD=beta tip);合并结果树 cd5c370c == git merge-tree --write-tree 自动合并结果树;零复活三层证据通过(严格复活数 0,--diff-filter=D 空,47 条 beta 真移除路径命中 0,检测器自检通过);双 flavor Java 编译 + 双 flavor AndroidTest Java 编译 BUILD SUCCESSFUL;双 flavor 全量 JVM 套件失败集与未触碰基线 29d52ab238 逐类一致(leanback 4148/8 失败 7 类、mobile 4983/7 失败 6 类,均既有 CRLF/Windows renameTo 环境问题,0 新增失败);定向 VideoActivityLayoutTest 155/155、TmdbDetailDirectPlayTransitionSourceTest 4/4、PlayerDisplaySettingSyncTest 7/7、PlaybackOwnershipSourceTest 16/16 全绿;git diff --check 与 --cached --check 退出码 0,冲突标记 0;构建后 gradlew clean 完成

Task-Guard: C57-beta-merge-review-dev2-20261009
2026-10-10 19:41:55 +08:00
Silent1566
819003db8f
Merge pull request #432 from Silent1566/dev4
dev4:合并 beta 评审通过,推送影视原生播放器控制栏电池电量+时间
2026-10-10 17:34:03 +08:00
Silent1566
c8764048c5 docs(c57): 记录 dev4 合并评审交付坐标(beta tip 已在祖先链,复评 2 个已提交未推送的电池提交,零复活三层证据 + mobile 全量验证)
Verification: 双flavor Java/AndroidTest编译通过; mobile全量单测4981项0失败(JBR21.0.10); VideoActivityLayoutTest 155项0失败; 零复活三层证据通过(含可证伪自检); git diff --check通过; 无冲突标记

Task-Guard: C57-beta-merge-review-dev4-20261010
2026-10-10 17:30:54 +08:00
Silent1566
c442601fbd feat(mobile): 影视原生播放器控制栏电池块补齐当前时间(同构沉浸融合 batteryInfo 竖排容器,时间复用 Formatters.TIME)
Verification: testMobileArm64_v8aDebugUnitTest VideoActivityLayoutTest 155 passed 0 failed + 8 affected classes BUILD SUCCESSFUL; assembleMobileArm64_v8aDebug BUILD SUCCESSFUL; ViewControlVodBinding batteryInfo/battery/batteryTime generated; adb install -r emulator-5560 Success; launch no FATAL

Task-Guard: ui-battery-time-20261010
2026-10-10 16:21:00 +08:00
Silent1566
8db36f33a6 feat(mobile): 影视原生播放器控制栏新增电池电量图标(对齐沉浸融合模式,全屏未锁定时显示,BatteryUtil 档位复用)
Verification: testMobileArm64_v8aDebugUnitTest VideoActivityLayoutTest 155 passed 0 failed; assembleMobileArm64_v8aDebug BUILD SUCCESSFUL; ViewControlVodBinding.battery generated; adb install -r emulator-5560 Success; launch no FATAL

Task-Guard: ui-battery-20261010
2026-10-10 15:17:09 +08:00
Silent1566
b8581afc41 fix(theme): 详情页/播放页焦点环圆角对齐宿主,并修正卡片集数名颜色
用户实机报告两点:
1. 播放页、详情页估计都有和首页一样的焦点环圆角问题;
2. 卡片下方「集数名称」一栏字体颜色不对、看不清(手机版和剧名同色)。

根因(与 §12.2 同一几何规则,只是宿主不同):环作为卡片 foreground 时,环外边界圆角
半径 = 声明值 + w/2。§12 只修了首页 selector_vod,同类实例在详情页/播放页还有 5 处仍
写「声明值 = 宿主圆角」,宿主圆角因此露出环外:
- selector_episode_card(8dp 宿主)8dp -> 6dp
- selector_tmdb_media_focus(8dp 宿主)8dp -> 6dp
- selector_tmdb_cast_focus(12dp 宿主)12dp -> 9.5dp
- shape_episode_photo_focused(8dp 宿主)8dp -> 6dp
- shape_video_focused(播放页画面框是直角 FrameLayout)8dp -> 0dp

cache 管理弹窗按钮另有一类更本质的问题:M3 按钮圆角来自
ShapeAppearance.M3.Comp.Button.Small.Container.Shape.Round -> Corner.Full = 50%(52dp 高
按钮 = 26dp 胶囊),而 foreground 环画在整个 view 上、按钮填充被 4dp inset(实测填充
bbox y12..143、环 bbox 0..155),任何固定 dp 都无法对齐。改为 Material 自带描边通道
(app:strokeColor + app:strokeWidth,与 dialog_about/item_following 同一做法),由同一个
ShapeAppearanceModel 同时画填充与描边;环色按既有规则取配对 on-色:tonal 走
focus_ring_secondary(13.18:1 / 7.24:1),text 走 focus_ring_primary(4.91:1)。
selector_cache_button_focus.xml 删除,CacheManagementDialog 两个工厂方法改用
applyFocusRing()。

集数名:adapter_vod 的 @id/remark 由 ?attr/colorOnSurfaceVariant(#44474F)改为
?attr/webhtvColorOnWallpaper(#FFFFFF),与剧名同色、与手机版一致;实机对比度
1.35:1 -> 7.26:1。

验证:
- TvFocusRingContractTest 14/14(新增前景环圆角规则 + 集数名可读性两项契约)
- TvAppSurfaceFocusRingDeviceTest 9/9(新增真实宿主 inflate + 真实环栅格化,四档密度
  hdpi/xhdpi/xxhdpi/xxxhdpi 逐像素判定:旧值 26/34/61/123 溢出,新值 0/2/0/2)
- :app:testLeanbackArm64_v8aDebugUnitTest 4161 tests / 0 failures
- :app:testMobileArm64_v8aDebugUnitTest 4980 tests / 0 failures
- scripts/check_ui_tokens.sh:violations=1(=基线)、hex_drawables=0、contrast failures=0
- dev1 实机(覆盖安装同签名 Debug 包):首页集数名全白 7.26:1;详情页选集卡环外
  「无法用 环色↔背景 混合解释」的像素 0;播放页画面框白环收成方角、黑角不再被切

Verification: 5 个前景环声明圆角改为 宿主圆角−w/2(8dp→6dp、12dp→9.5dp、直角→0dp);cache 按钮改走 MaterialButton stroke 通道并删除 selector_cache_button_focus;adapter_vod remark 改 webhtvColorOnWallpaper(1.35:1→7.26:1);TvFocusRingContractTest 14/14、TvAppSurfaceFocusRingDeviceTest 9/9(真实宿主四档密度 0 溢出)、leanback 4161 + mobile 4980 tests 0 failures、check_ui_tokens violations=1(=基线);dev1 实机三页截图复核通过

Task-Guard: tv-focus-ring-detail-player

Verification: 5 个前景环圆角改为 宿主圆角−w/2(8dp→6dp、12dp→9.5dp、直角→0dp);cache 按钮改走 MaterialButton stroke 通道(删 selector_cache_button_focus,CacheManagementDialog 走 applyFocusRing);adapter_vod remark 改 webhtvColorOnWallpaper 实测 1.35:1→7.26:1;TvFocusRingContractTest 14/14、TvAppSurfaceFocusRingDeviceTest 9/9(真实宿主 inflate + 真实 drawable,四档密度旧值 26/34/61/123 → 新值 0/2/0/2);leanback 4161 + mobile 4980 tests 0 failures;check_ui_tokens violations=1(=基线)、hex_drawables=0;dev1 覆盖安装实机复核:首页集数名 7.26:1、详情页选集卡环外异常像素 0、播放页画面框白环收成方角

Task-Guard: tv-focus-ring-detail-player
2026-10-10 13:56:58 +08:00
Silent1566
540d70b046 fix(theme): 应用表面焦点环改回 1.5dp 细环并让卡片环圆角对齐卡片 8dp 圆角
用户实机报告(dev1 192.168.50.3:5555)两点:颜色统一后 3dp 环比原来「白色那一族」的
1.5dp 粗;卡片焦点环在圆角处比卡片自身圆角大,卡片圆角露出环外一段米色月牙。

根因(实机像素复核 + Robolectric 栅格化扫描,非推测):
- 3dp 来自视频层样板 selector_video_item 的字面量,§9 把它套到应用表面后整族由 1.5dp 变粗;
- shape_vod_focused 是卡片的 foreground,而卡片可见表面另有自己的 8dp 圆角(图片走
  @style/Vod.Grid 上圆角、标题块走 shape_vod_name 下圆角、列表型宿主走 shape_vod_list
  四角)。描边型 <shape> 把描边中心线画在「内缩 w/2、圆角半径仍取声明值」的路径上,
  于是环外边界圆角 = 声明值 + w/2 = 8+1.5 = 9.5dp > 卡片 8dp,沿角落对角线卡片弧反而
  更靠外约 1px,即实机上那条 1–2px 米色月牙(m1.png: 环外边界 x=396.5 处出现 (221,207,194)
  这类卡片表面色像素)。

修复(生产改动仅 2 行):
- webhtv_focus_ring_width:3dp → 1.5dp(= 用户认可的原「白色那一族」宽度);
- shape_vod_focused 声明圆角:8dp → 7dp(宿主 8dp − w/2 = 7.25dp,再留描边按整数像素向上
  取整的余量;7dp 在 density 1.5/2/3/4 下实测溢出均为 0)。6 个 selector_vod 宿主表面都是
  8dp,单环仍同时对齐全部宿主。视频层 selector_video_item 保持 3dp/2dp/1dp 自成档位。

验证:
- TvAppSurfaceFocusRingDeviceTest 8/8(新增:真实 selector_vod 焦点分支与 8dp 卡片表面
  栅格化后卡片 0 像素落在环外;四档密度;变异检验用旧值 8dp+3dp 必须报出溢出)
- TvFocusRingContractTest 12/12(新增:卡片环圆角 ≤ 宿主圆角 − w/2 且不低于理论值 0.5dp)
- :app:testLeanbackArm64_v8aDebugUnitTest 4158 tests / 0 failures
- :app:testMobileArm64_v8aDebugUnitTest 4980 tests / 0 failures
- scripts/check_ui_tokens.sh:violations=1(= 基线)、hex_drawables=0、contrast failures=0
- dev1 实机(scripts/build_arm64_debug_install.sh --flavor leanback 覆盖安装同签名 Debug 包):
  环带 6px → 3px(功能按钮与内容卡片同宽、同色 = 主题 FOCUS 槽 #0B57D0);
  卡片圆角外侧「无法用 环色↔壁纸 混合解释」的像素数 25 → 0(16× 放大图人工比对确认)

Verification: dimen 3dp→1.5dp + shape_vod_focused 圆角 8dp→7dp;栅格化溢出 hdpi/xhdpi/xxhdpi/xxxhdpi = 0/5/0/0(旧值 25/52/114/181,变异检验可抓);TvAppSurfaceFocusRingDeviceTest 8/8、TvFocusRingContractTest 12/12;leanback 4158 + mobile 4980 tests / 0 failures;check_ui_tokens violations=1(=基线);dev1 实机覆盖安装后环带 6px→3px、卡片圆角外侧米色像素 25→0

Task-Guard: tv-focus-ring-app-surface-thin-corner

Verification: dimen 3dp→1.5dp + shape_vod_focused 圆角 8dp→7dp;Robolectric 栅格化卡片圆角溢出 hdpi/xhdpi/xxhdpi/xxxhdpi = 0/5/0/0(旧值 25/52/114/181,变异检验抓得到);TvAppSurfaceFocusRingDeviceTest 8/8、TvFocusRingContractTest 12/12;leanback 4158 + mobile 4980 tests 0 failures;check_ui_tokens violations=1(=基线);dev1 覆盖安装实机:环带 6px→3px(按钮与卡片同宽同色 #0B57D0)、卡片圆角外侧米色像素 25→0

Task-Guard: tv-focus-ring-app-surface-thin-corner
2026-10-10 12:22:04 +08:00
Silent1566
d8f958671a fix(theme): 收口剩余 TV 焦点环宽度并修正选集弹窗不可见焦点
接上一提交(统一 21 个应用表面焦点环)后,全库扫描仍发现 8 个 leanback 焦点态描边
没有引用唯一宽度 token,本轮收口:

- selector_control_sheet_button(2dp)、selector_episode_dialog_item(2dp)、
  selector_episode_dialog_page(3dp 字面量)、selector_danmaku_result_item(2dp)、
  selector_danmaku_search_action(2dp)、shape_video_item_focused(1.5dp)
  → 一律改为 @dimen/webhtv_focus_ring_width
- 两个文件按理由豁免:selector_video_item 是规范样板文件(字面量 3dp 与 token 同值,
  且被 NativeEnhancedPlaybackStyleFocusTest 当基准逐字断言);
  shape_audio_action_icon_focused 是播放页音频按钮的 inset 图标内描边环(40dp/17dp),
  角色与尺寸不同,套 3dp 会把图标糊成一团

顺带修掉扫描时暴露的「焦点完全看不见」缺陷:选集弹窗(固定深色面板 #DD111820)
的环色取自填充色的近似色,与自身填充只有 1.47:1 / 1.32:1,两个 selected 态更是
环与填充同色 = 1.00:1;改白后为 3.12:1 / 3.17:1,达到 WCAG 2.2 SC 1.4.11 的 3:1 门槛,
并与所有其它固定深色宿主的白环规则一致。同时把 state_focused 提到 state_selected
之前——原顺序会让「正在播放 + 获得焦点」的行命中 selected 分支而吞掉焦点环。

新增 TvFocusRingContractTest.noLeanbackFocusRingHardcodesItsWidth:扫描整个
leanback/res/drawable,断言每个焦点态描边都引用唯一 token(白名单式断言无法覆盖
新增文件,这条反过来做)。变格检验:把 selector_episode_dialog_page 改回 2dp 后
该测试与 appSurfaceFocusRingsShareOneWidthTokenAndAThemeColour 两项转红。

未完成:dev1 模拟器整轮离线(ping 100% 丢包 / ARP FAILED),未能做 D-pad 实机复核。

Verification: 剩余 8 个 leanback 焦点态描边收口:6 个改引 @dimen/webhtv_focus_ring_width(2 个豁免各有理由);选集弹窗环色改白,环/填充对比度由 1.00:1/1.32:1/1.47:1 提升到 3.12:1/3.17:1;修正 selected 先于 focused 导致焦点环被吞的分支顺序;新增全库不变量 noLeanbackFocusRingHardcodesItsWidth(变格检验:改回 2dp 后 2 项转红);leanback 4155 + mobile 4980 tests / 0 failures;TvFocusRingContractTest 11/11;TvAppSurfaceFocusRingDeviceTest 6/6;check_ui_tokens hex_drawables=0 violations=1(=基线)

Task-Guard: tv-focus-ring-app-surface-2
2026-10-10 09:53:22 +08:00
Silent1566
d07a8454f7 fix(theme): 统一 TV 端应用表面焦点环并接线到主题色板
用户报告(两张实机截图):同一电视首页上,搜索/历史功能按钮是蓝色边框、
最近观看内容卡片是白色边框,且粗细也不同。

根因:应用表面焦点环分裂成三族,各写各的取值——
shape_item_focused 等写 1.5dp ?attr/colorPrimary(蓝,且 colorPrimary 在 TV 上
同时驱动约 100 个布局的聚焦文字色);shape_vod_focused 等写
1.5dp~2dp @color/white(与调色板无关的常量,改主题纹丝不动);
shape_config_history_item_focused 等又写 2dp。

统一:宽度一律 @dimen/webhtv_focus_ring_width;宿主为调色板表面的 7 族改用
?attr/tvFocusRing,自带主题色填充的 4 族取焦点态填充的配对 on-色。
宿主固定明暗或属视频层的 10 个 drawable 只统一宽度、环色保持与调色板无关——
逐对计算 WCAG 对比度后确定边界(深色玻璃上 ?attr/tvFocusRing 仅 1.91:1,
浅色表深蓝在固定浅色面板上仅 1.6~2.8:1)。

验证:像素级栅格化证据(TvAppSurfaceFocusRingDeviceTest 6/6)、变格检验
(把 shape_vod_focused 改回 1.5dp 白后 3 项断言转红)、静态契约
(TvFocusRingContractTest)、leanback 4154 + mobile 4980 tests 全绿、
UI token 门槛回到基线。

未完成:dev1 模拟器本轮全程离线(ping 100% 丢包 / ARP FAILED),
未能做 D-pad 实机复核;证据改为 Robolectric 真实栅格化逐像素度量。

Verification: drawable 焦点环统一:21 个文件改为 @dimen/webhtv_focus_ring_width + 主题环色/配对 on-色;TvFocusRingContractTest 新增 2 项契约;TvAppSurfaceFocusRingDeviceTest 6/6 像素级栅格化证据(含 day/night 跟随 + 变格检验);leanback 4154 + mobile 4980 tests / 0 failures;check_ui_tokens hex_drawables=0 violations=1(=基线);assembleLeanbackArm64_v8aDebug SUCCESSFUL

Task-Guard: tv-focus-ring-app-surface
2026-10-10 09:24:09 +08:00
Silent1566
b6b8e7a375 docs: 记录加载圈系列在 5557 的实机验证证据与未定证部分
Verification: docs-only: records 5557 device verification evidence - debug leanback arm64 build installed via overwrite (signature SHA-256 identical to local debug keystore, artifact hash d5953c0c matches device base.apk), A/B against the pre-change APK (73c6567a) reproduced the identical ijk-smoke.mp4 timeout/freeze so it is not a regression, sintel-trailer.mp4 plays to the end with no stuck progress node after 3 seeks, 3 rounds of repeated VIEW intents exercising setPlayer(null) keep playing with no stuck spinner, crash buffer empty. Honestly records what was NOT provable on device (IJK rebuffer readout, same-episode replay semantics) and the prefs overwrite observation. No code change; no re-run of already-green tests.

Task-Guard: SWEEP-DEVICE-EVIDENCE-5557-20261009
2026-10-09 20:17:33 +08:00
Silent1566
e6413efd1e
Merge pull request #431 from Silent1566/dev1
fix(csp): 站点注入统一全屏整页(修竖屏按钮被压扁 / 横屏“没有全屏”)+ 合并 beta 最新代码
2026-10-09 19:46:54 +08:00
Silent1566
913ae81d19 docs(c56): 记录 dev1 交付坐标(合并提交 fe4d02e07 / recovery tag / 推送 / PR #431)
补记本任务闭环坐标与闭环记录:合并提交 fe4d02e076d781f5158d791c6aae8e0d216f07fb(两个父:
40ba21ed87 + beta tip 841a5707d5)、
合并结果树与合并前 HEAD 树同为 79182bfdb509d1a53102fa72ea839d79f205ab87、recovery tag
recovery/C56-beta-merge-review-dev1/20261009193053-fe4d02e076d7、origin/dev1 已推送、PR #431
(dev1 -> beta)已创建且未合并;并记录 PR 文件集与本地净差异逐项一致的校验结果。

Verification: 仅文档改动,无代码/构建/运行时变更;git status --porcelain 提交前仅含本文件,
提交后工作区干净;PR #431 state=OPEN、mergedAt=null、mergeable=MERGEABLE、changedFiles=4,
文件集与 git diff --name-only origin/beta HEAD 逐项一致;收尾复核 beta tip 仍为 841a5707d。

Task-Guard: C56-beta-merge-review-dev1-coords

Verification: docs-only 交付坐标闭环: 合并提交 fe4d02e076 两父(40ba21ed8+841a5707d)已校验, recovery tag recovery/C56-beta-merge-review-dev1/20261009193053-fe4d02e076d7, origin/dev1=fe4d02e07 已推送, PR #431 OPEN/mergedAt=null/MERGEABLE/changedFiles=4 且文件集与 git diff --name-only origin/beta HEAD 逐项一致, beta tip 复核仍 841a5707d

Task-Guard: C56-beta-merge-review-dev1-coords
2026-10-09 19:32:37 +08:00
Silent1566
fe4d02e076 merge: 合并 origin/beta 最新代码(PR#430)并复评站点注入整页链路(含已提交未推送的 CSP 修复)
远端 beta tip 841a5707d 的两个父提交(7e51768d8 / 67d930ed6)都已是本分支祖先,
故 beta 侧增量为 0 条内容:git merge --no-ff --no-commit origin/beta 零冲突、零文件变化,
合并结果树与合并前 HEAD 树逐字节相同(79182bfdb),MERGE_HEAD = 841a5707d。
零复活三层证据:严格复活行 0、--diff-filter=D 为空、beta 独有文件 0、关键移除能力关键词 0 命中。

复评对象:净差异 3 路径(CustomCspDialog.java 修改 + LayoutTest 新增 + SITE-INJECT 文档新增)
与 2 个已提交未推送提交(22348293b 竖屏整页、40ba21ed8 横屏整页)。

生产代码无缺陷,本轮未改动一行生产代码(sha256 前后一致)。
测试代码发现 1 个真问题并修复:
- 旧横屏“变异检验”是恒真算式((int)(W*0.76f) 与 Math.round 比较、W-(int)(W*0.76f)>0),
  不调用生产代码、无法转红;且 Robolectric 只装在 leanback 测试变体且默认竖屏,
  第 1 轮“横屏按朝向挑 0.76×0.98”分支在 JVM 层永远不可达——负对照 A 实测:
  回退该实现并用修复前测试文件跑 = 5 例全绿,缺陷可原样复发而不被发现。
- 修法:横屏负对照改为按旧窗口尺寸对同一面板链实测(root 宽<屏宽、高<可用高度),
  并对当前实现断言窗口宽高必须 MATCH_PARENT;新增 @Config(qualifiers=w686dp-h386dp-land)
  的 landscapeOrientationQualifierAlsoFillsTheWholePage()(自带 qualifier 自检),
  锁死真实横屏配置下的“铺满 + 按钮区 40dp 贴底”。负对照 B:同一变异下转红
  (真实横屏下 root 高度必须 MATCH_PARENT expected:<-1> but was:<378>);撤销变异 6/6 全绿。

改动仅测试与文档:CustomCspDialogLayoutTest 5→6 例 + 新增 C56 文档 + 订正 SITE-INJECT 文档
(变异检验口径与用例数、补充恢复 tag)。

Verification: 双 flavor Java 编译 + 双 flavor AndroidTest Java 编译 + 双 flavor 全量 JVM 套件
单次 Gradle 调用 BUILD SUCCESSFUL in 1m24s:leanback 651 suites/4146 tests/0 failure/0 error/2 skipped
(基线 4145,+1 = 新增加用例且可解释),mobile 726/4980/0/0/2(与基线一致)。
UI token 门禁 UI_TOKEN_STATUS PASS(violations=1、contrast min=4.28,与 C50-C55 基线逐项一致)。
git diff --check 退出码 0,冲突标记 0,未使用 git reset(合并状态完整保全)。

Task-Guard: C56-beta-merge-review-dev1

Verification: 合并 origin/beta(841a5707d) 内容零变化且零复活(严格复活行0/D过滤空/beta独有文件0/合并树==合并前HEAD树); 复评净差异3路径+2个已提交未推送提交: 生产代码无缺陷, 测试发现F1(横屏变异检验为恒真算式且真实横屏配置无回归锁)已修复并双向负对照(变异A: 修复前5例全绿->修复后6例转红 expected:<-1> but was:<378>, 撤销变异6/6绿); 生产文件sha256 311c8e09...1eeb前后一致; 双flavor编译+AndroidTest编译+全量JVM套件 BUILD SUCCESSFUL(leanback 651 suites/4146 tests/0 failure/0 error/2 skipped, mobile 726/4980/0/0/2, 差值+1可解释); UI_TOKEN_STATUS PASS(violations=1与基线逐项一致); git diff --check退出0, 冲突标记0

Task-Guard: C56-beta-merge-review-dev1
2026-10-09 19:30:53 +08:00
Silent1566
40ba21ed87 fix(csp): 站点注入横屏也铺满整页,修“没有全屏”
第 1 轮只把竖屏改成整页,横屏仍保留旧的 0.76x0.98 居中比例弹窗。
用户在 1920x1080 横屏设备复测看到的正是这一版:窗口 1459x1058 居中、
root [230,42][1689,1080],左右各空出 230px。

本次两种朝向统一铺满整页,删除 land/屏宽屏高三个参数,不再有任何按屏
比例的手算:窗口 MATCH_PARENT + ADJUST_RESIZE、root 与 Material 弹窗面板链
一并 match_parent、滚动区 height=0/weight=1/maxHeight=0,固定高按钮区
永远 40dp 并贴底,正文左右不贴边由 XML 既有 20dp padding 保证。

测试同步重写:竖屏 5 种比例 + 横屏 3 种比例都断言铺满与按钮 40dp、
窗口参数必须 MATCH_PARENT、短内容同样铺满、极短窗口按钮不被压缩,
并保留变异检验(回退第 1 轮实现后 4/5 失败)。

Verification: 用户复测反馈横屏未全屏已修复. 设备实测(dev1 192.168.50.3:5555 横屏 1920x1080@280): 窗口属性由 (1459x1058) gr=CENTER 变为 fill x fill + sim={adjust=resize}, root 由 [230,42][1689,1080] 变为 [0,42][1920,1080] 铺满整页, 取消/确定 70px=40dp 贴底, 列表 viewport 493px 且不与按钮区重叠; 竖屏(1080x2160@440, 5 条注入)仍整页, 按钮区 110px=40dp, viewport 1238px. JVM: CustomCspDialogLayoutTest 5/5 通过(竖屏5比例+横屏3比例均断言铺满与按钮40dp; 短内容; 极短窗口按钮不压缩; 变异检验回退第1轮实现后 4/5 失败); 全量单测 leanback 4145 项/0 failure/0 error/2 skipped, mobile 4980 项/0 failure/0 error/2 skipped. 设备状态已回收(registry md5 bce0777921bc78ec1991f4d89f1b3d87 一致, wm size/density reset, accelerometer_rotation=1, 应用 force-stop).

Task-Guard: SITE-INJECT-FULLPAGE-20261009
2026-10-09 19:05:57 +08:00
Silent1566
22348293b8 fix(csp): 站点注入竖屏铺满整页,底部按钮区不再被内容压扁
竖屏原本按屏幕比例手算高度(窗口 WRAP_CONTENT + 滚动区 wrap_content +
0.58H 上限 + 无 weight),条目一多就把底部按钮区挤出窗口下沿:设备实测
取消/确定 由 40dp 变 34.9dp、末张卡片操作行只剩 9.1dp。

改为竖屏铺满整页:窗口 MATCH_PARENT + ADJUST_RESIZE、root 与 Material
弹窗面板链一并 match_parent、滚动区 height=0/weight=1/maxHeight=0,
固定高按钮区永远保住自然高度并贴底,列表转为滚动视口。横屏保持
0.76x0.98 比例弹窗行为不变。

尺寸策略抽成静态 applyPageSizing 以便 JVM 测量测试锁定该契约。

Verification: 设备实测(dev1 192.168.50.3:5555, 1080x2160@440 竖屏, 5 条注入): 取消/确定由 34.9dp 恢复 40dp、第3卡操作行由 9.1dp 恢复到滚动视口内; 另测 1080x1920@480 与 1080x1800@440 竖屏按钮区均 40dp、横屏 1920x1080@280 窗口仍 0.76x0.98 且按钮区 40dp、文本模式/编辑面板/空搜索结果页面均铺满且按钮区贴底. JVM: CustomCspDialogLayoutTest 4/4 通过(含变异检验: 回退参数后 3/4 失败); dialog+bean 定向测试通过; 全量单测 leanback 4144 项/0 failure/0 error/2 skipped, mobile 4980 项/0 failure/0 error/2 skipped. 设备状态已回收(registry md5 bce0777921bc78ec1991f4d89f1b3d87 一致, wm size/density/reset, 应用 force-stop).

Task-Guard: SITE-INJECT-FULLPAGE-20261009
2026-10-09 18:43:23 +08:00
Silent1566
839809ee1e docs: 收口加载圈遗漏分支扫荡(4 项修复坐标、族闭合证明、有意契约与残留风险)
Verification: docs-only closure: records the four committed omission fixes (4319403502, 7809ff4952, d7b9439201, f2ccce36c9) with their recovery tags, proves the player-spinner write/clear sites are now closed (single VISIBLE/GONE write per flavor), and records with file:line evidence the deliberately-pinned contracts left unchanged (Exo-only stall watchdog from 60ad0d0969 + PlayerManagerLifecycleSourceTest, C47 seek gate clause, PlaybackOwnershipSourceTest isOwner/isEmpty). No code or build change in this session; no re-run of already-green verification.

Task-Guard: LOADING-SPINNER-OMISSION-SWEEP-20261009
2026-10-09 18:14:08 +08:00
Silent1566
f2ccce36c9 fix(osd): 屏显诊断重缓冲计数按引擎正确分派,IJK 不再恒为 0
PlayerOsdController.getDiagnostics() 的分派条件写成了「是否 MPV」:
  int rebufferCount = player.isMpv() ? player.getRebufferCount() : snapshot.rebufferCount();
而真实前提是「有没有 Exo analytics 快照」(即是否 Exo)。非 Exo 时 snapshot 为
Snapshot.empty(),于是 IJK 落到快照分支,重缓冲次数与总时长恒为 0。

PlayerManager.getRebufferCount()/getRebufferTotalMs() 本身是引擎无关的
(PlaybackBufferingTracker + MPV disc 计数),非 Exo 早有可用取数器,只是 IJK 没走到。
改为按 isExo() 分派:Exo 行为不变,IJK/MPV 读引擎无关追踪器。这是排查工具读数错误而非
播放缺陷——本系列排查「转圈」时曾据该读数给出无效建议,修掉后诊断面板对三种内核都可信。

Verification: :app:compileMobileArm64_v8aDebugJavaWithJavac 成功;:app:testMobileArm64_v8aDebugUnitTest
定向跑 PlayerDisplaySettingSyncTest 7/7(含新增 playerOsdDiagnosticsReadRebufferCountPerEngine)、
VideoActivityLayoutTest 154/154、TmdbDetailActivityLayoutTest 130/130 全绿。新断言对 base 源码必然
变红(base 表达式含 player.isMpv() 而不含 player.isExo())。过程中自查 git diff 发现并修回了新增
用例时误将签名与首行拼接成一行的问题。

Task-Guard: OSD-REBUFFER-ENGINE-BRANCH-20261009

Verification: compileMobileArm64_v8aDebugJavaWithJavac OK; PlayerDisplaySettingSyncTest 7/7 (incl. new playerOsdDiagnosticsReadRebufferCountPerEngine), VideoActivityLayoutTest 154/154, TmdbDetailActivityLayoutTest 130/130 all green; new assertion provably red at base (expression used player.isMpv()); accidental joined-line regression found via diff review and repaired before verification

Task-Guard: OSD-REBUFFER-ENGINE-BRANCH-20261009
2026-10-09 18:11:09 +08:00
Silent1566
d7b9439201 fix(playback): 被作废的取流请求必须释放加载态,消除永久转圈与同集无法再播
修复两处同族遗漏分支(上一次修复 7809ff4952 的延续):

① leanback VideoActivity.setPlayer(null) 早退不释放守卫。
   原写法 `if (result == null || isFinishing() || isDestroyed()) return;` 让三条路径共用一次早退,
   而 result == null 是可达的:SiteViewModel.cancelPlayerContent() 会向 PLAYER LiveData 写 null。
   4 个调用点中 onRefresh 的路径真会漏:cancelPlayerContent() 之后
   `if (mFlagAdapter.getItemCount() == 0) return;` 提前返回、不再重新置位,守卫残留使
   onStateChanged(READY) 的 break 与 hidePlaybackProgressIfStale() 同时为假,圈再无清除路径。
   修法:把 null 视为「请求已作废、不会再有结果回调」,在该分支释放守卫。

② 详情页 inlinePlaybackPending 缺归属判定。applyTmdbResultNow()(TMDB 详情异步装载完成重排剧集)
   与 onResume→refreshSelectionAfterExternalPlayback() 会重设选择面但不自增代际,在途回调因
   isInlinePlaybackRequestCurrent() 为假直接返回,标记再无释放路径 ⇒ 圈永久留存,且
   isSamePendingInlinePlayback() 恒真使同一集无法再次起播。
   修法:新增 inlinePlaybackPendingGeneration 记录置位代际,回调失效分支按归属释放
   (避免旧回调清掉新请求的标记),两处显式作废点改用无条件重载。任务被取消时回调不执行,
   故显式作废点的同步释放仍必要,二者互补。

Verification: 双 flavor Arm64 Debug Java 编译成功;:app:testMobileArm64_v8aDebugUnitTest 定向跑
VideoActivityLayoutTest 154/154、TmdbDetailDirectPlayTransitionSourceTest 4/4、PlaybackOwnershipSourceTest
16/16 全绿(含本任务新增/扩展断言)。新断言对 base 源码必然变红(逐方法体字符串校验:修复前无
独立 null 分支、三个方法与 helper 均不含 releaseInlinePlaybackPending*)。过程中自查 git diff 发现
并修回了首轮批量编辑误删的 `float speed = player().getSpeed();` 与一处空行。

Task-Guard: ABANDONED-REQUEST-LOADING-RELEASE-20261009

Verification: compileLeanback/Mobile Arm64 debug Java OK; VideoActivityLayoutTest 154/154, TmdbDetailDirectPlayTransitionSourceTest 4/4, PlaybackOwnershipSourceTest 16/16 all green; new assertions provably red at base commit via per-method string check; accidental deletion of float speed line and a blank line found via diff review and repaired before verification

Task-Guard: ABANDONED-REQUEST-LOADING-RELEASE-20261009
2026-10-09 18:06:17 +08:00
Silent1566
841a5707d5
Merge pull request #430 from Silent1566/dev1
合并 beta 最新代码并复评缓存改动:补齐「临时文件清理 / 长按一键全清」的调用点级回归锁(C55)
2026-10-09 17:55:55 +08:00
Silent1566
67d930ed63 docs(c55): 记录 dev1 交付坐标(合并提交 447934222b / recovery tag / 推送 / PR #430)
Verification: 坐标回填:合并提交 447934222b88934720b387225d7d561e781108ac(rev-list --parents 实测两个父 92ad7c69d + 7e51768d8,确为 merge commit,第二父 = origin/beta tip 7e51768d881a725754dd68321ab802680ea30e1c);recovery tag recovery/C55-beta-merge-review-dev1/20261009175202-447934222b88(annotated,0s);git push origin dev1 6bb920372..447934222,推送后 origin/dev1 == dev1 == 447934222;gh pr create 返回 https://github.com/Silent1566/webhtv/pull/430,gh pr view 430 实测 state=OPEN mergedAt=null mergeable=MERGEABLE mergeStateStatus=CLEAN base=beta head=dev1 changedFiles=14 additions=1140 deletions=49;gh api pulls/430/files 合计 14 个文件名与 git diff --name-only origin/beta HEAD 逐项一致(diff 无输出);PR 只创建未合并。文档改动为纯 docs(本任务文档交付坐标与闭环记录)。

Task-Guard: C55-beta-merge-review-dev1-coordinates
2026-10-09 17:53:14 +08:00
Silent1566
447934222b merge: 合并 origin/beta 最新代码(PR#429 dev4 搜索下拉对比度修复)并复评缓存临时文件/一键全清调用点回归锁
- 合并 origin/beta tip 7e51768d8(dev4 深色模式搜索分组下拉对比度修复 + PR#429):0 冲突,合并树 0d68f909,
  第二父 7e51768d8。四向结构证据 + 行级严格判据(复活行数 0)证明合并树里每个字节只可能来自 beta tip
  或本分支自身 13 个路径,故远端已移除/回退的内容零复活,beta 增量与 dev1 改动均零丢失。
- 复评 dev1 已提交未推送的缓存改动(13 路径 +776 -49):确认无功能缺陷。
- F1(真问题,已修复):两处缓存缺陷的调用点级回归锁缺失。负对照实测:把 executeCleanup 的
  case TEMP_FILES 调用点改回 TEMP_RETENTION_MS(用户报告的缺陷原形)后缓存包 71/71 仍全绿,
  缺陷可在单测全绿的状态下复发。按仓库既有源码守卫约定新增
  CacheFullCleanupTest.everyCleanupCallSiteUsesTheSharedRule(),锁定「FULL 分派」「六个模块共享保留期
  规则」「调用点不得写窗口字面量」三类不变量,并以两向变异验证会转红(B1 命中 CacheFullCleanupTest.java:206,
  B2 命中 FULL 分派断言)。
- 验证:双 flavor Java/AndroidTest 编译 + 双 flavor 全量 JVM 套件通过(leanback 650/4140、mobile 726/4980,
  failures=0 errors=0,差值逐项可解释);UI token 门禁 PASS(violations=1,与基线逐项一致);
  git diff --check 退出 0、无冲突标记、生产文件 sha256 字节还原。

Verification: 结构四向闭合:git diff 92ad7c69d <合并树> = 仅 beta 的 5 路径(dev1 改动零丢失);git diff origin/beta <合并树> = 仅 dev1 自身 13 路径且 --diff-filter=D 为空(beta 零丢失);git ls-tree 对比 beta 有而合并树缺的文件 = 0。行级严格判据复活行数 0(beta 4330 提交 / 139 移除类单亲提交 / 27862 删除行 vs 540 新增行;43 处表面命中全部为 beta tip 自身存在的脚手架行)。0 冲突,MERGE_HEAD=7e51768d881a725754dd68321ab802680ea30e1c,合并树 0d68f90990fb6d9c3d03c5f523f9ffe22567863c(重置后重做合并复现同一树)。复评 13 路径 +776 -49 确认无功能缺陷;F1 调用点级回归锁缺口已修复:负对照 A(case TEMP_FILES 调用点改回 TEMP_RETENTION_MS)缓存包 suites=14 tests=71 failures=0 证明缺口真实,补 everyCleanupCallSiteUsesTheSharedRule 后 B1 转红(失败点 CacheFullCleanupTest.java:206)、B2(FULL 分派改为 false &&)转红并报 FULL must select the full-clean path,生产文件 sha256sum -c 字节还原 f7540b763c584e1551ba2d7080768998cbfd6ffd3a11e7f16c8d0945063d9a64。6 个目标任务全部实际执行 BUILD SUCCESSFUL in 1m 23s:leanback 650/4140、mobile 726/4980,failures=0 errors=0 skipped=2(差值 +1 / +1本轮 +2beta 的 SearchScopePopupLayoutTest 2->4 例)。UI_TOKEN_STATUS PASS violations=1 与 C50/C52/C53/C54 基线逐项一致。git diff --check 退出 0,冲突标记命中 0,fetch 后 beta 未前进。

Task-Guard: C55-beta-merge-review-dev1
2026-10-09 17:52:02 +08:00
Silent1566
92ad7c69d1 docs(c54): 记录上游 Silent1566 合并交付坐标(合并提交 45bffbb860 / recovery tag / 设备收尾)
上游 webhtv/webhtv Silent1566 的 4 个提交已合并入 dev1,双 flavor 编译与全量单测零新增回归、UI token 零新增违规、mobile/leanback 双形态实机通过;本次仅补记交付坐标并同步功能设计文档,未改动任何代码。

Verification: docs-only closure:写入交付坐标(合并提交 45bffbb860 / recovery tag recovery/C54-upstream-sync-silent1566/20261009170756-45bffbb860dc / 未推送 / 设备装置已还原并覆盖安装 mobile flavor);无代码、构建、测试或运行时行为变化;git diff --check=0

Task-Guard: C54-deliver-coordinates
2026-10-09 17:09:43 +08:00
Silent1566
45bffbb860 merge: 合并上游 webhtv/webhtv Silent1566 缓存临时文件清理修复与长按一键全清
上游 4 个提交(f9f47c24ae/92f1844342/f0da126a2c/814935cee)全部纳入:修复临时文件行显式清理无效(显式请求忽略后台保留期)、补回拆分前语义的长按一键全清(CacheCleanupMode.FULL + 残留扫描,不弹面板、Toast 报结果)、修正缺陷回归锁与结果文案语言路径。
唯一冲突为 CacheManagementDialog import 块:取上游 Setting.wrapLanguage 依赖,保留本地 WebHtvAlertDialogBuilder 主题契约,拒绝带回 MaterialAlertDialogBuilder。
本地改动零丢失;双 flavor 全量单测零失败;UI token 零新增违规;mobile 与 leanback 双形态实机通过(含全清后冷启动)。

Verification: 上游 tip 814935ceea 成为合并提交第二父(MERGE_HEAD 核验);1 个冲突(CacheManagementDialog import 块:取上游 Setting + 保留本地 WebHtvAlertDialogBuilder,未带回 MaterialAlertDialogBuilder)解决后 0 未合并路径、0 冲突标记;零丢失四层证据:上游独占 5 个代码/测试路径与上游 tip 逐字节相同、合并净差 +586/-49/12 路径(=上游 +585/-49 + 本任务文档 1 行)、585 行上游新增逐行在上游 tip 命中(外来内容 0)、本地新增行丢失 0、无路径被删除;双 flavor 编译+androidTest 编译+全量单测 BUILD SUCCESSFUL(2m12s):leanback 650 suites/4139 tests、mobile 726/4977,failures=0 errors=0 skipped=2(较 C53 基线 +8 例/flavor = 上游新增用例);UI token 门禁与基线逐项一致(layouts=385/violations=1 既有 item_following.xml/contrast pairs=38 failures=0 min=4.28,零新增);git diff --check=0;负对照:explicitRequest 退回 MODULE 时 CacheFullCleanupTest 7 例 1 失败(锁有效),仅调用点回退 24h 窗口时缓存包单测仍全绿(调用点级锁缺失,已记录);实机 192.168.50.3:5555(LIO-AN00/Android 9,证书 SHA-256 一致,install -r 覆盖安装、未卸载):mobile 版临时文件行清理『清理完成 释放 3 MB · 删除 1 个文件』且 js/stray 保留、长按不弹面板 Toast『清理完成 释放 43.3 MB · 删除 470 个文件』、cache 23 项/45M→仅余运行中加载器 jar/624K、单击仍开面板、全清后冷启动无 FATAL/ANR 且缓存自动重建;leanback 版同类『释放 2 MB · 删除 1 个文件』『释放 7.4 MB · 删除 162 个文件』、14 项/8.3M→1 项/624K、单击仍开面板、无 FATAL/ANR;journal 4 条 MODULE/FULL COMPLETED 与 UI 文案逐条一致;设备 home_button 测试装置已还原为 0,8,6,1,2,3,4,7 并删除临时 prefs 备份;未推送、未创建 PR、未打正式包

Task-Guard: C54-upstream-sync-silent1566
2026-10-09 17:07:56 +08:00
Silent1566
7809ff4952 fix(detail): 作废内联取址请求时释放其加载标记,消除永久加载圈
现象:详情页内播(沉浸融合/详情直放)偶发加载圈一直转但不影响播放;同一集还会表现为无法再次起播。

根因:playInline() 先置 inlinePlaybackPending=true 再自增代际,而回调里
`inlinePlaybackPending = false;` 写在 isInlinePlaybackRequestCurrent(...) 检查**之后**。
于是凡是「只自增代际、不接替请求」的作废点,回调直接 return,标记再无释放路径:
① updateInlineLoading() 的可见条件首项即该标记 ⇒ 圈永久留在屏上;
② isSamePendingInlinePlayback() 恒真 ⇒ selectInlineEpisode 早退,同一集无法再次起播。
实测该类作废点两处:refreshAndSwitchInlinePlayer()(选其它内核,8993 调用)与
cancelPendingInlinePlayerSwitch()(选当前已生效内核 8998 / 打开外部播放器 9295)。
其余自增点(resetDetailState / cancelPendingInlinePlayback / closeDetailFullscreenPlayer)
均已释放,属置位点的 playInline 本身正常。

修法:两处作废点在自增代际后、投递新请求前同步释放标记并刷新面板。必须在作废点同步
释放而非仅在回调里释放:任务若在运行前被取消,submit 的 lambda 根本不执行,回调式释放
永不触发。切内核自身的缓冲显示由 updateInlineLoading 的引擎条件兜住,不依赖该标记。

Verification: :app:compileMobileArm64_v8aDebugJavaWithJavac 成功;:app:testMobileArm64_v8aDebugUnitTest 定向 TmdbDetailDirectPlayTransitionSourceTest 4/4(含新增断言);同批显式列出 77 个 Tmdb/Inline/PlaybackOwnership 用例类共 610 项,1 项失败经字节取证为既有 CRLF 检出环境问题(断言要求裸 \n,而 leanback VideoActivity.java 为 i/lf w/crlf、裸 LF 0 处;且该断言读的文件本次未改动),与本改动无因果。新断言对修复前源码必然变红(逐方法体字符串校验)。

Task-Guard: INLINE-LOADING-RELEASE-20261009

Verification: compileMobileArm64_v8aDebugJavaWithJavac OK; TmdbDetailDirectPlayTransitionSourceTest 4/4 pass (incl. new cancellingAnInlinePlaybackRequestReleasesItsLoadingFlag); wider 610-test Tmdb/Inline/PlaybackOwnership sweep: 609 pass, 1 failure (TmdbSourceOnlyInteractionTest line 42) proven pre-existing CRLF checkout artifact (bare LF sequence absent, CRLF variant present, file unmodified by this change); new assertion provably red before the fix

Task-Guard: INLINE-LOADING-RELEASE-20261009
2026-10-09 17:07:35 +08:00
Silent1566
7e51768d88
Merge pull request #429 from Silent1566/dev4
dev4:合并 beta 最新代码并复评手机版搜索下拉面板对比度修复
2026-10-09 16:52:48 +08:00
Silent1566
4319403502 fix(tv): 详情未就绪丢弃播放结果时释放加载守卫,消除永久转圈
现象:leanback 播放页偶发加载圈一直转、但不影响播放。

根因:setPlayer(Result) 在守卫持有期间的 6 条退出路径中,!canApplyPlayerResult()
这条早退分支不释放 mPlaybackRequestActive/mPlaybackPlayerStarted。命中后
onStateChanged(STATE_READY) 的 `if (mPlaybackRequestActive && !mPlaybackPlayerStarted) break;`
与 hidePlaybackProgressIfStale() 的同一条件同时被挡下——而这两处是加载圈仅有的清除
路径,于是旧内容继续播放、圈永久留存。与 C42 已修的同族分支同源(commit 3374def641)。

修法:该分支放弃本次结果时一并释放两个守卫,并补注释说明;mobile VideoActivity 没有
这套守卫字段(grep -c = 0),不涉及。范围仅 leanback VideoActivity 与该契约的源级用例。

Verification: :app:compileLeanbackArm64_v8aDebugJavaWithJavac 成功;:app:testMobileArm64_v8aDebugUnitTest 定向跑 VideoActivityLayoutTest 154/154、PlaybackOwnershipSourceTest 16/16 全绿(含本任务新增断言)。同批 ReaderPlaybackRoutingSourceTest 的 2 项失败经取证为既有 CRLF 检出环境问题(reader.html 为 i/lf w/crlf、裸 LF 0 处,断言要求裸 \n),与本改动无因果,已在任务文档记录。

Task-Guard: PLAYBACK-LOADING-GUARD-20261009

Verification: compileLeanbackArm64_v8aDebugJavaWithJavac OK; testMobileArm64_v8aDebugUnitTest: VideoActivityLayoutTest 154/154 pass (incl. new guard-release assertion), PlaybackOwnershipSourceTest 16/16 pass; ReaderPlaybackRoutingSourceTest 2 failures proven pre-existing CRLF checkout artifact (reader.html i/lf w/crlf, bare LF count 0), unrelated to this change

Task-Guard: PLAYBACK-LOADING-GUARD-20261009
2026-10-09 16:38:45 +08:00
Silent1566
27fe5c6927 docs(c54): 记录 dev4 交付坐标(合并提交 08d4b66118 / recovery tag / 推送 / PR #429)
- 合并提交 08d4b6611802db1f3349aff828df9d08b42c5d69,第二父 = origin/beta tip 35a5a63f8a
- recovery tag recovery/C54-beta-merge-review-dev4/20261009083551-08d4b6611802(已推送)
- origin/dev4 61e483011e → 08d4b661180(fast-forward)
- PR #429(base=beta、head=dev4、OPEN、mergedAt=null、MERGEABLE/CLEAN),文件集 5 路径与净差异及 compare API 三者一致;仅创建未合并

Task-Guard: C54-dev4-doc-coordinates

Verification: 仅文档改动:doc 记录合并提交 08d4b66118 / recovery tag recovery/C54-beta-merge-review-dev4/20261009083551-08d4b6611802 / origin/dev4 推送 61e483011ed→08d4b661180 / PR #429(state=OPEN、mergedAt=null、base=beta、head=dev4、5 路径与 git diff origin/beta dev4 及 compare API 一致);无代码改动,无需重跑构建与测试

Task-Guard: C54-dev4-doc-coordinates
2026-10-09 16:37:24 +08:00
Silent1566
08d4b66118 merge: 合并 origin/beta 最新代码(PR#427 小说朗读 / PR#428 去广告总时长)并复评 dev4 搜索下拉对比度修复
- 合入 beta tip 35a5a63f8a5(11 提交 / 36 路径,0 冲突、0 删除);合并树相对 beta 的净差异只有本分支既有改动(3 个 mobile 文件 + 1 个文档)与本任务文档
- 零复活:resurrected = 0(revert 集 109 提交 / 725 路径;可证伪自检注入 5 条「在 revert 集且不在 beta 树」的路径全部被报出);零漂移:36/36 带入路径 blob 与 beta 逐字节一致;零丢失:beta 树 − 合并树 = 0
- 复评本地未推送提交 42b03f028e9(手机版搜索下拉对比度):面板 colorSurfaceContainer × item 文字 colorOnSurface 同源配对;ThemeResolver.enforceBase 对 surfaceContainer 有 4.5:1 门(surfaceChanged = hasSurface || hasContainer || hasContainerHigh),自定义主题下不会重现;无失效导入、无行为外改动
- 复评 beta 增量:AndroidManifest 新服务 exported=false + foregroundServiceType=mediaPlayback(FGS/NOTIFICATIONS 权限既有,targetSdk=28);新增 13 个 reader_tts_* 键三语占位符逐条一致;PR#428 三条 HLS 通道文案统一到 HlsAdblockNotice.message(先归整到 0.1 秒再分档,与 AdBlockTimeFormatter 口径一致,0/负/非有限值回退片段数)
- 验证:双 flavor Java + 双 flavor AndroidTest Java 编译 BUILD SUCCESSFUL;双 flavor 全量 JVM 单测 mobile 4971 / leanback 4131,failures=0 errors=0 skipped=2(含 SearchScopePopupLayoutTest 4、Tts* 30、HlsAdblock* 17);check_ui_tokens --strict contrast failures=0、violations=1(既存 item_following.xml,零新增);git diff --cached --check 干净
- 环境:JAVA_HOME 为 Microsoft JDK 21.0.12 时 2 个既有 MPV 测试因 File.renameTo 语义差异确定性失败;本轮统一使用项目 provisioned JBR 21.0.10,非本次引入,按约定仅记录不修改

Task-Guard: C54-beta-merge-review-dev4

Verification: 合并 beta tip 35a5a63f8a5(11 提交 / 36 路径,0 冲突 0 删除)后:git diff origin/beta 净差异仅本地 4 路径 + 本任务文档;resurrected=0(109 revert 提交 / 725 路径 + 5 条已知回退路径注入自检全部报出);36/36 带入路径 blob 与 beta 一致(零漂移);beta 树 − 合并树 = 0(零丢失);双 flavor Java + AndroidTest Java 编译 BUILD SUCCESSFUL;双 flavor 全量 JVM 单测 mobile 4971 / leanback 4131,failures=0 errors=0 skipped=2;check_ui_tokens --strict contrast failures=0 / violations=1(既存 item_following.xml);git diff --cached --check 干净;JDK=项目 provisioned JBR 21.0.10

Task-Guard: C54-beta-merge-review-dev4
2026-10-09 16:35:51 +08:00
Silent1566
814935ceea fix(cache): 修复临时文件缺陷回归锁缺失与结果文案语言回退
Verification: 缓存包单测 71/71 通过(0 failures/0 errors; CacheFullCleanupTest 5->7 例, 新增 onlyExplicitRequestsIgnoreTheBackgroundRetentionWindow 与 explicitRequestStillOnlyClaimsTheReportedFamily, 并把两条临时文件用例改为向 explicitRetention 取窗口); :app:compileMobileArm64_v8aDebugJavaWithJavac 与 :app:compileLeanbackArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL; git diff --check 无空白问题

Task-Guard: cache-full-cleanup-review
2026-10-09 16:23:44 +08:00
Silent1566
35a5a63f8a
Merge pull request #428 from Silent1566/dev1
去广告成功提示补充总广告时长(三条 HLS 通道统一文案 + 时长格式化边界修复)
2026-10-09 16:06:24 +08:00
Silent1566
6bb9203722 docs(c53): 记录交付坐标(修复提交 926b9d50c / tag / 推送 / PR #428)
Verification: 交付坐标文档提交(仅 docs/C53-beta-merge-review-dev1-20261009.md):记录任务起始 HEAD 72cdec02b、origin/beta tip fe1f725a1(已为 HEAD 父提交,merge --no-ff 返回 Already up to date)、复评修复提交 926b9d50c、recovery tag recovery/C53-beta-merge-review-dev1/20261009160214-926b9d50ca66、推送 e44dadffd..926b9d50c dev1->dev1(推送后 origin/dev1==dev1)、PR #428(OPEN/未合并/mergeStateStatus=CLEAN),PR 文件集 9 路径与 git diff --name-only origin/beta HEAD 逐项一致,PR 变更规模 +485 -11。

Task-Guard: C53-beta-merge-review-dev1-coordinates
2026-10-09 16:03:34 +08:00
Silent1566
926b9d50ca fix(adblock): 复评修正广告时长跨单位进位与显示粒度边界(F1/F2)
复评 72cdec02b(去广告提示补充总广告时长)时在时长格式化上发现 2 个真实缺陷:

- F1 时长跨单位边界自相矛盾:原 durationText 用未舍入原值分档,
  [59.95, 60) 会被 %.1f 格式化成「60.0 秒」,与仓库既有约定
  AdBlockTimeFormatter.formatSeconds(先舍入后进位,测试锁定
  59.96 -> 00:01:00.0)冲突。改为先按 0.1 秒粒度舍入成 tenths 再分档,
  秒档条件 tenths < 600,进位只发生一次。
- F2 低于显示粒度的时长仍显示「0.0 秒」:AD-NOTICE-01 验收标准第 4 条
  要求不出现「0.0 秒」误导,但 0 < d < 0.05 的正值仍走秒档并被 %.1f
  格式化成「0.0 秒」。改为显示粒度以下(含 0/负数/非有限值)返回空串,
  message 退回只显示条数,最小可显示值为 0.1 秒。

新增 HlsAdblockNoticeTest 两条锁定用例(6 -> 8 项),既有文案断言全部保持。
本提交同时记录 C53 合并判定与复评结论(docs/C53-...),并更新
AD-NOTICE-01 任务文档的复评补充与下一动作。

Verification: 复评修复 F1/F2:durationText 先按 0.1 秒粒度舍入再分档(59.96 -> 1 分钟,消除自相矛盾的 60.0 秒),显示粒度以下返回空串、message 退回只显示条数(0.04 -> 无时长,消除 0.0 秒)。负对照按复评前原文逻辑实跑得 old(59.96)=60.0 秒 / old(0.04)=0.0 秒,证明两条新增用例可证伪。验证:双 flavor 定向单测 34 项(17+17)failures=0 errors=0;双 flavor Java/AndroidTest 编译 + 全量 JVM 套件 BUILD SUCCESSFUL(leanback 4131 / mobile 4969,failures=0 errors=0,较 C52 基线 +6/+6);UI_TOKEN_STATUS PASS(violations=1 为基线既有的 item_following.xml,零新增违规);git diff --check=0、冲突标记 0。合并判定:git merge --no-ff origin/beta = Already up to date(beta tip fe1f725a1 已是 HEAD 父提交,merge-base --is-ancestor 为真);零复活严格判据 0 行(139 个 revert 类单亲提交 / 26786 distinct 删除行 vs diff 新增 134 行,表面重合 13 行全为通用脚手架行且大量存在于 beta tip),--diff-filter=D 为空(零丢失)。

Task-Guard: C53-beta-merge-review-dev1
2026-10-09 16:02:14 +08:00
Silent1566
42b03f028e fix(mobile): 修复深色模式搜索分组下拉面板对比度不足
手机版搜索页与搜索结果页的范围/分组下拉面板由代码写死 Color.WHITE,
而同一面板的 item 文字取主题语义角色 colorOnSurface,深色表该角色是近白色
#E2E2E9 —— 前景与底色来自两张不同的表,深色模式下就是「近白字压在白底上」。
设备实测(192.168.50.3:5561,uimode night)搜索页与搜索结果页两个下拉均为
#FFFFFF × #E2E2E9 = 1.29:1,与用户照片采样一致。

面板改用与 item 文字同表的 M3 菜单容器角色 colorSurfaceContainer:
SearchFragment.getScopePopupBackground() 与 CollectFragment.getGroupPopupBackground()
各一行行为改动,圆角/水波纹/条目高度/宽度计算与选中回调均不变。
ThemeResolver 对 onSurface 本就有 enforceBase(surface, surfaceContainer,
surfaceContainerHigh) ≥ 4.5:1 的修复通道,自定义主题下不会再重现该缺陷。

Verification: JVM SearchScopePopupLayoutTest 4/4 通过(新增源码守卫 + 直接解析两套 token
表算对比度的守卫,并经变异检验转红);check_ui_tokens --strict contrast failures=0、
violations=1(既存,与基线一致);assembleMobileArm64_v8aDebug 成功并 -r 覆盖安装
(签名 4dbe7298);设备四组合实测 深色 12.14:1 / 浅色 14.73:1(修复前 1.29:1)。

Verification: JVM: testMobileArm64_v8aDebugUnitTest --tests SearchScopePopupLayoutTest => 4/4 pass (BUILD SUCCESSFUL); 变异检验:SearchFragment 面板改回 Color.WHITE 后 mobileScopePopupsTakeTheirSurfaceFromThePalette FAILED(AssertionError:70) 并转红,恢复后 4/4 通过; scripts/check_ui_tokens.sh --strict => contrast failures=0, violations=1(既存 item_following.xml,与基线一致,无新增); assembleMobileArm64_v8aDebug BUILD SUCCESSFUL; adb 192.168.50.3:5561 覆盖安装(install -r, 签名 4dbe7298 一致) Success; 设备像素实测四组合:深色搜索页下拉/深色分组下拉 #1F2428 × #E2E2E9 = 12.14:1,浅色两组 #ECEEF4 × #1A1C1E = 14.73:1(修复前 #FFFFFF × #E2E2E9 = 1.29:1,与用户照片 #FFFFFF 面板一致); 测试后已把 cmd uimode night 恢复为 no,未改动应用数据/主题/站源配置

Task-Guard: MOBILE-SEARCH-DROPDOWN-CONTRAST-20261009
2026-10-09 15:30:28 +08:00
Silent1566
f0da126a2c fix(cache): 长按一键全清不再打开缓存管理面板
Verification: 长按一键全清改为不弹面板(用户指正)。设备实测(5563/leanback arm64 debug 覆盖安装 com.silent.android.webhtv,versionText=5.6.0-202610091513,预置 2MB zip+64KB js+256KB bin,设置行 2.3MB/702MB): ①只发一次长按(不预先点击)后 mResumedActivity 仍为 SettingActivity 且无障碍树无任何面板节点; ②长按后1秒抓屏同时可见设置页在前台+缓存行自动刷新为 无/702MB+Toast「清理完成 释放 2.3 MB · 删除 7 个文件」; ③journal 末条 {mode:FULL,reason:shortcut,bytesBefore:2437024,after:0,deletedFiles:7,COMPLETED,warnings:[]} 与 Toast 一致; ④短按仍正常打开面板(无回归),logcat 无 FATAL/ANR; ⑤代码: showFullCleanup 三重载/ARG_CLEANUP_MODE/shortcutStarted/isFullCleanupShortcut 已删除,结果文案抽为静态 describe 共用,新增串 cache_cleanup_full_started 三语齐备; 构建 BUILD SUCCESSFUL; 未改缓存包纯函数故未重跑单测; build.gradle 已按 git hash-object+sha256 双指纹字节还原

Task-Guard: full-cleanup-no-panel
2026-10-09 15:28:04 +08:00
Silent1566
72cdec02b2 feat(adblock): 去广告成功提示补充总广告时长,三条 HLS 通道统一文案
原提示文案在三处内联且以 structured 为条件,legacy 兜底通道即使已算出
removedDurationSec 也只显示条数,用户因此只看到「总切片数」。

- HlsAdblockNotice 新增 message(...)/durationText(...) 作为唯一文案入口,
  只要时长 > 0 就追加「总广告时长 X」,不再依赖 structured 判据;
  < 60s 用秒、>= 60s 用分钟,避免长广告块显示成 185.0 秒。
- nano /m3u8 代理、Exo ExoHlsAdblockDataSource、MPV/IJK MpvHlsProxy
  三条通道统一改用该入口,消除三份重复实现。
- 补测:文案/时长/分钟进位、结构化与 legacy 双通道含时长断言、
  三通道必须走共享入口的源码契约测试;Exo 弱断言改为精确文案。

验证:mobile+leanback 定向单测 30 项全通过;设备实测 legacy 兜底
提示为「已跳过 2 个广告片段,总广告时长 45.5 秒」。仅改文案构造,
不触碰净化判据、删除阈值、回退闸门与统计写入。

Verification: 去广告提示补充总广告时长:mobile+leanback 双 flavor 定向单测各 15 项全通过(HlsAdblockNoticeTest 6 / HlsAdblockPipelineTest 6 / ExoHlsAdblockDataSourceTest 3,failures=0 errors=0),新增三通道共享入口契约测试锁死回归;设备 192.168.50.3:5555 (LIO-AN00/Android 9) 覆盖安装 mobile debug 后经真实 /m3u8 去广链路实测系统 Toast 队列原文:修复前 '已跳过 2 个广告片段'(无时长),修复后 legacy 兜底 '已跳过 2 个广告片段,总广告时长 45.5 秒'(removed=2 structured=false legacy=true,时长 20.0+25.5 秒吻合)与 '已跳过 1 个广告片段,总广告时长 7.0 秒',调用栈为 Notify.show(Notify.java:55) <- M3u8.recordAndNotify(M3u8.java:120);结构化通道由单测断言 '已跳过 1 个广告片段,总广告时长 7.0 秒' 覆盖;安装后 APK dex 仅含新文案、旧 '已跳过 %d 个广告片段(%.1f 秒)' 已消失,进程存活且 FATAL EXCEPTION=0

Task-Guard: AD-NOTICE-01
2026-10-09 15:21:51 +08:00
Silent1566
92f1844342 docs(cache): 记录长按一键全清与临时文件修复的设备实测证据
Verification: 设备实测(5563/leanback arm64 debug 覆盖安装 com.silent.android.webhtv,apksigner 证书 SHA-256 与既有包一致无需卸载,versionText=5.6.0-202610091450): ①临时文件模块行清理=清理完成 释放 3 MB·删除 1 个文件(新建 webhtv-sync-test1.zip 被删,js/zz-test-idle.js 与 unknown-probe.bin 保留);②长按缓存行=清理完成 释放 6.6 MB·删除 119 个文件,总量变共无,cache 目录清空;③journal: mode=MODULE bytesBefore=3145728 deletedFiles=1 COMPLETED warnings=[] 与 mode=FULL bytesBefore=6911351 deletedFiles=119 COMPLETED warnings=[];④设置行自动刷新为 无/702MB,确认框默认聚焦取消;⑤全清后冷启动无 FATAL/ANR 且 chaquopy/WebView 缓存自动重建;app/build.gradle 已按 git hash-object+sha256 双指纹字节还原

Task-Guard: cache-full-cleanup-device-verify
2026-10-09 15:03:36 +08:00
Silent1566
f9f47c24ae fix(cache): 修复临时文件显式清理无效并补回长按一键全清
Verification: 缓存包单元测试 69/69 通过(新增 CacheFullCleanupTest 5 例覆盖显式请求删新临时包、后台保留期仍保留、进行中传输豁免、残留扫描删无主残留与闲置插件脚本、保留播放缓存根/传输/恢复文件;CachePolicyEngineTest 新增 fullPlanCoversEveryModuleExactlyOnce);:app:compileMobileArm64_v8aDebugJavaWithJavac 与 :app:compileLeanbackArm64_v8aDebugJavaWithJavac 通过;git diff --check 干净;设备端长按手势实测未执行(待申请模拟器)

Task-Guard: cache-full-cleanup-and-temp-fix
2026-10-09 14:30:35 +08:00
Silent1566
fe1f725a12
Merge pull request #427 from Silent1566/dev1
merge: 合并 origin/beta 最新代码(PR#425 C47 seek 加载圈窗口 / PR#426 首页菜单键弹窗对比度)并复评小说朗读补全
2026-10-09 14:12:57 +08:00
Silent1566
e44dadffd6 docs(c52): 记录交付坐标(合并提交 86e1bfe3c / 修复提交 32202da2d / tag / PR #427)
文档收口提交:补齐任务文档的提交、recovery tag、推送与 PR 坐标,记录 PR 文件集与本地净差异
的逐项一致性校验结果,并记录两条既有静态扫描告警(picNonce 的 Math.random、图片缓存键 MD5)
不在本次改动范围内的判定依据。

Verification: docs-only 收口:仅回填交付坐标与逐项校验结果(PR 文件集 27 == 本地净差异 27),
无代码改动、未再次构建或验证;该净差异此前已通过双 flavor Java 与 AndroidTest Java 编译、
双 flavor 全量 JVM 套件(leanback 4125 / mobile 4963,0 失败)、UI token 门禁与真机
ReaderTtsDeviceTest OK (6 tests)

Task-Guard: C52-beta-merge-review-dev1-coordinates

Verification: docs-only 收口:仅回填交付坐标(合并提交 86e1bfe3c / 修复提交 32202da2d / recovery tag / PR #427)与逐项校验结果(PR 文件集 27 == 本地净差异 27),另记录两条既有扫描告警的归属判定;无代码改动、未再次构建或验证;该净差异此前已通过双 flavor Java 与 AndroidTest Java 编译、双 flavor 全量 JVM 套件(leanback 4125 / mobile 4963,0 失败)、UI token 门禁与真机 ReaderTtsDeviceTest OK (6 tests)

Task-Guard: C52-beta-merge-review-dev1-coordinates
2026-10-09 14:10:59 +08:00
Silent1566
32202da2de fix(reader-tts): 修复停播通知残留、暂停中改语速出声与朗读桥线程,复评朗读补全并合并 beta
合并远端 beta 最新代码(PR#425 C47 seek 加载圈窗口 / PR#426 首页菜单键弹窗对比度),
零冲突;零复活三层证据复活行数 0,beta 增量逐 blob 一致、零丢失。

复评未推送的朗读功能(NOVEL-TTS)后修复三处真实缺陷:
- 停播后通知栏残留:onTtsState 在 stopForegroundCompat 撤掉通知后仍无条件
  updateNotification,把通知贴回来且标题为「正在朗读」,服务销毁也不清理。
  改为 stopped 不再重贴,并在 onDestroy 兜底 cancel。
- 暂停中改语速出声:MediaPlayer.setPlaybackParams 用非零速度等价 start(),
  暂停中拖动语速会把音频拖响(界面仍显示「已暂停」)。改为暂停中只更新
  options,resume 后在 start() 之后补 applyRate。
- 朗读桥线程:@JavascriptInterface 跑在 WebView 的 JavaBridge 线程,12 个
  朗读桥直接改控制器状态会与主线程引擎回调并发(含 size/get 竞态与非主线程
  startForeground/通知更新)。统一经 postToService 回主线程。

同时修正 NOVEL-TTS 文档中「音频焦点 GAIN 自动恢复」的不实描述(实现只让出、
不自动恢复),并为上述修复补齐真机断言与源码契约测试。

Verification: 双 flavor Java 与 AndroidTest Java 编译通过;双 flavor 全量 JVM 套件
leanback 4125 / mobile 4963 用例 0 失败 0 错误;UI token 门禁 PASS 且相对基线零新增
违规;真机 192.168.50.3:5555 ReaderTtsDeviceTest OK (6 tests);F1/F2 修复前在真机上用
同一套断言各自复现(暂停中改语速把音频拖响、停播后通知栏残留);零复活三层证据复活
行数 0、beta 增量逐 blob 一致

Task-Guard: C52-beta-merge-review-dev1

Verification: 双 flavor Java + AndroidTest Java 编译通过;双 flavor 全量 JVM 套件 leanback 4125 / mobile 4963 用例 0 失败 0 错误;UI token 门禁 PASS(相对基线零新增违规);真机 192.168.50.3:5555 ReaderTtsDeviceTest OK (6 tests);F1/F2 修复前同机负对照各自复现缺陷(暂停中改语速出声、停播后通知残留);零复活三层证据复活行数 0、beta 增量逐 blob 一致

Task-Guard: C52-beta-merge-review-dev1
2026-10-09 14:09:47 +08:00
Silent1566
86e1bfe3ce merge: 合并 origin/beta 最新代码(PR#425 C47 seek 加载圈窗口 / PR#426 首页菜单键弹窗对比度)并复评小说朗读补全 2026-10-09 13:39:00 +08:00
Silent1566
db04c4c8bc docs(novel-tts): 更正朗读测试用例计数为 29(含音调映射)
Verification: 文档更正:JVM 用例计数与第二个会话新增的音调映射用例对齐(29 用例),无代码改动

Task-Guard: NOVEL-TTS-3
2026-10-09 13:23:14 +08:00
Silent1566
1ebec24a65 fix(reader): 朗读音调接入微软 Edge SSML 并按音源隐藏无效控件,路由丢失暂停可验证
Verification: 补强验证:定向 JVM 测试(含音调→Hz 映射及越界夹取)与 mobile/leanback 编译通过;arm64 Debug 重新打包安装通过;真机 192.168.50.3:5555 上 ReaderTtsDeviceTest 6/6 通过,阅读页端到端用例新增覆盖「音频路由丢失自动暂停并可继续朗读」

Task-Guard: NOVEL-TTS-2
2026-10-09 13:22:58 +08:00
Silent1566
8539a450f2 feat(reader): 补全小说模式朗读(系统/百度/Edge/自定义在线引擎 + 后台通知控制)
Verification: 定向 JVM 测试 28 用例通过(TtsTextSplitter/TtsHttpRule/ReaderTtsBridgeSource);mobile+leanback arm64 Java 编译与 arm64 Debug 打包安装通过;真机 192.168.50.3:5555 上 ReaderTtsDeviceTest 6/6 通过(百度与微软 Edge 引擎真实合成+播放推进、系统引擎无引擎时给出可操作错误、定时到点真的停播、阅读页面板按钮→JS 桥→前台服务→引擎端到端含后台继续朗读/通知栏控制/章末续读/停止);自定义在线引擎经临时夹具验证 POST+body 模板+自定义 Header 生效(服务端日志)后已移除夹具

Task-Guard: NOVEL-TTS
2026-10-09 13:14:15 +08:00
Silent1566
29d52ab238
Merge pull request #426 from Silent1566/dev2
merge: 合并 origin/beta 最新代码(PR#425 C47 seek 加载圈窗口)并复评 dev2 首页菜单键弹窗对比度修复
2026-10-09 11:48:22 +08:00
Silent1566
7543959f3e docs(c51): 记录 dev2 交付坐标(合并提交 1f8fc83369 / recovery tag / PR #426)
文档收口提交:补齐任务文档的提交、recovery tag、推送与 PR 坐标,并记录 PR 文件集与本地净差异的逐项一致性校验结果。
无生产代码改动。

Verification: docs-only 收口:仅记录交付坐标(合并提交 1f8fc83369 / recovery tag / PR #426)与 PR 文件集校验结果,无代码改动、未再次构建或验证;该净差异此前已通过双 flavor Java 与 AndroidTest Java 编译、mobile 与 leanback 定向用例(175 项 0 失败)与 UI token 门禁(与基线一致)

Task-Guard: C51-dev2-doc-coordinates
2026-10-09 11:43:45 +08:00
Silent1566
1f8fc83369 merge: 合并 origin/beta 最新代码(PR#425 C47 seek 加载圈窗口)并复评 dev2 首页菜单键弹窗对比度修复
把 origin/beta tip 75735b58f6(PR#425 from dev4)合入 dev2,0 冲突;远端已移除/回退的内容零复活,
beta 增量零丢失,日志与验证记录见 docs/C51-beta-merge-review-dev2-20261009.md。

beta 增量(5 提交 / 7 路径,全部纳入):
- 23e5280f37 修复拖拽进度时加载中/网速大概率不显示:seek 期间开最小可见 1200ms 窗口,
  并用 canHideSeekProgress() 统一约束网速 ticker 兜底、READY 回调与控制器晚绑定补发;
  两个 VideoActivity 的实现与断言与 beta 逐字节一致。
- 1a4110178f / 61e483011e 两份 C47/C49 任务记录,8dd441b1cc 与 75735b58f6 两个合并提交。

本分支自有改动(相对 beta 净差异 4 路径):首页菜单键弹窗焦点条目文字改用
colorOnPrimary(home_menu_text.xml + adapter_home_menu.xml + 对比度回归测试 + 任务文档)。

复评:3 轮。第 2 轮发现 1 个必修问题——任务文档把「上游设计本意」误记为
「adapter_home_menu.xml 曾直接写 @color/white」,实际该布局由 e95b90d3a8(2026-08-23) 创建即用
共享选择器、从未写过 @color/white;真实根因链是 0503f8e3cf 把焦点文字改为 ?attr/colorPrimary
(当时填充仍是硬编码 #2F6FED)、1bb72bd709 再把填充改为 ?attr/colorPrimary,
两者叠加才成为同一角色。已改写为可逐条复现的表述并新增 §8 更正与再验证,未改任何代码或测试。

Verification: 合并 origin/beta tip 75735b58f6(0 冲突;MERGE_HEAD 即该 tip)。零复活:182 个单亲 revert/回退类提交 x 852 触碰路径,beta 已移除 671 路径在合并树中复活 0(含 ISSUE_TEMPLATE 注入自检)。零丢失:beta 增量 7 路径逐 blob 与 beta 逐字节一致,本分支 4 路径逐 blob 与 c5912111a4 逐字节一致,beta 树 4980 路径在合并树中缺失 0。3 轮评审:第 1 轮 0 问题,第 2 轮发现并修复 1 个必修问题(任务文档 §2 历史引用不实,改为可逐条复现的准确表述并新增 §8 更正记录,代码/测试零改动),第 3 轮复核通过。验证:双 flavor 主代码与 AndroidTest Java 编译成功;mobile 定向 C47SeekLoadingProgressSourceTest 5/5 + VideoActivityLayoutTest 154/154;leanback 定向 theme.* 162 + HomeMenuDialogContrastTest 3/3 + HomeMenuDialogSourceTest 5/5 + C47SeekLoadingProgressSourceTest 5/5,合计 175 项 0 失败 0 错误;对比度独立复算 6.39/7.50 与 14.73/12.14,旧写法 1.00;check_ui_tokens.sh 与合并前基线逐项相同(violations=1 hex_layouts=1 pairs=38 failures=0 min=4.28 PASS);git diff --check 与 --cached --check 均为 0,11 个改动路径无冲突标记;提交前再次 fetch 确认 origin/beta 未前进;末次构建后已执行 gradlew --no-daemon clean 回收资源;未使用模拟器(净差异 4 路径 blob 与已实测提交相同,重复实机验证不产生新信息)

Task-Guard: C51-beta-merge-review-dev2-20261009
2026-10-09 11:38:46 +08:00
Silent1566
c5912111a4 fix(tv): 首页菜单键弹窗焦点条目文字改用 colorOnPrimary
HomeMenuDialog 条目的焦点底色是 shape_config_history_item_focused 的
colorPrimary 实心填充,而文字走共享的 config_history_text,其焦点色同样是
colorPrimary —— 同一角色压在自身之上:默认表 1.00:1,设备自定义主题下
ThemeBinder 只改写文字色状态列表、不改写 StateListDrawable 内的填充,实测
#006876 on #0B57D0 = 1.01:1。

新增 app/src/leanback/res/color/home_menu_text.xml(焦点/按下 colorOnPrimary,
常态 colorOnSurface)并接线到 adapter_home_menu.xml;共享的 config_history_text
保持不变,因为它还服务 dialog_history 中焦点底色为 primaryContainer 的描边按钮。

验证:HomeMenuDialogContrastTest 解析两套 token 表并计算对比度(焦点 6.39:1 /
7.50:1,常态 14.73:1 / 12.14:1,旧写法 1.00:1 钉为回归断言);leanback 测试与
theme.* 全族通过;覆盖安装后在 192.168.50.3:5557 实测焦点条目 1.01:1 -> 6.39:1,
其余 10 项保持 14.71:1,焦点移动后新焦点项同样 6.39:1。

Task-Guard: TV-HOME-MENU-CONTRAST-20261009

Verification: leanback JVM: HomeMenuDialogContrastTest 3/3 + HomeMenuDialogSourceTest 5/5 + theme.* 全族通过; assembleLeanbackArm64_v8aDebug 成功并 adb install -r 覆盖安装 192.168.50.3:5557; 设备实测焦点条目 #FFFFFF on #0B57D0 = 6.39:1(修复前 #006876 on #0B57D0 = 1.01:1), 其余 10 项 14.71:1

Task-Guard: TV-HOME-MENU-CONTRAST-20261009
2026-10-09 11:07:53 +08:00
Silent1566
75735b58f6
Merge pull request #425 from Silent1566/dev4
merge: 合并 origin/beta 最新代码(PR#421/422/423/424)并复评 C47 seek 加载圈窗口修复
2026-10-09 10:46:28 +08:00
Silent1566
61e483011e docs(c49): 记录 dev4 交付坐标(合并提交 8dd441b1cc / recovery tag / PR #425)
文档收口提交:补齐任务文档的提交、recovery tag、推送与 PR 坐标,并记录 PR 文件集与本地净差异的逐项一致性校验结果。
无生产代码改动。

Verification: 文档收口:仅记录交付坐标(合并提交 8dd441b1cc / recovery tag / PR #425)与 PR 文件集校验结果,无代码改动;该 7 路径净差异此前已通过双 flavor Java/AndroidTest 编译、双 flavor 全量单测(mobile 4933 / leanback 4092 零失败)与 UI token 门禁 PASS

Task-Guard: C49-dev4-doc-coordinates
2026-10-09 10:41:12 +08:00
Silent1566
8dd441b1cc merge: 合并 origin/beta 最新代码(PR#424 实验室配置源弹窗)并复评 C47 seek 加载圈窗口
- 以最终 origin/beta tip 7df98107be 合入 dev4(含 PR#422 自动下一集黑屏修复、PR#423 历史集数行对比度、PR#424 实验室配置源弹窗),0 冲突,合并树 df59dec76 与 merge-tree 预测逐字节一致
- 远端已移除/回退内容零复活:净差异 6 路径 == 本地自身改动集;行级扫描 54 个 revert 提交 / 36 removed 行 → 复活 0 行;并以 AdAudioConsumer.java 注入自检证明检测器不空转(正例 170 命中、负例 0)
- 复评 C47「拖拽 seek 时加载中/网速不显示」窗口修复:订正文档两处事实错误(onSeekStarted 的第二个调用点 PlaybackActivity.seekTo(477);leanback onControllerReadyReconciled 系本次新增而非既有改走闸门)
- 新合入 PR#424 实验室弹窗增量逐点复核无必修缺陷(内容与面板同源、语义 token、8 用例契约测试两 flavor 通过)
- 验证:双 flavor Java/AndroidTest 编译通过;全量单测 mobile 4933 / leanback 4092 零失败;UI token 门禁 PASS

Verification: 双 flavor Java 编译 + 双 flavor AndroidTest Java 编译 BUILD SUCCESSFUL;双 flavor 全量 JVM 单测 mobile 4933 / leanback 4092,failures=0 errors=0 skipped=2;UI token 门禁 PASS(violations=1 为预先存在的 item_following.xml,相对基线零新增);零复活三层证据 resurrected=0 且可证伪自检 PASS(哨兵 AdAudioConsumer.java 正例 170 命中/负例 0);beta 增量 31 路径零丢失零漂移、dev4 自身 6 路径零丢失零改写;31 条已暂存路径与索引 blob 零内容差异;合并树 df59dec76 与 git merge-tree 预测逐字节一致

Task-Guard: C49-beta-merge-review-dev4
2026-10-09 10:38:08 +08:00
Silent1566
7df98107be
Merge pull request #424 from Silent1566/dev1
merge: 合并 origin/beta 最新代码(PR#423 手机历史集数行对比度修复)并复评实验室配置源弹窗修复
2026-10-08 23:59:21 +08:00
Silent1566
cb8022bf77 docs(c50): 记录交付坐标(提交 a8b30e09d / 1e83bdc25 / tag / PR #424)
Verification: docs-only 收口:记录交付坐标(合并 a8b30e09d / 文档 1e83bdc25 / tag / PR #424);PR #424 base=beta head=dev1 state=OPEN mergedAt=null MERGEABLE,PR 文件集 7 项与 git diff --name-only origin/beta HEAD 逐项一致;dev1 已推送且 0 ahead/0 behind;未新增构建或验证

Task-Guard: C50-beta-merge-review-dev1
2026-10-08 23:52:50 +08:00
Silent1566
1e83bdc25a docs(c50): 复评实验室配置源弹窗修复并记录 beta 合并评审,修正下拉列表主题跟随的不实描述
Verification: 双 flavor Java + AndroidTest 编译与全量 JVM 套件 BUILD SUCCESSFUL(leanback 4087 / mobile 4928 用例,0 失败 0 错误);check_ui_tokens.sh PASS(violations=1 为既存 item_following.xml,相对基线零新增);零复活三层校验 resurrected=0(139 个单亲 revert 类提交 / 761 文件版本 / 236817 删除行)、beta 增量 3 路径逐 blob 与 beta 一致、净差异仅 dev1 自身 6 路径;设备复测(192.168.50.3:5555)复现弹窗与下拉对比度 14.87:1 / 12.64:1 并验证网络 URL 切换功能流;冲突标记 0、9 个 strings.xml 无重复键、改动 XML 良构

Task-Guard: C50-beta-merge-review-dev1
2026-10-08 23:50:56 +08:00
Silent1566
a8b30e09dc merge: 合并 origin/beta 最新代码(PR#423 历史集数行对比度修复)并复评实验室配置源弹窗修复 2026-10-08 23:33:46 +08:00
Silent1566
60e657c074 fix(lab): 配置源下拉列表改用弹窗主题上下文与语义 item 布局,修复白字浅底
Verification: dev1 192.168.50.3:5555 最终 APK 像素实测:配置源下拉弹出列表 item 文字 #1A1C1E 对比 #F3EDF7 面板 = 14.87:1(修复前 1.19:1),深色模式 12.64:1;弹窗正文 6.11-11.24:1,主题色=鸢尾紫时面板/描边/图标/按钮全部跟随;check_ui_tokens --strict 仅剩 HEAD 既存 item_following.xml 违规;testMobileArm64_v8aDebugUnitTest + testLeanbackArm64_v8aDebugUnitTest BUILD SUCCESSFUL;LabSettingsDialogThemeTest 8/8 通过并经变异检验转红

Task-Guard: LAB-CONFIG-DIALOG-20261008-DROPDOWN
2026-10-08 23:27:19 +08:00
Silent1566
765dce2e2a
Merge pull request #423 from Silent1566/dev2
merge: 合并 origin/beta 最新代码(PR#422 自动下一集黑屏修复)并复评 dev2 历史集数行对比度修复
2026-10-08 22:48:28 +08:00
Silent1566
a7154d35e4 fix(lab): 实验室配置源弹窗内容与面板同源,修复默认主题下白字看不清并让主题色生效
Verification: dev1 192.168.50.3:5555 像素实测:默认主题弹窗正文 6.11-11.24:1(修复前 1.05:1)、深色 5.71-7.53:1、主题色=鸢尾紫面板 #C6D2EA→#EBDEF3 且描边/图标/按钮 #0B57D0→#8400F0;check_ui_tokens --strict 仅剩 HEAD 既存 item_following.xml 违规(stash 验证无关);testMobileArm64_v8aDebugUnitTest + testLeanbackArm64_v8aDebugUnitTest BUILD SUCCESSFUL;新增 LabSettingsDialogThemeTest 6/6 通过并经变异检验转红

Task-Guard: LAB-CONFIG-DIALOG-20261008
2026-10-08 22:13:26 +08:00
Silent1566
a36a1e9c8f docs(c49): 记录交付坐标(提交 a51e6f366f / tag / PR #423)
Verification: 文档-only 收口提交;PR #423 base=beta head=dev2 state=OPEN mergedAt=null,PR 文件集 3 项与 git diff --name-status origin/beta HEAD 逐项一致;dev2 已推送且 0 ahead/0 behind;未再次构建或验证。
2026-10-08 22:10:09 +08:00
Silent1566
a51e6f366f merge: 合并 origin/beta 最新代码(PR#422 自动下一集黑屏修复)并复评 dev2 历史集数行对比度修复
Verification: 合并 origin/beta tip 4174c65ea3(0 冲突;MERGE_HEAD 即该 tip);零复活:182 个单亲 revert/移除提交 x 852 触碰路径,beta 已移除 671 路径在合并树中复活 0(含 ISSUE_TEMPLATE 注入自检);零丢失:beta 增量 4 路径逐 blob 与 beta 一致,dev2 自身 2 路径逐 blob 保留,合并树路径集合 == beta 路径集合;2 轮评审发现并修复 1 个必修问题(新增注释含裸色值使 UI token 门禁违规 1→2,改写注释后回到基线 1);git diff --check 与 --cached --check 均 0;check_ui_tokens.sh violations=1 legacy=0 contrast failures=0 PASS;双 flavor 全量单测 mobile 4920/0/0 leanback 4079/0/0 BUILD SUCCESSFUL;双 flavor Java 与 AndroidTest Java 编译成功;PlaybackOwnershipSourceTest 16/16 x2、HistoryAdapterTest 3/3;未使用模拟器(本任务零生产行为改动)。

Task-Guard: C49-beta-merge-review-dev2
2026-10-08 22:08:02 +08:00
Silent1566
1a4110178f docs(c47): 记录模拟器验收证据与精度边界
把 C47 的实机(模拟器)验收过程与结论补入任务文档,不涉及代码变更。

- 环境阻塞与排除:安装 dev4 后 App 启动即崩 Room IllegalStateException
  (Migration didn't properly handle: History)。只读排查确认是设备预存状态——
  user_version=37 但 History 仅 17 列,缺 MIGRATION_36_37 应加的 5 列
  (typeName/area/actor/director/year),且 tv 文件时间戳早于本次安装;C47 提交
  只动 2 个 VideoActivity + 测试 + 文档,不触碰 db/,故与本次改动无关。为完成
  验收临时移开 databases/tv 让 Room 重建,验收后已完整还原。
- 判据纠正:dumpsys activity top 报的 V/G 是视图自身标志,对 overlay 容器不可靠
  (根 app:id/progress 为 G 时其子 app:id/traffic 仍可能显示 V)。判定覆盖层可见
  性必须用根节点。
- 路径辨析:mobile 的手势横滑不经过本次改动——onSeeking() 会主动 hideProgress(),
  且 onTouchEnd/onSeekEnd 不调用 onSeekStarted()(唯一调用者是 CustomSeekView,
  即进度条)。用户所述「拖拽进度」对应进度条路径,验收须用 app:id/timeBar 实测
  绝对坐标 [178,597][794,675]。
- 进度条拖拽实测:设备端紧循环采样(单次 30-160ms)显示 基线 G(隐藏)→ 抬手
  瞬间 V(出现)→ 持续约 1.0-2.0s 后干净回到 G;越过缓冲区拖拽时窗口更长。与
  「最小可见 1.2s + 闸门」预期一致,未复现「抬手即被收圈」。
- 精度边界(如实记录):该实例 loadavg≈9-12(x86_64 + ARM 转译 + 软件渲染),
  uiautomator dump 约 3.9s、dumpsys 取时戳滞后 150-800ms,无法逐帧分辨 1.2s
  窗口,traffic 文本也不落 mText,故不宣称网速观感已逐帧确认。
- 设备已还原:原 APK 重新覆盖安装(sha256 315e7d03… 与安装前一致)、databases/tv
  还原为 user_version=37/17 列、移除全部临时文件;未打正式包。

Task-Guard: C47-device

Verification: 仅文档变更:把 C47 的模拟器验收证据写入 docs/C47-seek-loading-progress.md(设备 192.168.50.3:5561 = emulator-5560 HD1910,mobile/arm64-v8a Debug 覆盖安装)。证据:① App 启动崩溃经只读排查定性为设备预存 Room 迁移不匹配(user_version=37 但 History 仅 17 列,缺 MIGRATION_36_37 的 5 列;C47 不触碰 db/),为验收临时移开 databases/tv 并在验收后完整还原;② 纠正判据:dumpsys 的 V/G 对 overlay 容器不可靠,须用根节点 app:id/progress;③ 辨析路径:mobile 手势横滑不经 onSeekStarted(onSeeking 会 hideProgress),用户所述拖拽对应进度条路径,须用 app:id/timeBar;④ 进度条拖拽实测(设备端紧循环采样 30-160ms):基线 G → 抬手瞬间 V → 持续约 1.0-2.0s 后干净回到 G,未复现「抬手即被收圈」;⑤ 如实记录精度边界:该实例 loadavg≈9-12,uiautomator dump 约 3.9s、dumpsys 取时戳滞后 150-800ms,无法逐帧分辨 1.2s 窗口,也不宣称网速文本已逐帧确认;⑥ 设备已完整还原(原 APK sha256 315e7d03… 一致、DB 还原为 37/17、临时文件清除)。未执行 gradle(本次仅改 markdown,无代码变更),git diff --check clean

Task-Guard: C47-device
2026-10-08 22:02:38 +08:00
Silent1566
4174c65ea3
Merge pull request #422 from Silent1566/dev1
merge: 合并 origin/beta 最新代码(PR#421 站点注入搜索与手机缓存排版)并复评自动下一集黑屏修复
2026-10-08 20:45:22 +08:00
Silent1566
0a0bed4208 docs(c48): 记录交付坐标(提交 87380b5cf / tag / PR #422)
Verification: 文档-only 收口提交;PR #422 已创建且 mergedAt=null,PR 文件集(gh api 分页 4 项)与 git diff --name-only origin/beta HEAD 逐项一致;dev1 已推送且 0 ahead/0 behind

Task-Guard: C48-beta-merge-review-dev1
2026-10-08 20:42:39 +08:00
Silent1566
87380b5cf7 merge: 合并 origin/beta 最新代码(PR#421 站点注入搜索与手机缓存排版)并复评自动下一集黑屏修复
把远端 beta 最新 7 个提交合入 dev1(3 个实质增量:站点注入搜索、搜索空状态与排序刷新回归修复、手机缓存管理排版修复),
并复评 dev1 全部已修改代码(含已提交未推送的 5096941a4 自动下一集黑屏修复)。

合并:0 冲突,第二父为 origin/beta tip 46917be79。
零复活:104 个单亲 revert/移除类提交 x 137 文件版本扫描复活行数为 0;dev1 与 beta 共有 4970 路径中 4968 路径 blob 逐字节相同,只在 beta 存在的路径数为 0。
零丢失:beta 增量 17 路径与 beta tip 逐 blob 一致;dev1 自身 3 路径全部保留。
净差异收敛为 dev1 自身 3 路径。

复评 3 轮(本任务 app/src 零改动):
- 第 1 轮复核 5096941a4:根因(preparePlayer 回调后清 spec / attachSurface 只判空)成立;新判断为旧语义超集,无功能回退;PlayerView.setPlayer 同实例早退,无解绑-绑定循环;已 release 引擎走 isCommandAvailable=false 分支,无空指针风险;单测可证伪。
- 第 2 轮复核 beta 增量:站点注入搜索的 visibleIndices 索引层、越界守卫、筛选期禁排序、局部通知保留、空状态同步、搜索字段覆盖、主题 token、三语言资源均通过;手机缓存排版竖排/横排分支、焦点链、主题契约、双 flavor 布局 id 一致性均通过。
- 第 3 轮最终复核:净差异、零复活、空白、冲突标记、重复键、编译、单测、门禁全部通过。

Verification: 见 commit trailer 与 docs/C48-beta-merge-review-dev1-20261008.md

Task-Guard: C48-beta-merge-review-dev1

Verification: 合并提交 b8adf3cc1 第二父为 origin/beta tip 46917be79(0 冲突 / 0 冲突标记);零复活:104 个单亲 revert/移除类提交 x 137 文件版本扫描,复活行数 0,且 dev1 与 beta 共有 4970 路径中 4968 路径 blob 逐字节相同、只在 beta 存在的路径数 0;零丢失:beta 增量 17 路径与 beta tip 逐 blob 一致(差异 0),dev1 自身 3 路径全部保留;净差异收敛为 dev1 自身 3 路径(PlaybackActivity.java +9 -2 / PlaybackOwnershipSourceTest.java +26 / docs/AUTONEXT-01-…md +169);3 轮评审全部通过无必修问题(本任务 app/src 零改动);双 flavor Java 编译 BUILD SUCCESSFUL (1m18s EXIT=0);双 flavor AndroidTest Java 编译 BUILD SUCCESSFUL (27s EXIT=0);双 flavor 全量单测 BUILD SUCCESSFUL (2m6s EXIT=0) leanback 4079 tests / mobile 4920 tests failures=0 errors=0 skipped 各 2,定向 PlaybackOwnershipSourceTest 16/16 双 flavor、CustomCspDialogTest 5/5、CustomCspSettingTest 3/3;UI token 门禁 UI_TOKEN_STATUS PASS violations=1 与基线一致(零新增);三套 strings.xml 无重复键、两个 flavor dialog_cache_management.xml id 集合相同、全部 XML 解析通过;git diff --check 含 --cached 退出码 0;未使用模拟器(本任务零生产代码改动)

Task-Guard: C48-beta-merge-review-dev1
2026-10-08 20:40:55 +08:00
Silent1566
0582c72221 fix(mobile): 修复历史记录集数行在壁纸上的对比度不足
手机版历史卡片信息区底色是 shape_vod_name(#33000000) 压在壁纸上,与明暗调色板无关,
但集数行(adapter_vod.xml 的 @+id/remark)在 f63b0a81bc 统一 token 时从 @color/white_70
改成了 ?attr/colorOnSurfaceVariant,日间表解析为 #44474F:压在默认(梦想紫)壁纸上实测
对比度仅 1.4:1,历史记录的集数信息几乎不可读。

改回与标题行同一套与调色板无关的角色 ?attr/webhtvColorOnWallpaper(#FFFFFF),两种明暗
表取值相同;实机实测同一底上由 1.4:1 提升到 7.42:1。HistoryAdapterTest 增加守卫,
固定集数行与标题行必须使用该角色。

Verification: unit: :app:testMobileArm64_v8aDebugUnitTest runs 4919 tests; HistoryAdapterTest(3) incl. the new episode-line foreground-role guard passes; the only 5 failures are in 4 unrelated source-scan suites (TmdbSourceOnlyInteractionTest, PlayerPlaybackRegressionSourceTest, ReaderPlaybackRoutingSourceTest, WebThemeTokenSourceTest) that read files absent from this diff, so they are pre-existing. device: mobileArm64_v8aDebug APK overwrite-installed (-r, no uninstall) on 192.168.50.3:5557 where the signature hash 4dbe7298 matches the local debug key; HistoryActivity episode line measured white #FFFFFF on the info fill over the dream-purple default wall = 7.42:1 (old ?attr/colorOnSurfaceVariant #44474F = 1.40:1; user screenshot 1.40:1), and 9.4-11.2:1 on the emulator's as-found aurora-glass wall. Emulator wall pref restored to the as-found value 10.

Task-Guard: HIST-REMARK-CONTRAST-20261008
2026-10-08 20:39:43 +08:00
Silent1566
23e5280f37 修复:拖拽进度时加载中/网速大概率不显示
现象:拖动播放进度条后,加载圈(转圈+网速)基本不出现或一闪即没。

根因是本地 seek 专属进度控制与加载圈兜底之间的时序竞态:
CustomSeekView.onScrubStop -> seekListener.onSeekStarted() 先亮圈,showProgress()
随即 App.post(mR2/mR3, 0) 立刻投递网速 ticker,而 seek 命令要等这一跳之后才提交。
ticker 第一跳执行 hidePlaybackProgressIfStale(),此时引擎仍报 READY,于是把刚亮起的
圈收掉。次生缺口:onStateChanged(STATE_READY) 与 onControllerReadyReconciled() 也会
无条件收圈,引擎在 seek 生效前的那次 READY 读数同样收圈。

上游取证:webhtv/Silent1566 与 main 等全部分支均无 seek 专属窗口(onSeekStarted /
SeekListener / mSeekProgressFallback 命中数 0),上游的圈纯由 BUFFERING 状态驱动,
且上游没有本地 2839bb40955/4e303d30d34 这两个提交。故不照搬上游(无对应代码可摘,
回退到纯状态驱动会丢掉已交付的本地 seek 进度控制与加载圈兜底),而是按上游语义在本地
补上窗口这一环。

修法:seek 期间打开「最小可见 + 确实可收」窗口,无新增生产类。
- 新增 SEEK_PROGRESS_MIN_VISIBLE_MS = 1200L 与 mSeekProgressPending/StartedAtMs。
  取 1200ms 而非 500ms:网速读数由 PlaybackSpeedMeter 相邻两次采样的字节差算出,
  setTraffic 每秒一跳且每次 hideProgress 都 Traffic.reset() 重设基线,首跳必然空白,
  窗口盖不过一跳则圈虽停留、网速仍渲染不出来,只修到诉求的一半。
- onSeekStarted() 先开窗口再 showProgress()(顺序关键,后者会立刻投递 ticker),
  最后挂最小可见计时器。
- 新增 canHideSeekProgress():未开窗口放行;开着则要求已过最小可见时长、播放器有效、
  READY 且不在真实加载阻塞中(!isLoading() || isPlaying())。
- hidePlaybackProgressIfStale()(症状的直接执行者)、onStateChanged(READY)、
  onControllerReadyReconciled()、hideSeekProgressIfReady() 统一走该闸门。
- hideProgress() 同时关窗口(音频舞台路径借此自动收口);showProgress() 在窗口开着时
  不摘掉最小可见计时器。
- 曾写 200ms 重试后移除:网速 ticker 在圈可见期间本就每秒重判,自发重试会在播放器长期
  报 loading 时变成每秒 5 次的空转唤醒,故窗口收尾只保留计时器 + ticker 两条路径。

有意接受的代价(测试已锁定):缓冲内瞬时 seek 也会多显示约 0.7s 的圈,方向偏向「显示」
而非「不显示」,与诉求一致,不涉及功能或数据。

范围:仅两个 flavor 的 VideoActivity 与测试;未改 native/AAR/依赖/构建配置。
TmdbDetailActivity 内嵌播放器未覆写 onSeekStarted、加载态纯由 isLoading() 驱动,
不存在同款竞态,故未纳入。

Verification: 双 flavor arm64 Debug Java 编译 BUILD SUCCESSFUL;C47SeekLoadingProgressSourceTest 5x2=10、VideoActivityLayoutTest 154、PlaybackOwnershipSourceTest 15x2=30,合计 194 次用例执行 0 failure 0 error 0 skipped(真实执行);两处变异精确命中并已按 md5 恢复(删 hidePlaybackProgressIfStale 的 seek 闸门 -> '网速 ticker 不得收掉挂起的 seek' 变红;最小可见时长 1200->500 -> '须盖过一个网速采样间隔' 变红);git diff --check clean;全仓测试源集无其它用例钉住旧 500ms 形状;未做真机观感验收(本工作区分配的口 192.168.50.3:5561 多次连接被拒,其余端口属其它工作区未占用);未打正式包

Task-Guard: C47
2026-10-08 19:50:03 +08:00
Silent1566
b8adf3cc1c merge: 合并 origin/beta 最新代码(PR#421 站点注入搜索与手机缓存排版)并复评自动下一集黑屏修复 2026-10-08 19:48:17 +08:00
Silent1566
5096941a40 修复自动下一集黑屏:Surface 未绑定到重建后的引擎
自动下一集换集时 PlayerManager.clear() 先把 spec 置空,preparePlayer() 随后重建
引擎并回调 onPlayerRebuild();此时 isOwner() 为 false,setRender() 整段被跳过,
render 值不变。attachSurface() 原来只按“PlayerView.getPlayer() 是否为空”判断,
而 View 上仍挂着上一集已 release() 的旧引擎(非空),于是新引擎从未拿到 Surface:
解码器能初始化、能到 READY、音频正常,但零视频帧 —— 表现为有声音、全黑无画面,
必须手动切换播放核心或软硬解才恢复(两者都会重新走 onPlayerRebuild → setRender
→ detach+attach,顺带完成缺失的重绑)。

改为按引擎实例身份判断并强制重绑:同引擎跳过(未重建时的正常换集行为完全不变),
不同引擎先 setPlayer(null) 再 setPlayer(next)。

用户设备修复前日志确证:换集边界 render=0/target=0 使重绑分支被跳过、无
"attach after setPlayer"、READY 后长时间无 first-frame;随后一次偶然的引擎重建
重新绑定后立刻出现首帧。该偶然重建来自已被 56ebd07f1 整体删除的音频指纹去广告
rebuildAudioPipeline(),这正是缺陷在近期才频繁出现的原因。

Verification: PlaybackOwnershipSourceTest 16/16 通过(新增 kernelRebuildBindsTheNewEngineToThePlayerViewByInstanceIdentity);revert 生产改动后该用例 FAILED,证明确实锁定本次修复;双 flavor Java 编译 BUILD SUCCESSFUL;scripts/build_arm64_debug_install.sh --flavor mobile --serial 192.168.50.3:5555 构建成功并 install -r 覆盖安装(未卸载),启动与界面渲染正常、logcat 无 FATAL EXCEPTION

Task-Guard: autonext-black-screen

Verification: PlaybackOwnershipSourceTest 16/16 passed (new kernelRebuildBindsTheNewEngineToThePlayerViewByInstanceIdentity); falsified by stashing the production change => that test FAILED; compileMobileArm64_v8aDebugJavaWithJavac + compileLeanbackArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL; build_arm64_debug_install.sh --flavor mobile --serial 192.168.50.3:5555 built and install -r succeeded, app booted/rendered with zero FATAL EXCEPTION

Task-Guard: autonext-black-screen
2026-10-08 19:40:31 +08:00
Silent1566
46917be796
Merge pull request #421 from Silent1566/dev2
merge: 合并 origin/beta 最新代码(音频指纹移除与 T3→T4 本机网关)并复评站点注入搜索/手机缓存排版
2026-10-08 18:56:40 +08:00
Silent1566
1a4d70410c merge: 合并 origin/beta 最新代码(音频指纹移除与 T3→T4 本机网关)
Verification: origin/beta tip 24265785a3 成为合并提交第二父(0 冲突);零复活:beta 上 845 个 revert 类提交触碰路径中 187 个在当前 beta 树已删除,这 187 个在合并树 904ca58f 中复活数 0;被移除的 100 个路径在 dev2 侧本地改动丢失数 0;悬空引用 0(8 个已移除类与 5 个已移除字符串引用数均为 0);路径集合闭合(合并树 vs dev2 并 beta 复活 0 丢失 0);beta 关键文件 build.gradle/libs.versions.toml/Nano.java/PlaybackActivity.java/PlayerManager.java 与 beta 逐字节一致;净差异 16 路径 0 删除;git diff --check 退出码 0;双 flavor Java 与 androidTest Java 编译 BUILD SUCCESSFUL;双 flavor 全量单测 mobile 4919/7 leanback 4078/8 与基线失败集合逐条一致(零新增回归);定向契约测试 204 用例 failures=0 errors=0(含 VodApiTest 31/31);UI token 门禁 violations=1 hex_layouts=1 hex_drawables=0 与基线完全一致(零新增违规);双 flavor debug APK 打包 BUILD SUCCESSFUL;TV 192.168.50.3:5557 实机覆盖安装启动 FATAL=0,首页与去广告页正常且音频检测分组已移除无空分组,设备内真实 HTTP 调用验证 T3 到 T4 网关 ac=config 返回 200 与完整 type4 站点信封且 key 正确 URL 编码、ac=detail 返回苹果CMS 列表信封、OPTIONS 返回 204、相邻端点未被误路由;手机实机启动 FATAL=0,缓存弹窗模块竖排且窄屏 720x1600+320dpi+1.3x 字体下底部策略行与三档清理按钮刷新确定完整可见;设备 wm size/density/font_scale 已恢复;两轮评审均未发现必修问题

Task-Guard: C47-beta-merge-review-dev2
2026-10-08 17:59:32 +08:00
Silent1566
74c39d6dea docs(c46): 记录 dev2 合并 beta 与站点注入搜索/手机缓存排版的评审与验证
Verification: origin/beta tip d8daedf86c 为 HEAD 第一父(合并完整);零复活:267 个 revert 类提交 x 742 路径中 55 个 beta 已删除路径在 HEAD 复活数 0,6 个净差异新增路径在 beta 全历史条目数均为 0;beta 增量零丢失(5054 路径 0 缺失);净差异 15 路径 0 删除;冲突 0 / 冲突标记 0;git diff --check 退出码 0;双 flavor Java 与 androidTest Java 编译 BUILD SUCCESSFUL;双 flavor 全量单测 mobile 5220/7 leanback 4379/8,与基线 d8daedf86c 失败集合逐条一致(零新增回归);定向契约测试 326 用例 failures=0 errors=0;UI token 门禁 violations=1 hex_layouts=1 hex_drawables=0 与基线完全一致(零新增违规);TV 192.168.50.3:5557 实机覆盖安装启动 FATAL=0、站点注入搜索过滤生效(2 条到 1 条)、无匹配空状态可见、缓存弹窗保持 TV 横排;手机实机模块竖排且窄屏 720x1600+320dpi+1.3x 字体下底部控件完整可见;设备 wm size/density/font_scale 已恢复;两轮评审均未发现必修问题

Task-Guard: C46-beta-merge-review-dev2
2026-10-08 17:11:01 +08:00
Silent1566
24265785a3
Merge pull request #419 from Silent1566/dev3
dev3:合并 beta 最新代码(PR#417/#418)并复评 T3→T4 本机网关
2026-10-08 16:59:49 +08:00
Silent1566
6d11b98128
Merge pull request #420 from Silent1566/dev1
移除音频指纹去广告与语音广告识别(含 C46 复评补齐两处遗留缺口)
2026-10-08 16:57:03 +08:00
Silent1566
2283e15d13 docs(c46): 修正 revert 检测口径与净差异路径计数
上一版把检测器写成 git log --grep='回退|revert'(未锚定),
grep 会匹配提交正文,而本任务 5d4a7e8e18 的正文恰好含
「258 个 revert-like 提交、1144 条被触及路径」,其中一行以 revert 开头,
导致本任务自己的提交被误判为 revert 提交,进而把本任务文档
docs/C46-…md 误报为「复活路径」。

修正:
1. 检测器改为只匹配主题行(%s)并锚定开头,得到 109 个 revert 提交、
   725 条被触及路径、601 条不在 beta 树、在 HEAD 树存在 = 0;
2. 记录两次误报(MSYS 路径转换、本提交正文被 grep 命中)的成因与排除方式;
3. 把过时的「净差异 5 个路径」订正为 6 个(5 个功能路径 + 本任务文档);
4. 修正标题层级以满足 markdownlint。

仅文档改动,未修改生产代码。

Verification: documentation-only correction: replaced the over-broad revert-commit detector (git log --grep matched commit bodies, so this task's own merge message containing the word 'revert' was misclassified) with a subject-anchored definition (109 revert commits / 725 touched paths / 601 absent from beta tree / 0 revived); cross-checked by excluding this task's 3 commits (0 revived) and confirmed the flagged file never existed on origin/beta; also corrected stale '5 paths' to '6 paths' net-diff figures and heading level for markdownlint

Task-Guard: C46-revival-count-correction
2026-10-08 16:55:50 +08:00
Silent1566
c2761b2ff6 docs(c46): 记录交付坐标(提交 cd88c907d / tag / PR #420)
- 提交 cd88c907d9
- recovery tag recovery/C46-beta-merge-review-dev1/20261008164917-cd88c907d912
- dev1 已推送至 origin/dev1(0 ahead / 0 behind)
- PR #420 dev1 -> beta:OPEN、未合并(merged=false、merged_at=null)、MERGEABLE、122 文件 +323 -24844
- PR 文件集经 gh api 分页校验与 git diff --name-only origin/beta dev1 逐项一致

Task-Guard: C46-beta-merge-review-dev1-doc-closure

Verification: 纯文档收口:仅记录已确认的提交、recovery tag、推送与 PR#420 坐标(merged=false / merged_at=null / MERGEABLE / 122 文件),无代码或行为变更;PR 文件集经 gh api 分页校验与本地净差异逐项一致

Task-Guard: C46-beta-merge-review-dev1-doc-closure
2026-10-08 16:51:24 +08:00
Silent1566
5e4cc37ba5 docs(c46): 记录 Nano 资源回退分支的可证伪区分证据
前一条记录只写了「回退资源与内置 asset 逐字节一致」,但设备上
/storage/emulated/0/WebHTV/EnvFiles/T4Proxy.js 已被 LabActivity 同步存在,
该结果无法区分命中新增回退分支还是原有 Local 外置文件分支。

补充移走外置文件的可证伪验证:
- 外置存在 -> 由 Local 分支服务(sha256 同);
- 移走外置 -> 由新增回退分支服务内置 asset,sha256 字节一致(改动前该 URL 为 404);
- 写入哨兵内容 -> 返回哨兵原文,用户脚本未被覆盖;
- 恢复外置文件 -> 设备状态复原。

仅文档改动,未修改生产代码。

Verification: documentation-only follow-up commit recording the Nano fallback-branch discriminating evidence (moved the external /storage/emulated/0/WebHTV/EnvFiles/T4Proxy.js away and confirmed HTTP 200 serving the built-in asset byte-identically, plus sentinel test proving user scripts are not overwritten); no production code changed

Task-Guard: C46-fallback-evidence
2026-10-08 16:49:38 +08:00
Silent1566
cd88c907d9 docs(c46): 复评 beta 合并后的 C45 交付并补齐两处遗留缺口
合并状态:origin/beta tip d8daedf86 已是 dev1 祖先(dev1..origin/beta 计数为 0),
无需合并操作;dev1 = origin/beta tip + C45 单个提交,线性关系。

远端已移除内容零复活(三层证据):
1. 结构性证明:dev1 相对 beta 的 120 个改动路径与 C45 提交改动路径完全一致,
   改动集之外的 4935 个文件 blob 与 beta 100% 相同;
2. 行级扫描:beta 历史 22 个单亲 revert/移除类提交、1686 行被删内容,
   10 行原始命中经甄别全部为 beta 自身后续合法重新引入(三文件与 beta tip 逐字节相同);
3. 净差异核对:dev1 独有且 beta 不含的非空行仅 20 行,全部来自 C45 自身改写。

复评发现并修复两处真实缺陷(均属 C45 完成度缺口):
- scripts/pull-ad-audio-log.sh:只服务被删功能的孤儿脚本,其依赖的 3 个偏好键
  与 10 个诊断标记在源码中引用数均为 0,上游 Silent1566 亦无此文件 → 删除(-53 行);
- 智能去广-设计文档.md:C45 声明的「决策 F 改写」实际执行成整节删除,而该节描述的
  PlaybackMediaSignalHub/PipelineLease/generation 门控仍被实时字幕使用
  (RealtimeSubtitleController 是现存唯一生产 consumer)→ 以「决策 E」恢复该架构决策。

第 3 轮订正我自己在第 2 轮的超范围恢复:「当前明确不承诺」4 条全部指向已删功能,
C45 删除它是正确的,已撤销恢复。

生产代码零改动:app/src 下本次无任何新增/修改/删除。

Verification: compileLeanbackArm64_v8aDebugJavaWithJavac + compileMobileArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL; testLeanbackArm64_v8aDebugUnitTest 4039 tests + testMobileArm64_v8aDebugUnitTest 4885 tests, 0 failures/0 errors; scripts/check_ui_tokens.sh UI_TOKEN_STATUS PASS (violations=1 为预先存在的 item_following.xml,不在改动集内); scripts/build_arm64_debug_install.sh --flavor mobile --serial 192.168.50.3:5555 BUILD SUCCESSFUL + 覆盖安装 Success; 设备冷启动无 FATAL/ClassNotFound/InflateException,设置页摘要「总开关、规则、片头片尾」,去广告子页仅基础/规则与统计/片段跳过三组,ad_audio*/speech_ad* 偏好键计数 0 而 adblock/ai_ad_detection/auto_skip_intro_outro 保留; git diff --check clean

Task-Guard: C46-beta-merge-review-dev1

Verification: 双 flavor Java 编译 BUILD SUCCESSFUL;双 flavor 全量单测 4039+4885 全通过 0 失败 0 错误;UI token 门禁 PASS 相对基线零新增违规;零复活三层程序化校验通过(改动集外 4935 文件 blob 与 beta 100% 相同,复活行 0);功能层残留引用 0;mobile 覆盖安装成功且冷启动无崩溃、设置页无音频识别项、ad_audio*/speech_ad* 偏好键计数 0

Task-Guard: C46-beta-merge-review-dev1
2026-10-08 16:49:17 +08:00
Silent1566
5d4a7e8e18 merge: 合并 origin/beta 最新代码(PR#417/#418)并复评 T3→T4 本机网关
纳入 beta 唯一实质增量 6e667a236f:gradle/gradle-daemon-jvm.properties
从已下架的 JetBrains JBR 21 硬钉改为「Java 21、任意厂商」并重新生成
10 个有效下载地址,修复 CI 在测试前即中断的问题(旧 toolchainVendor=JETBRAINS
已移除,实测 ./gradlew --version 显示 Compatible with Java 21, any vendor)。
0 冲突、0 冲突标记。

复评 dev3 全部已修改代码(含已提交未推送的 c388619629 T3→T4 本机网关),
4 轮评审全部通过,未发现必修问题,本任务未修改任何生产代码。

远端已移除/回退内容零复活:全 refs 258 个 revert-like 提交、1144 条被触及
路径逐条比对,合并索引树相对 origin/beta 复活数 = 0;净差异 5 个路径与
revert 路径集交集为空。检测器已用「注入伪造树」反证有效(能正确报出
ISSUE_TEMPLATE),故 0 复活非空转结论。

验证:
- VodApiTest 31 tests / 0 skipped / 0 failures / 0 errors;
- 双 flavor Java 与 AndroidTest 编译 BUILD SUCCESSFUL;
- node --check、git diff --check、冲突标记扫描均通过;
- UI token 门禁 violations=1,为既有 item_following.xml,相对 beta 零新增;
- 实机 192.168.50.3:5559 端到端:170 个站源、真实站源搜索/详情/播放/分类
  与 base64 ext 筛选全部正常,内部 site/tmdb 字段未泄漏;
  /file/WebHTV/EnvFiles/T4Proxy.js 回退资源与内置 asset 逐字节一致。

净差异(相对 origin/beta)仅 5 个路径,全部为 dev3 自身改动:
T4Proxy.js、Nano.java、VodApi.java、VodApiTest.java、docs/C45-t4-api-gateway.md。

Verification: merge origin/beta d8daedf86c (0 conflicts, 1 path: gradle/gradle-daemon-jvm.properties); zero revived remote-removed paths (1144 revert-touched paths scanned, detector self-test with injected fake tree reports REVIVED; net diff vs origin/beta disjoint from revert set); beta increment and dev3 changes lossless (per-path SAME); VodApiTest 31 passed 0 failures; dual-flavor Java+AndroidTest compile BUILD SUCCESSFUL; gradlew --version shows 'Java 21, any vendor'; node --check passed; UI token gate relative to beta zero new violations; device 192.168.50.3:5559 e2e: 170 sites, real-source search/detail/play/category/ext filter, asset fallback byte-identical; git diff --check clean; no conflict markers

Task-Guard: C46-beta-merge-review-dev3-20261008
2026-10-08 16:43:37 +08:00
Silent1566
56ebd07f10 移除:删除音频指纹去广告与语音广告识别功能,向 Silent1566 上游靠齐
删除 app/src/main/java/com/fongmi/android/tv/ad/audio 全部 45 个类与其 37 个测试类、
AdSkipPromptPresenter、SpeechRecognitionFactory、RealtimeSubtitleSpeechRecognitionFactory,
以及 speech_ad_rules_v1.txt、probe-rules-v1-community.json 和 11 个只服务于这两个功能的文档。

清理接线:PlayerManager 的 AdAudioRuntimeController/AdAudioPlaybackPort/管线重建预算与
refreshAdAudioRuntime 调用;PlaybackActivity 的 AdSkipPromptPresenter 绑定;Backup 的
SpeechAdSetting.sanitizePreferences 通道与三个 speech_ad 偏好键;PlaybackMediaSignalHub
的 AD_AUDIO consumer 种类;RealtimeSubtitleRecognizer 的 AD_AUDIO 执行 profile。

设置页删除音频识别分组(指纹开关、自动跳过、社区规则源、语音开关/关键词/规则/时长/模式),
三套 strings.xml 各删 66 条键并把去广告摘要改为“总开关、规则、片头片尾”。
移除仅被签名规则包使用的 Tink 依赖。

保留接口/HLS/AI 规则去广告、广告统计、片头片尾区间跳过与实时字幕;PCM Hub 与
rebuildAudioPipeline 仍由实时字幕使用,故未删除。

Verification: compileLeanbackArm64_v8aDebugJavaWithJavac + compileMobileArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL; testLeanbackArm64_v8aDebugUnitTest 4039 tests + testMobileArm64_v8aDebugUnitTest 4885 tests, 0 failures/0 errors (--rerun-tasks, full re-run); targeted bean/setting/player.audio/subtitle suites 0 failures; scripts/build_arm64_debug_install.sh --flavor mobile --serial 192.168.50.3:5555 BUILD SUCCESSFUL + overwrite install Success; device cold start no crash/no FATAL/no ClassNotFound, Ad settings page shows only Basic/Rules+stats/Segment-skipping, prefs ad_audio*/speech_ad* count 0 while adblock/ai_ad_detection/auto_skip_intro_outro intact; residual AdAudio|SpeechAd|AudioFingerprint|ProbeRule|AdSkipCoordinator|SpeechRecognitionFactory references 0 in app/src and docs/; git diff --check clean

Task-Guard: C45-remove-ad-audio-fingerprint-speech
2026-10-08 14:53:45 +08:00
Silent1566
c388619629 feat(server): add local T3-to-T4 gateway with HTTP contract coverage
Verification: VodApiTest: 31 passed, 0 failures (real NanoHTTPD-to-Spider fixture); Node HTTP contract: 10 scenarios passed; node --check, scoped Java LSP and git diff --check passed; single-use build/test servers closed; app/build and build cleaned; no APK/device testing

Task-Guard: C45-t4-api-gateway
2026-10-08 14:52:04 +08:00
Silent1566
ce01b45c3c merge: 合并上游 webhtv/webhtv Silent1566 站点注入搜索与手机缓存排版修复
上游 3 个提交(58ebb653ff/7357b2c37d/05469a967a)全部纳入:站点注入弹窗搜索与空状态、手机窄屏缓存管理排版修复。

解决 CacheManagementDialog 唯一 import 冲突:取上游 Util(mobile 分支必需),拒绝带回 MaterialAlertDialogBuilder,保留本地 WebHtvAlertDialogBuilder 主题契约。

按强制评审结论做最小本地适配:6 处硬编码颜色改为本地语义 token(?attr/colorOnSurface / colorOnSurfaceVariant / colorSurfaceContainerHighest),上游测试主题基座改为本地 Theme.WebHTV.Dialog(M2 主题缺 colorOutline 会导致布局 inflate 失败)。

Verification: 上游 tip 05469a967a 成为第二父;1 冲突(import)解决且 0 残留冲突标记;上游 14 路径全部落地(6 新增/8 修改/0 删除,6 条缺失行均为评审结论下的语义 token 与测试主题基座有意改写);本地既有改动零丢失(7 交集路径逐行核对,2 行为 mobile 参数化预期改写);双 flavor Java 与 androidTest Java 编译 BUILD SUCCESSFUL;双 flavor 全量单测相对合并前 worktree 基线零新增失败(leanback 基线 9→8、mobile 5217/7→5220/7 失败集合逐条一致);定向 27 类 176 用例 failures=0;UI token 门禁 violations=1/hex_layouts=1/hex_drawables=0 与基线完全一致(零新增);TV 192.168.50.3:5557 实机覆盖安装启动无 FATAL、设置页缓存行与缓存弹窗 TV 横排正常、站点注入搜索框渲染且过滤生效、无匹配空状态可见;手机实机缓存弹窗模块竖排、窄屏 720x1600+320dpi+1.3x 字体下详情占满宽度且底部策略与清理按钮滚动后完整可见、模块级确认框正常;设备 wm size/density/font_scale 已恢复;git diff --check 通过;全部路径在 app/ docs/ scope 内

Task-Guard: C45-upstream-sync-silent1566
2026-10-08 13:58:40 +08:00
Silent1566
d8daedf86c
Merge pull request #418 from Silent1566/dev1
fix(ci): 修复守护进程 JVM 供给失败导致流水线在测试前中断
2026-10-08 12:13:54 +08:00
Silent1566
6e667a236f fix(ci): 修复守护进程 JVM 供给失败导致流水线在测试前中断
流水线 run 37649723583 在「Run release-critical tests」步骤、尚未执行任何
测试前即失败:

  Unable to download toolchain matching the requirements
  ({languageVersion=21, vendor=JetBrains, implementation=vendor-specific,
  nativeImageCapable=false}) ... Received status code 400 from server: Bad Request

根因:gradle/gradle-daemon-jvm.properties 把守护进程 JVM 硬钉在 JetBrains
JBR 21,而该包已从 foojay 下架。该文件记录的 10 个 api.foojay.io ID 现已
全部失效(逐个返回 HTTP 400「Package id not found」),且 foojay 当前根本
不再发布 JetBrains JDK 21(仅有 11 与 17)。

文件上次生成于 5 月;上一次发布成功是因为 runner 本地缓存中恰好仍有 JBR,
待缓存转冷后才暴露该问题——因此「上次成功/本次失败」之间仓库侧零改动
(同一 blob 5c34300fa6)。

修复:
1. 用官方 ./gradlew updateDaemonJvm --jvm-version=21 重新生成该文件,
   10 个下载地址恢复有效(均 HTTP 301,实测可下载真实产物)。
2. 移除 toolchainVendor=JETBRAINS 条件,使 Gradle 接受 setup-java 安装的
   Temurin 21,而不再尝试供给已不存在的 JBR。构建逻辑不依赖 JetBrains 厂商,
   这也正是 Gradle 文档记载的默认行为(默认不生成 vendor 条件)。

验证:
- 以无 jdks/ 缓存的 GRADLE_USER_HOME 在真实仓库复现出与 CI 逐字相同的报错;
- 重新生成的文件与 updateDaemonJvm 规范输出逐字节一致;
- 10 个新地址均解析到真实产物(Linux x86_64 实测 206 + gzip 魔数 1f8b);
- ./gradlew --version 显示「Compatible with Java 21, any vendor」,且未创建
  jdks/(即无需下载);
- 流水线两条 Gradle 命令原样执行均 BUILD SUCCESSFUL:移动端 73 个测试
  (17 个 XML)0 失败 0 错误,Leanback 10 个测试 0 失败;
- git diff --check 干净;仅改动 gradle/gradle-daemon-jvm.properties。

Task-Guard: FIX-CI-DAEMON-JVM-20261008
2026-10-08 12:09:52 +08:00
Silent1566
05469a967a fix: 修复站点注入搜索空状态与排序刷新回归
Verification: 原提交及修复已复评;Robolectric与匹配测试8/8通过(修复前2失败);Leanback Debug Java/资源编译通过;变更Java文件LSP clean;git diff --check通过;一次性daemon已退出

Task-Guard: site-injection-search-review
2026-10-08 11:43:00 +08:00
Silent1566
6e3037c569
Merge pull request #417 from Silent1566/dev3
dev3:合并 beta 最新代码(PR#414-#416)并复评修复 LightDialog 外壳透明度双重施加
2026-10-07 23:30:11 +08:00
Silent1566
f85398d359 merge: 合并 origin/beta 最新代码(PR#414-#416)并复评修复 LightDialog 外壳透明度双重施加
- 合并 origin/beta tip 2fafb302cc(PR#414 短剧源禁用、PR#415 episode 并发、PR#416 弹窗 tint 泄漏),0 冲突
- 按 beta 当前权威树处置历史回退项:SpiderCrashBreadcrumb 等 3 个路径不复活
- LightDialog 抽出唯一外壳形状源 shell(),外壳保持不透明,dialogOpacity 只由
  ThemeBinder.bindWindowBackground 施加;修复 0.70 被算成 0.49,以及半透明填充
  失去基线角色匹配导致 surfaceContainerHigh 用户覆写无法到达该外壳
- 新增 LightDialogShellOpacityTest(2 用例,反证可失败)与 ThemeBinderContractTest 反预乘断言

Verification: C44 dev3 beta 合并复评:合并 0 冲突(第二父=origin/beta tip 2fafb302cc);beta 增量 13 路径零丢失、dev3 既有 12 路径零丢失(三方逐文件一致);远端已回退内容零复活(341 路径扫描 0 复活,检测器自检可报 REVIVED,含 790d678c9e 的 SpiderCrashBreadcrumb 3 路径未带回);第 1 轮发现并修复 LightDialog 外壳 dialogOpacity 被应用两次(0.70 -> 0.49)且半透明填充失去角色匹配导致 surfaceContainerHigh 覆写失效,新增 LightDialogShellOpacityTest 2 用例并反证可失败;第 2/3 轮复评无新增必修问题;leanback 4371 用例/6 失败、mobile 5217 用例/5 失败,失败集合与本机 CRLF 基线的既有集合逐条一致且涉及 23 个源文件相对 origin/beta 与合并前 HEAD 均逐字节一致;双 flavor Java + AndroidTest Java 编译 BUILD SUCCESSFUL;check_ui_tokens --strict violations=1 为既有 mobile/item_following.xml 零新增;git diff --check 0;设备 192.168.50.3:5559 leanback 覆盖安装(未卸载)实测显式深色与显式浅色两种模式:ChoiceDialog 聚焦 6.39/5.23、常规 12.14/14.73、面板标题 10.48/13.99,LightDialog 外壳跟随当前模式;设备偏好已逐键还原(296 键仅 2 个运行时缓存键自然变化)

Task-Guard: C44-beta-merge-review-dev3-20261007
2026-10-07 23:21:27 +08:00
Silent1566
7357b2c37d feat: add site injection search
Verification: CustomCspSettingTest passed; :app:testMobileArm64_v8aDebugUnitTest passed with mobile Java/resource compilation; git diff --check passed; regenerated app/.cxx remains protected and uncommitted

Task-Guard: site-injection-search
2026-10-07 21:49:46 +08:00
Silent1566
2fafb302cc
Merge pull request #416 from Silent1566/dev2
merge: 合并 origin/beta 最新代码(PR#412-#415)并修复弹幕接口弹窗 tint 泄漏
2026-10-07 19:54:09 +08:00
Silent1566
fb5f2a03df merge: 合并 origin/beta 最新代码(PR#412-#415)并复评弹幕弹窗 tint 泄漏修复
Verification: 合并 origin/beta(056200cda0) 0冲突;回退内容零复活(124移除类提交x361路径 + 5682f2b05x70路径 blob级比对=0);beta 5045路径零丢失;dev2 4路径零丢失;三方合成文件0;net-diff 4路径全为dev2自身改动;mobile 5216用例/5失败=基线5199/5零新增回归;leanback 4365/6=基线4351/6零新增回归;双flavor androidTest编译成功;定向171用例0失败;设备192.168.50.3:5557 DanmakuApiDialogDeviceTest OK(3 tests) 且RED反证1 failed;UI token violations=1=基线零新增;git diff --check退出0

Task-Guard: C44-beta-merge-review-dev2
2026-10-07 19:49:18 +08:00
Silent1566
fb85759b03 fix(tv): 主题模式解析与选项弹窗跟随活动调色板
- ThemeController 使用显式 theme_mode 解析,显式浅/深色覆盖系统
- ChoiceDialog 选项按钮与弹窗根背景改用 ThemeController.current() token
- 自定义 Dialog 入口补 ThemeController.bindDialog
- 新增 AppearanceRowThemeTest#choiceItemsUseTheActivePaletteInBothModes 契约

Verification: TV-THEME-MODE-DARK-20261007: 定向 JVM 测试通过(leanback com.fongmi.android.tv.theme.* + ui.dialog.* 共 210 用例,唯一失败 DialogRoundedCornerSourceTest 为 beta 侧既有 CRLF 脆弱断言,与本改动零交集);ChoiceDialog 选项按钮 token 化对比度实测 浅/深 = 聚焦 6.39/7.50、选中 12.57/7.04、常规 14.73/12.14,禁用 2.12/2.67(与修复前 2.37 同口径);已按 beta 侧 C33/C35/C37/C39 既有记录处置,不扩界修改

Task-Guard: TV-THEME-MODE-DARK-20261007
2026-10-07 19:36:13 +08:00
Silent1566
10daccd631 fix(tv): honor explicit dark and light theme modes
Verification: ThemeController now resolves explicit theme_mode before system mode; ThemeDialogModeTest and ThemeControllerContractTest passed; full Leanback theme suite passed; leanback arm64 Debug built and adb install -r succeeded on 192.168.50.3:5559; temporary verification files removed

Task-Guard: TV-THEME-MODE-DARK-20261007
2026-10-07 17:30:50 +08:00
Silent1566
7169eddc35 fix(tv): theme appearance dialog shell
Verification: Leanback theme suite 159 tests passed; leanback arm64 Debug built successfully; adb install -r succeeded on 192.168.50.3:5559; rebuilt app launched stably; temporary screenshots removed; diff check passed

Task-Guard: TV-THEME-DIALOG-20261007
2026-10-07 16:04:35 +08:00
Silent1566
756f164ab3 fix(tv): persist theme editor light and dark mode
Verification: Leanback theme suite passed; focused mode persistence and flavor contract tests passed; leanback arm64 debug built and adb install -r succeeded on 192.168.50.3:5559; worktree diff check passed

Task-Guard: TV-THEME-MODE-20261007
2026-10-07 15:19:08 +08:00
Silent1566
a10322a75c docs(danmaku): 记录提交 7596ebabb7 与恢复标签 2026-10-07 14:27:20 +08:00
Silent1566
7596ebabb7 fix(dialog): 弹窗改用主题覆盖层,阻止控件 tint 泄漏到系统编辑菜单
BaseAlertDialog.builder() 此前把圆角面板控件样式 MaterialAlertDialog_WebHTV_Rounded
作为 themeResId 传入,使其 backgroundTint 成为对话框上下文级属性,并被系统浮动编辑菜单
(复制/粘贴)的 AppCompat ImageButton 继承。vivo 绘制类在 mutate() 该背景时抛出
ClassCastException,导致弹幕接口输入处长按即崩溃。

圆角本已由 ThemeOverlay.WebHTV.Dialog 的 alertDialogStyle 指向同一控件样式,
面板外观不变;改用主题覆盖层后 tint 不再泄漏。

验证:
- 新增设备回归 DanmakuApiDialogDeviceTest(tint 不泄漏、面板样式仍为 Rounded、
  复制/剪切/粘贴、浮动工具栏可创建、保存与取消、IME 完成),旧代码 RED、新代码 OK (3 tests)。
- DialogRoundedCornerSourceTest 收紧为断言主题覆盖层,mobile/leanback 均通过。

限制:本地为 Android 9 模拟器,未在 vivo V2307A / Android 14 真机复测。

Verification: 手机源码回归 testMobileArm64_v8aDebugUnitTest DialogRoundedCornerSourceTest 2/2 通过;TV 源码回归 testLeanbackArm64_v8aDebugUnitTest 同用例 2/2 通过;192.168.50.3:5557 设备回归 DanmakuApiDialogDeviceTest OK (3 tests);旧代码上两项均 RED(源码断言命中 theme overlay,设备断言命中 panel backgroundTint leaked into system text actions);覆盖安装未清除应用数据

Task-Guard: FIX-DANMAKU-VIVO-20261007
2026-10-07 14:26:36 +08:00
Silent1566
056200cda0
Merge pull request #415 from Silent1566/dev4
合并 beta 最新代码并修复剧集列表并发修改崩溃
2026-10-07 14:24:03 +08:00
Silent1566
2b10824361 merge: 合并 origin/beta 最新代码并修复 episode 列表并发
Verification: 合入 origin/beta 6ff6a4458cf;无冲突;PR 净差异仅 SourceEpisodeSeasonCache.java、TmdbEpisodeSorter.java、SourceEpisodeSeasonCacheTest.java 与 C43 文档;beta 已删除的 SpiderCrashBreadcrumb.java、其测试及 SPIDER-CRASH-DIAG 文档均未复活;最新 beta(含 PR#414)移动/Leanback 定向 JVM 测试、双 flavor Java/AndroidTest Java 编译 BUILD SUCCESSFUL;gradlew.bat clean BUILD SUCCESSFUL;git diff --cached --check 通过

Task-Guard: C43-beta-merge-review-dev4
2026-10-07 14:14:22 +08:00
Silent1566
6ff6a4458c
Merge pull request #414 from Silent1566/dev1
merge: 合并 origin/beta 最新代码(PR#412/#413)并复评补齐短剧源禁用契约
2026-10-07 13:08:54 +08:00
Silent1566
d1b7e2750e docs(c42): 记录 dev1 交付坐标并订正合并树与提交树
合并结果树 de7921410 是任务文档写入前用于逐字节比对的索引树;提交树含文档故为 4351c0f。补记提交、recovery tag、推送与 PR #414 坐标。

Task-Guard: C42-beta-merge-review-dev1
2026-10-07 13:07:18 +08:00
Silent1566
84d76f4c59 merge: 合并 origin/beta 最新代码(PR#412/#413)并复评补齐短剧源禁用契约
## 合并

- 合并 origin/beta tip 2a2139beb(Merge PR #413 from dev3),纳入 10 个提交
  (PR#412 播放加载圈守卫、PR#413 TV 固定深色面板对比度回归修复)
- 0 冲突、0 冲突标记,19 路径自动合入,合并树 de7921410
- beta 增量 19 路径逐字节一致、dev1 既有改动 3 路径逐字节一致

## 远端已移除内容零复活(用户核心关注点)

- 116 个 revert/移除类单亲提交零复活:550 文件版本、117040 行扫描、复活 0 行
- 远端剔除提交 5682f2b05(剔除 PR #353 主题系统改动)触碰的 70 个路径
  与 origin/beta 逐字节一致,旧主题系统文件在两侧同为缺席

## 评审修复(第 1 轮发现,第 2/3/4 轮订正后通过)

- 补齐短剧源规则契约的第三个站点:ShortDramaSourceDialog.showSiteManage()
  曾用 tempEnabledRules.isEmpty() 回填默认关键词,用户清空规则后打开一次
  「站点管理」即被重新勾选写回,用户报告的「短剧源无法禁用」从该路径复现,
  而原测试只钉住了 show() 与 resetToDefault() 两处,抓不到
- 改为钉语义不变量:空规则判定式与 defaultRulesText() 必须彻底消失、
  defaultRules() 合法入口不超过「未配置初始值」与「恢复默认」两处
- 按仓库既有约定加 codeOnly() 剥注释,避免契约匹配到说明文字
- 本任务未改动任何生产源码:两个生产文件与 6414185af 及合并索引逐字节一致

## 验证

- 双 flavor Java 与 androidTest 编译 BUILD SUCCESSFUL
- 全量单测 mobile 5214 / leanback 4365,零失败零错误
- 三次注入反证(第三处 defaultRules() 兜底、isEmpty+defaultRulesText 旧写法、
  去掉 isConfigured() 初始值)均使契约 FAILED,证明非空转,注入已完全回滚
- UI token 门禁 violations=1(既有 item_following.xml,不在本次净差异)

Verification: 合并 origin/beta 2a2139beb(PR#412/#413)0 冲突;beta 增量 19 路径零丢失、dev1 增量 3 路径零丢失;116 个 revert/移除类提交零复活(550 文件版本/117040 行扫描);远端剔除提交 5682f2b05 触碰的 70 路径与 origin/beta 逐字节一致(零带回);双 flavor Java+androidTest 编译 BUILD SUCCESSFUL;全量单测 mobile 5214 / leanback 4365 零失败零错误;ShortDramaConfigTest 双 flavor 各 3 tests 通过,三处注入反证均 FAILED 后已完全回滚(生产源码与 6414185af 逐字节一致);UI token 门禁 violations=1 且唯一违规 item_following.xml 不在本次净差异中(相对基线零新增);git diff --check 退出码 0、无冲突标记

Task-Guard: C42-beta-merge-review-dev1
2026-10-07 13:05:22 +08:00
Silent1566
2a2139bebc
Merge pull request #413 from Silent1566/dev3
merge: 合并 origin/beta 最新代码(PR#410/#411/#412)并复评修复 TV 固定深色面板对比度回归
2026-10-07 11:35:34 +08:00
Silent1566
12f2639b8d merge: 合并 origin/beta 最新代码(PR#410/#411/#412)并复评修复 TV 固定深色面板对比度回归
Verification: 合并 origin/beta tip 53b54d1b6(PR#410/#411/#412)0 冲突,合并树 3005b6f2a 与 merge-tree 预测一致;26 个 beta revert 提交移除内容零复活;复评发现并修复合并引入的 TV 固定深色面板对比度回归(5 处:dialog_exit_confirm/dialog_display/dialog_disc_menu/dialog_audio_comment/adapter_tmdb_recommendation_landscape,实测 1.02-3.10:1 -> 6.39-19.80:1);新增 TvFixedDarkSurfaceContrastTest 4 用例(含合成探针,反证可失败);全量 JVM leanback 4362 / mobile 5211 零失败;check_ui_tokens.sh --strict violations=1 legacy=0 hex_colors=0 相对基线零新增;设备 192.168.50.3:5559 日间模式复现缺陷并确认修复(主按钮 2.68:1 -> 6.39:1),设备 base.apk md5 1e4dcde4ac3b3deb3513843960f5ecfb 与本地构建产物一致;git diff --check 退出码 0

Task-Guard: C42-beta-merge-review-dev3-20261007
2026-10-07 11:31:58 +08:00
Silent1566
9555806b70 fix: prevent episode list concurrent modification crash
Verification: 定向单测通过::app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.helper.SourceEpisodeSeasonCacheTest --tests com.fongmi.android.tv.utils.TmdbEpisodeSorterTest;9+3 tests passed,Java compile passed;git diff --check passed

Task-Guard: fix-source-episode-concurrency
2026-10-07 11:20:06 +08:00
Silent1566
53b54d1b62
Merge pull request #412 from Silent1566/dev2
dev2:合并 beta 最新代码(PR#411)并复评修复播放加载圈守卫泄漏
2026-10-07 10:55:35 +08:00
Silent1566
3374def641 merge: 合并 origin/beta 最新代码(PR#411)并复评修复播放加载圈守卫泄漏
- 合并 origin/beta tip 9b168a1f38(PR#411),0 冲突;远端 18 个回退提交移除内容零复活
- 复评 dev2 未推送提交 f77c4a0236 时发现真实缺陷:setPlayer 的重复结果早退分支
  未释放 mPlaybackRequestActive,导致 onStateChanged 与 hidePlaybackProgressIfStale
  两个收圈路径同时被挡下,加载圈在「同一结果已在播」时永不清除;改为在该分支内释放守卫
- 同步订正 ReaderPlaybackRoutingSourceTest 中被钉死的单行写法为语义断言,保留「重复结果不得重复起播」口径
- 双 flavor Java/androidTest 编译通过;双端全量 JVM 套件相对合并前基线零新增回归

Verification: :app:compile{Leanback,Mobile}Arm64_v8aDebugJavaWithJavac and :app:compile{Leanback,Mobile}Arm64_v8aDebugAndroidTestJavaWithJavac BUILD SUCCESSFUL; :app:testMobileArm64_v8aDebugUnitTest 5200 tests/6 failed and :app:testLeanbackArm64_v8aDebugUnitTest 4351 tests/7 failed, both failure sets identical to the pre-merge baseline worktree @ f77c4a0236 (mobile 5195/6, leanback 4349/7) => zero new regressions (CRLF-only multi-line source assertions + one load-sensitive flake, all target files byte-identical to origin/beta); 18 beta revert commits x 48 file-versions x 795 removed lines => 0 resurrected; 6 merged paths byte-identical to origin/beta, 2 dev2 paths preserved; merge tree 8d0126b93e == git merge-tree prediction; fix falsification: reverting the duplicate-result guard branch => VideoActivityLayoutTest 154 tests/1 failed (leanbackPlaybackLoadingIgnoresStaleReadyBeforeNewPlayerStarts), and deleting the mobile guard => reclaimedOrRepeatedPlayerResultsAreNotStartedTwice FAILED; check_ui_tokens.sh --strict violations=1 legacy=0 (pre-existing mobile/item_following.xml, zero new) and UI_TOKEN_CONTRAST pairs=38 failures=0; git diff --check clean

Task-Guard: C42-beta-merge-review-dev2
2026-10-07 10:50:03 +08:00
Silent1566
790d678c9e feat(crash): 崩溃页显示最后加载的蜘蛛源,便于定位外部 JAR 缺陷
Verification: leanback+mobile unit tests 7/7 pass; assembleLeanbackArm64_v8aDebug EXIT=0; aapt2 confirms crash_details_spider in 3 locales; dexdump confirms CrashActivity.read() + crash_details_spider ref and JarLoader.record() x1; device 5557 overwrite-install writes cache/spider-last.txt

Task-Guard: SPIDER-CRASH-DIAG
2026-10-07 01:39:37 +08:00
Silent1566
f77c4a0236 fix(tv): keep playback loading visible until new player starts
Verification: :app:compileLeanbackArm64_v8aDebugJavaWithJavac and VideoActivityLayoutTest 154/154 passed; assembleLeanbackArm64_v8aDebug BUILD SUCCESSFUL; install -r on 127.0.0.1:5557 succeeded; gradle clean BUILD SUCCESSFUL

Task-Guard: native-enhanced-loading-spinner
2026-10-07 01:36:29 +08:00
Silent1566
6414185aff 修复短剧源规则无法禁用
Verification: 聚焦单元测试 :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.bean.ShortDramaConfigTest 通过;LSP 变更文件无诊断;mobile arm64 debug 包构建成功并覆盖安装到 192.168.50.3:5555;真实 UI 删除 [短] 与 短剧后保存并重新打开仍为空;bash ./gradlew clean 成功

Task-Guard: short-drama-rules-disable
2026-10-06 23:31:31 +08:00
Silent1566
5ff8037e58 docs(tv): 补充浅色模式路径的设备验证结果
TV flavor 只编译深色 token 表,浅色模式是独立的解析路径,单独在设备上验证
「主题模式=浅色」下的外观与语言对话框:10 个文字区域对比度 6.43-10.49:1,
全部达到 WCAG AA 4.5:1。同时记录测量方法(字形取 max 而非百分位,行带由
纵向扫描实测),避免抗锯齿边缘导致的假阴性。

Verification: 设备实测 192.168.50.3:5559 将主题模式改为浅色后重开外观与语言, 10 个文字区域对比度 6.43-10.49:1 全部达标(WCAG AA 4.5:1); 验证后已把主题模式恢复为跟随系统、界面大小恢复为稍大

Task-Guard: TV-APPEARANCE-LIGHTMODE-VERIFY-20261006
2026-10-06 23:22:11 +08:00
Silent1566
009d708422 docs(tv): 记录最终提交后的设备重新验证结果
清理提交 8624f6c0d 后从最终提交重新打包并覆盖安装,确认设备产物 md5 与构建
产物一致,并重跑完整路径。11 个文字区域实测对比度 6.43-10.49:1,全部达到
WCAG AA 4.5:1 阈值(修复前最差 1.00:1)。

Verification: 从最终提交 8624f6c0d 重新打包并覆盖安装: build_arm64_debug_install.sh --flavor leanback --serial 192.168.50.3:5559 BUILD SUCCESSFUL + install Success; 设备 base.apk md5 691103eb120cacdf17404fa711f8ccae 与构建产物一致; 设备复现首页->设置->外观与语言->界面大小, 11 个文字区域对比度 6.43-10.49:1 全部达到 WCAG AA 4.5:1 (修复前最差 1.00:1)

Task-Guard: TV-APPEARANCE-FINAL-VERIFY-20261006
2026-10-06 22:59:06 +08:00
Silent1566
58ebb653ff fix: repair mobile cache management layout
Verification: Baseline mobile layout instrumentation 4/4 failed with module detail width collapsing to 16px at 320dp/2x font; fixed arm64 mobile APK and AndroidTest built successfully; adb install -r coverage on emulator-5560; fixed CacheManagementDialogLayoutTest 4/4 passed across narrow portrait, 1.3x/2x Chinese font, and English landscape; real 720x1600/320dpi/1.3x UIAutomator and screenshots confirmed full-width module details, readable action rows, and complete bottom actions after scroll; emulator display settings restored; LSP diagnostics clean; diff --check clean.

Task-Guard: mobile-cache-layout
2026-10-06 22:57:32 +08:00
Silent1566
9b168a1f38
Merge pull request #411 from Silent1566/dev1
dev1:合并 beta 最新代码(PR#410 真正打通 TV 浅色模式)并复评线路/选集 chip 底色与浅色光影剧幕中间层
2026-10-06 22:50:37 +08:00
Silent1566
92f9b020f2 docs(c41): 订正净差异路径数为实测 6 并区分是否含本任务文档
Verification: 文档数值订正:C41 记录中「合并结果净差异」原写 5 个路径,实测为 6 个(第 6 个是本任务文档 docs/C41-beta-merge-review-dev1-20261006.md 自身);已改为区分「本任务文档创建前 5 个」与「含文档自身 6 个」,与 git diff --name-only origin/beta HEAD 的实测输出一致。仅改动文档,无代码/资源/行为变更,无需重跑构建与单测。

Task-Guard: C41-doc-precision
2026-10-06 22:42:27 +08:00
Silent1566
8d03e86d82 merge: 合并 origin/beta 最新代码(PR#410 真正打通 TV 浅色模式)并复评
合并 origin/beta @ 414babc1b(PR#410)进 dev1:0 冲突,65 路径自动合入(58 个 leanback 布局、
leanback webhtv_tokens.xml 删除、双 flavor ThemeDialog、ThemeController、webhtv_styles.xml、
LeanbackForegroundContrastTest)。26 个 beta 回退提交零复活(143 文件版本 / 1377 行被移除行逐行扫描)、
beta 增量 65 路径零丢失、dev1 未推送的 5c95aa19c 五路径零丢失。

复评 dev1 全部已修改代码(含已提交未推送的 chip 底色 + 浅色剧幕中间层修复)2 轮,未发现需修改缺陷:
- setChipState 已走 setBackgroundTintList 持久通道;全文件剩余 7 处 setBackgroundColor 均非 chip 填充;
- cinemaLightBackdropShade() 与用户所要求的历史实现(7e42054de^)逐字节一致;
- applyLightCinemaCopyPlate / LightCinemaCopyPlateDrawable 全仓零引用,删除的 7 个 graphics import
  在全文件出现 0 次,未使用 import 数与 origin/beta 持平(均为既有 2 项);
- detailInfo 无程序化 padding/background 写入点,删除羽化底板后无残留副作用;
- beta 新引入的 405 处 leanback 前景迁移逐类核对最近绘制背景:379 处 webhtvColorOnWallpaper 压在
  壁纸/玻璃面板/black_20|black_40 形状上、4 处 player_control_muted 与 12 处 white_70/80/90 全在
  播放器 OSD 内部,两种配色下均为深底,未发现白底白字;
- LeanbackForegroundContrastTest 门禁可失败性已反证(注入 ?attr/colorOnSurfaceVariant 后
  lightCardRowsKeepThePaletteFollowingRole 与 constantLightForegroundsStayOnDarkSurfacesInDayMode
  立即失败),探针已完全回滚。

已记录不修改的边界:LeanbackForegroundContrastTest 的常量浅色前景表未登记 beta 新引入的
white_70/80/90,该测试属 C40/dev2 侧契约,扩大其覆盖面超出本任务范围;实测这 12 处当前全部正确。

Verification: 合并 origin/beta @ 414babc1b 进 dev1:0 冲突、0 冲突标记;26 个单亲 revert 提交 × 143 文件版本 × 1377 行被移除行逐行扫描,复活 0 行 0 文件;beta 增量 65 路径逐文件与 414babc1b 字节一致;dev1 未推送 5c95aa19c 的 5 路径逐文件字节一致;净差异 git diff --name-only origin/beta HEAD 仅 5 路径且全为 dev1 自身改动;revert 补丁可应用性与 origin/beta 同集合(HEAD-only=∅、beta-only=∅)。评审 2 轮未发现需修改缺陷:setChipState 已改走 setBackgroundTintList 且全文件剩余 7 处 setBackgroundColor 均非 MaterialButton chip 填充;cinemaLightBackdropShade() 与 7e42054de^ 历史实现逐字节一致;applyLightCinemaCopyPlate/LightCinemaCopyPlateDrawable 全仓零引用、删除的 7 个 graphics import 全文件出现 0 次、未使用 import 数与 origin/beta 持平;detailInfo 无程序化 padding/background 写入点;beta 新引入 379 处 webhtvColorOnWallpaper + 4 处 player_control_muted + 12 处 white_70/80/90 逐类核对最近绘制背景均为深底,未发现白底白字;LeanbackForegroundContrastTest 门禁可失败性已反证(注入 colorOnSurfaceVariant 后 2 个用例失败,探针已回滚且 diff 为空)。验证:双 flavor Java 与 androidTest 编译 BUILD SUCCESSFUL;:app:testMobileArm64_v8aDebugUnitTest 5199 tests 0 failures 0 errors 2 skipped;:app:testLeanbackArm64_v8aDebugUnitTest 4351 tests 0 failures 0 errors 2 skipped;check_ui_tokens.sh --strict violations=1 legacy=0 相对基线零新增(唯一违规为既有 mobile/item_following.xml);git diff --check 退出码 0。设备 192.168.50.3:5555(API 28 leanback arm64,覆盖安装未卸载,经 HomeActivity 正常路径进入详情页):浅色光影剧幕白色中间层可见且深色文字可读;线路 chip 填充实测 (234,240,245) vs 相邻空白 (168,180,193),选中项蓝光线路绿色 tint+描边 (29,143,90);选集第 1 季 chip 填充实测 (248,245,247) vs 相邻空白 (174,184,197)。

Task-Guard: C41-beta-merge-review-dev1
2026-10-06 22:37:06 +08:00
Silent1566
5c95aa19cd fix(detail): 修复线路/选集 chip 无底色并恢复光影剧幕浅色白色中间层
用户报告两个问题:
1. 电视版「线路」「选集」chip 只剩描边、没有底色,压在亮色剧照上看不清;
2. 「光影剧幕」浅色模式要改回早之前有白色中间层的版本,和深色模式差不多。

chip 无底色:setChipState 用 MaterialButton#setBackgroundColor,该方法只 tint 当前那个
MaterialShapeDrawable 实例,不更新 helper 的 backgroundTint 字段;Material 之后在 inset/
圆角/尺寸变化时用该字段重建背景,填充因此丢回全透明。同一页的「第 N 季」按钮走
setBackgroundTintList(写持久字段)所以一直有底色,构成截图里的天然 A/B 对照。
改用 setBackgroundTintList。

浅色剧幕:cinemaBackdropShade() 是夹在剧照与内容之间的全屏渐变中间层,深色一直是黑幕,
浅色那层此前被改成全透明,内容直接浮在剧照原图上。恢复 cinemaLightBackdropShade() 并接回
浅色分支,删除为绕开该缺失而引入的局部羽化底板 applyLightCinemaCopyPlate()/
LightCinemaCopyPlateDrawable。同时 tintTmdbSectionTitles() 原先不分深浅一律强制白字,
在白色中间层上会看不见,改为仅深色剧幕强制白字、浅色剧幕使用调色板深色。

新增契约测试:TmdbDetailChipFillTest 用真实渲染证明两条通道在背景重建后的差异;
TmdbCinemaLightReadabilityTest 从生产源码读取中间层 alpha 做 WCAG 对比度断言。

Verification: TmdbDetailChipFillTest 2/2 passed (real-render proof: tint channel keeps chip fill through Material background rebuild; legacy setBackgroundColor degrades to 0x00000000); TmdbCinemaLightReadabilityTest 4/4 passed (reads shipped middle-layer alphas from production source; WCAG contrast >=4.5:1 for title/body; mutation check weakening alpha 0x99->0x1A drops title contrast to 2.95:1 and fails 3 assertions); TmdbDetailActivityLayoutTest 130/130; TmdbCinemaThemeTest 4/4; :app:testMobileArm64_v8aDebugUnitTest 5196 tests 0 failures; :app:testLeanbackArm64_v8aDebugUnitTest 4348 tests 0 failures; leanback arm64 debug APK built (196M) and disassembly confirms setChipState calls MaterialButton.setBackgroundTintList with no setBackgroundColor, cinemaLightBackdropShade present, LightCinemaCopyPlateDrawable removed. Device verification NOT obtained: dev1 emulator 192.168.50.3:5555 was offline for the whole task (port closed; 5557/5559/5561 belong to other devs and were not taken; no local emulator/AVD and no SSH/docker/virsh path to restart it).

Task-Guard: CINEMA-LIGHT-CHIP-FILL-20261006
2026-10-06 19:27:59 +08:00
Silent1566
414babc1b5
Merge pull request #410 from Silent1566/dev2
merge: 合并 origin/beta 最新代码(PR#407-#409)并复评修复 TV 浅色迁移的日间白底白字回归
2026-10-06 19:27:21 +08:00
Silent1566
990f8039d7 merge: 合并 origin/beta 最新代码(PR#407-#409)并复评修复 TV 浅色迁移的日间白底白字回归
合并 origin/beta @ cb82755ae8(PR#407-#409:主题编辑器安全区、缓存确认框主题化、详情页追更就地取消),
0 冲突;25 个 beta 回退提交零复活、beta 增量零丢失。

评审 dev2 未推送的「真正打通 TV 浅色模式」时发现:405 处 leanback 前景整文件批量迁移未区分该前景
压在什么表面上,其中 4 个布局的行底是固定浅色卡片,迁移后变成白底白字(日间 1.05:1 / 1.16:1 /
1.29:1,低于 WCAG 非文本 3:1 与正文 4.5:1)。已把这 4 个布局的前景回退为 ?attr/colorOnSurface /
?attr/colorOnSurfaceVariant(与 mobile 同名文件语义一致,日间 16.21:1)。

新增 LeanbackForegroundContrastTest:遍历全部 129 个 leanback 布局,按标签树解析每个调色板无关
浅色前景最近的绘制背景并判定其日间取值,防止同类迁移回归;已反证可失败。

Verification: 合并 origin/beta @ cb82755ae8 进 dev2:0 冲突;25 个 beta revert × 171 文件版本 × 1334 行行级比对零复活、PR 方向零回带;beta 增量 13 路径零丢失;dev2 增量 66 路径中 65 路径逐行完整,8 行为有意修正。第 1 轮评审发现 dev2 未推送的 TV 浅色迁移把 4 个布局(adapter_device/adapter_player_osd/adapter_recommendation_feedback/adapter_tmdb_item)的行前景整文件替换为调色板无关浅色常量,而它们的行底是固定浅色卡片,日间实测 1.05:1 / 1.16:1 / 1.29:1(白底白字,低于 WCAG 非文本 3:1 与正文 4.5:1),已回退为 ?attr/colorOnSurface / ?attr/colorOnSurfaceVariant(日间 16.21:1);新增 LeanbackForegroundContrastTest 把该口径固化为遍历全部 129 个 leanback 布局的结构性检查,反证可失败(回退修复后 tests=3 failures=2,命中 6 处并复现实测数字)。第 2/3 轮复评通过。双 flavor Java 与 androidTest 编译 BUILD SUCCESSFUL;全量 JVM 套件相对合并前基线零新增回归(mobile 10→6、leanback 10→7,失败集合 comm -13 双向为空);check_ui_tokens.sh --strict violations=1 相对基线零新增;git diff --check 退出码 0;设备 127.0.0.1:5557(API 28 leanback arm64,覆盖安装未卸载)日间/夜间各一遍通过,屏显设置弹窗与设置页卡片行文字实测深字压浅卡,缓存管理/DoH/AI 服务页渲染与焦点环正常。已记录非本任务引入的既有夜间缺陷(同 4 个布局的固定浅色卡片无 drawable-night 变体,beta 上同样存在,刻意不断言为通过)。

Task-Guard: C40-beta-merge-review-dev2
2026-10-06 11:02:58 +08:00
Silent1566
8624f6c0d7 refactor(tv): 删除 AppearanceRowTheme 中未被引用的三个辅助方法
refresh()/textColors()/color() 在引入后没有任何调用点(实际调用只有
apply()),属于本任务不应保留的推测性接口面。删除它们并移除随之无用的
ColorStateList/ContextCompat 导入;同时把外观行测试中对 apply() 方法体的
边界从 refresh( 改为 shape(,不再依赖被删除的符号。

Verification: AppearanceRowThemeTest 7 tests + ThemeControllerContractTest 8 tests 通过(0 failures/0 errors); leanback+mobile arm64 Debug Java 编译通过

Task-Guard: TV-APPEARANCE-ROWTHEME-CLEANUP-20261006
2026-10-06 08:27:57 +08:00
Silent1566
663ac5e7da fix(tv): 修复外观与语言二级选择弹窗标题不可读
ChoiceDialog 的标题写死 #202124、消息写死 #5F6368,而它的面板是
shape_shell_proxy_dialog (?attr/colorSurfaceContainerHigh),在 TV 上编译为深色
#2A2F34。设备实测(192.168.50.3:5559) 从「外观与语言」行点入的「界面大小」选择
弹窗标题对比度仅 1.00:1,消息 2.23:1,与用户报告的看不清文字属同一路径上的
同类缺陷。

标题改用 ThemeController.current().colorOnSurface()、消息改用
colorOnSurfaceVariant()。选项行未动:它们画在自有的不透明白色卡片上,实测
常态 16.10:1、选中 6.85:1、焦点 4.51:1,均达标。

设备实测:标题对比度 1.00:1 -> 12.06:1。

Verification: AppearanceRowThemeTest 7 tests + ThemeControllerContractTest 8 tests 全部通过(0 failures/0 errors); leanback+mobile arm64 Debug Java 编译通过; scripts/build_arm64_debug_install.sh --flavor leanback --serial 192.168.50.3:5559 覆盖安装成功且设备 base.apk md5 与构建产物一致(59156f9453f3791500224e1490a50a1c); 设备实测 192.168.50.3:5559 首页->设置->外观与语言->界面大小 二级选择弹窗标题对比度由 1.00:1 提升到 12.06:1

Task-Guard: TV-CHOICEDIALOG-TITLE-CONTRAST-20261005
2026-10-06 08:10:22 +08:00
Silent1566
35a97894a2 feat(theme): 真正打通 TV 浅色模式
删除 leanback 恒深色 token 遮蔽表,使 TV 与手机一样按 day/night 解析色板;
Theme.WebHTV.TV 不再硬编码 isLightTheme=false;405 处 leanback 前景从
?attr/colorOnSurface* 迁移到与手机一致的调色板无关角色
(webhtvColorOnWallpaper / player_control_muted / white_80_90_70);
ThemeDialog 预览模式改为按 ThemeController.isNight 打开,不再在 TV 上恒以深色预览。

缺陷证据:改动前 theme_mode=0 与 =1 截图逐字节相同(297612B),即 TV 忽略浅色选择。
改动后同一设置页在系统浅/深下像素差 8.29%,浅色下 primary 由 #A8C7FA 变为 #0B57D0;
显式浅色可覆盖系统深色且跨重启持久。

Verification: 改动前 theme_mode=0 与 =1 截图逐字节相同(297612B, md5 5cfbd8eb0d77)证明缺陷真实;改动后以系统 night 驱动 A/B,no vs yes 各 3 帧帧内稳定且两态 md5 不同(ea1e269b vs 4d11f57e),像素差 8.29%;主色量化:旧构建浅色选中 light#0B57D0=0/dark#A8C7FA=3281(缺陷),新构建浅色 light=3281/dark=0;用户原路径端到端(UI 点 外观与语言→主题模式→浅色)theme_mode 落盘 0,force-stop 重启且系统设为 night=yes 后仍渲染浅色帧 f9ceed4f(与系统浅色下的浅色帧逐字节相同),证明显式浅色覆盖系统深色且跨重启持久;编辑器 uiautomator 显示 浅色 selected=true/深色 selected=false(改动前恒深色);构建 bash scripts/build_arm64_debug_install.sh --flavor leanback --serial 127.0.0.1:5557 BUILD SUCCESSFUL 并 adb install -r 覆盖安装成功(未卸载);:app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.theme.* --tests TvFocusRingContractTest 150 tests / 1 failed,唯一失败 ThemeBinderContractTest.materialAlertDialogsAreBuiltThroughTheThemedBuilder 经证为既有(纯静态扫描,测试与被告发文件 CacheManagementDialog.java 均未被本单元改动,用法由 ae0b26e8ee 2026-09-25 引入晚于测试方法 2c2712e55d 2026-09-24);scripts/check_ui_tokens.sh --strict violations=1 legacy=0,唯一违规为既有 mobile item_following.xml,零新增;65 文件 +448/-517;设备 prefs 已复原(wall=10/wall_type=0/wall_color=-13922613/theme_color=-16732991,删除注入的 theme_mode,chown+restorecon,系统 night 复位 no),临时脚本与截图已清理,gradlew clean 完成并停止守护进程

Task-Guard: TV-LIGHT-THEME-20261005
2026-10-05 22:40:30 +08:00
Silent1566
57362eb4f2 fix(tv): 修复外观与语言对话框行文字不可读
TV 版「外观与语言」的每一行把固定浅色 selector_git_cloud_card(#F8F9FA) 作为
底色,而行文字已跟随 ThemeController.current()。leanback 编译的是深色 token
表,于是 #E2E2E9 / #C4C6D0 被画在 #F8F9FA 上,设备实测对比度仅 1.09:1 / 1.24:1,
用户报告「看不清文字」;同一固定卡片也让自定义主题 profile 无法生效。

新增 AppearanceRowTheme:用当前语义 token 生成行背景 StateListDrawable
(常态 surfaceContainerHigh + outlineVariant,焦点/按下 primaryContainer +
2dp primary 环) 并同时设置两个文字色。焦点行不用 primary 实心填充,因为行文字
在焦点时并不改色,onSurface 压 primary 仅 1.3-2.4:1。两个 flavor 的 addRow()
改调该渲染器,并在 onStart()/onThemeProfileApplied() 重绘已建行。

设备实测(192.168.50.3:5559):常态行 label 10.48:1、value 7.93:1;焦点行
label 7.09:1、value 5.31:1;焦点环对填充 5.32:1、对面板 7.86:1;切换内置主题
松林绿后行填充变为 #242F1F、焦点环变为 #A9D291,证明样式随 profile 变化。

Verification: AppearanceRowThemeTest(5)+ThemeControllerContractTest/ThemeEditorContractTest/ThemeBinderContractTest/ThemeContractTest 通过; leanback+mobile arm64 Debug Java 编译通过; scripts/build_arm64_debug_install.sh --flavor leanback --serial 192.168.50.3:5559 覆盖安装成功; 设备实测 192.168.50.3:5559 外观与语言 5 行对比度由修复前 1.09-1.36:1 提升到 4.08-12.06:1, 焦点环对填充 5.32:1/对面板 7.86:1, 切换到内置主题松林绿后行填充由 #2A2F34 变为 #242F1F 证明样式随 profile 变化

Task-Guard: TV-APPEARANCE-DIALOG-CONTRAST-20261005
2026-10-05 22:30:10 +08:00
Silent1566
cb82755ae8
Merge pull request #409 from Silent1566/dev4
dev4: 合并 beta 最新代码(PR#407 缓存管理 P0-P4 / PR#408 主题编辑安全区)并复评修复缓存确认框主题化门禁回归
2026-10-05 20:20:55 +08:00
Silent1566
3e6b8dc390 merge: 合并 origin/beta 最新代码(PR#408 主题编辑安全区)并解决缓存确认框等价修复冲突
beta 在 PR #409 创建后前进到 c94e5548be1(Merge PR #408 from dev3),使 PR 报
CONFLICTING。本次把该增量合入 dev4:

- 唯一冲突 app/src/main/java/com/fongmi/android/tv/ui/dialog/CacheManagementDialog.java:
  dev3 在 PR #408 里独立做出了与本分支第 1 轮完全相同的修复(三处确认框由裸
  MaterialAlertDialogBuilder 改为 WebHtvAlertDialogBuilder)。双方改动等价,仅本分支
  多两行中文注释,故取 beta 版解决,使该文件与 origin/beta 逐字节一致,不把纯注释
  差异带进 PR。
- 第 1 轮的门禁修复因此被 beta 超集覆盖,最终净差异回到纯 dev4 自身改动 + 本文档。
- beta 本轮还带入 dev3 的主题编辑安全区修复(ThemeDialogLayout.safeArea + 两 flavor
  ThemeDialog 按系统栏 insets 重定尺寸),与 dev4 追更就地取消零文件交集。

复核:零复活 0 行/0 文件(含 PR 方向反向校验);beta 增量 8 路径 0 缺失且逐字节一致;
双 flavor Java/androidTest 编译通过;全量 JVM 相对任务前基线零新增回归(mobile
5191/6、leanback 4346/7,失败集合逐条相同);UI token 门禁零新增违规。

Verification: second merge of origin/beta c94e5548be into dev4 after PR #409 reported CONFLICTING (base advanced via PR #408); 1 conflicted path CacheManagementDialog.java where dev3 independently made the identical MaterialAlertDialogBuilder->WebHtvAlertDialogBuilder fix - resolved by taking the beta version so the file is byte-identical to origin/beta; 0 conflict markers; zero-resurrection rerun 28 reverts/194 file-versions/1773 lines = 0 lines 0 files, PR direction 0/0; beta round-2 delta 8 paths 0 missing lines/files, 8/8 byte-identical to origin/beta; net diff vs origin/beta = dev4-only 4 paths + this doc (first-round CacheManagementDialog fix superseded by beta superset); both flavors Java + androidTest compile BUILD SUCCESSFUL; full JVM mobile 5191/6-fail leanback 4346/7-fail = zero new regressions vs pre-task baseline (5122/6, 4277/7) and identical failure sets; ThemeBinderContractTest 26/0; check_ui_tokens --strict violations 1 (baseline 2, zero new); git diff --check clean

Task-Guard: C39-beta-remerge-dev4-20261005
2026-10-05 20:05:13 +08:00
Silent1566
ae09751eed docs(c39): 订正净差异路径数为最终实测 6 并区分合并时点与 PR 时点
Verification: doc-only correction: net-diff figure updated from the pre-fix merge state (4 paths) to the final PR state (6 paths = 4 dev4 paths + CacheManagementDialog fix + this doc), measured by git diff --name-status origin/beta dev4; markdown clean; no code change

Task-Guard: C39-doc-closure-dev4
2026-10-05 19:45:34 +08:00
Silent1566
b19ccde879 merge: 合并 origin/beta 最新代码(PR#407 / 缓存管理 P0-P4)并复评修复缓存确认框主题化门禁回归
把 origin/beta tip 03c239e32e 合入 dev4(0 冲突),并复评 dev4 已提交未推送的
详情页追更就地取消改动。复评发现合并带入 1 个真实回归并修复:

- CacheManagementDialog 的 3 处清理确认框(轻度/标准、单模块、深度两步)原先直接用
  裸 MaterialAlertDialogBuilder,其 create() 不经过 ThemeController.bindDialog,自定义
  主题下面板与文字仍停留在编译期调色板,使 ThemeBinderContractTest 由合并前 26/26 通过
  变为 26 项 1 失败(纯 origin/beta 树同样失败,CI 不跑该门禁)。现统一改用
  WebHtvAlertDialogBuilder,与 BaseAlertDialog 同源;该构造器在默认主题下走
  baseline.equals(active) 短路,零行为差异。

- 远端已移除(回退)内容零复活:28 个单亲 revert × 194 文件版本 × 1773 行程序化比对
  0 复活行 / 0 复活文件;PR 方向(会不会把已删内容带回 beta)同样 0 行 / 0 文件。
- beta 增量零丢失:76 路径 0 缺失,且 76/76 逐字节等于 origin/beta;dev4 侧 4 路径
  逐字节等于 a455e5a6cce;双方改动路径零交集。
- 净差异恰好 4 个路径,全部为 dev4 自身改动。
- 双 flavor Java/androidTest 编译通过;全量 JVM 相对合并前真实 worktree 基线零新增回归
  (mobile 5185/6、leanback 4340/7,失败集合逐条相同且均为既有 CRLF 环境问题)。
- 设备覆盖安装实测:详情页就地取消用例 OK(1)、追更墓碑/迁移用例 OK(3)、缓存管理面板与
  三条确认框路径正常且焦点落在「取消」。

Verification: merge origin/beta 03c239e32e into dev4 (0 conflicts); zero-resurrection 28 reverts/194 file-versions/1773 lines = 0 lines 0 files (also PR-direction: 0); beta delta 76 paths 0 missing lines/files, 76/76 byte-identical to origin/beta; dev4 4 paths byte-identical to a455e5a6cc; net diff vs beta = exactly 4 dev4-only paths; full JVM mobile 5185/6-fail leanback 4340/7-fail = zero new regressions vs real-worktree baseline a455e5a6cc (5122/6, 4277/7), identical failure sets (pre-existing CRLF-env multiline source assertions, targets byte-identical to both sides); fixed merge-introduced ThemeBinderContractTest regression (CacheManagementDialog 3 alert builders -> WebHtvAlertDialogBuilder; 26/1 -> 26/0), CI does not run that gate; both flavors Java + androidTest compile BUILD SUCCESSFUL; check_ui_tokens --strict violations 1 vs baseline 2 (zero new); git diff --check clean; device 127.0.0.1:5561 over-install (install -r -t, signer 95e4b2e7...7e4d): TmdbDetailFollowingCancelDeviceTest OK(1) 24.6s, TmdbDetailFollowingTombstoneDeviceTest+FollowingMigrationDeviceTest OK(3), cache management panel + ChoiceDialog + light-confirm + deep two-step confirm all render with focus on Cancel, no new crashes

Task-Guard: C39-beta-merge-review-dev4-20261005
2026-10-05 19:43:47 +08:00
Silent1566
c94e5548be
Merge pull request #408 from Silent1566/dev3
merge: 合并 origin/beta 最新代码(PR#407 缓存管理上游同步)并复评修复主题契约与安全区 insets 缺陷
2026-10-05 18:20:45 +08:00
Silent1566
bbaf19b972 merge: 合并 origin/beta 最新代码(PR#407 缓存管理上游同步)并复评修复主题契约与安全区 insets 缺陷
Verification: 合并 origin/beta tip 03c239e32(0 冲突,合并树 5b0ad6bb5 与 merge-tree 预测一致);16 个 beta revert 提交移除内容零复活(54 路径差异 0);4 轮评审修复 2 处真实缺陷:CacheManagementDialog 裸用 MaterialAlertDialogBuilder 违反主题契约门禁(改 WebHtvAlertDialogBuilder)、ThemeDialog 全零 insets 未回退致竖屏导航栏按钮裁 48px(新增 isEmpty + 三级 insets 回退,修复后余量 60px);全量 JVM mobile 5191/leanback 4346 零失败,双 flavor androidTest 编译通过;check_ui_tokens.sh --strict violations=1 既有项零新增;5559 实机 mobile 竖屏+导航栏与 leanback 横屏窗口 [48,48][1872,1032] 与基线一致;设备状态已恢复

Task-Guard: C38-BETA-MERGE-REVIEW-DEV3-20261005
2026-10-05 18:16:21 +08:00
Silent1566
3e4e49331a fix(theme): fit editor dialog inside system bar safe area
Verification: mobile 310/310 与 leanback 191/191 定向测试通过;5559 竖屏导航栏场景保存按钮完整可见且余量83px;leanback窗口/按钮无回归;设备偏好与显示设置已恢复

Task-Guard: THEME-EDITOR-INSET-20261005
2026-10-05 16:46:50 +08:00
Silent1566
03c239e32e
Merge pull request #407 from Silent1566/dev2
dev2: 合并 beta 最新代码(PR#403-#406)并复评修复焦点环注释裸 hex 门禁回归
2026-10-05 13:28:55 +08:00
Silent1566
2162548799 merge: 合并 origin/beta 最新代码(PR#403-#406)并复评修复焦点环注释裸 hex 门禁回归
本次改动:

1. 合并远端 beta 最新代码
   - origin/beta tip 79244f274d(PR#403-#406 之后)合入 dev2,0 冲突(42 路径自动合入);
     合并提交第二父即 79244f274d;
   - 合并树 vs origin/beta 净差异 74 路径,全部为 dev2 自身改动(缓存管理 P0-P4 + 评审文档),
     beta 侧内容零改动。

2. 远端已移除的回退提交零复活
   - beta 上 25 个单亲 revert 提交,按行级程序化比对被移除内容
     (removed(R,f) = lines(R^:f) - lines(R:f)):4215 行扫描 → 0 行复活、0 文件复活;
   - beta 增量零丢失(546 条新增行逐行校验 0 缺失);
   - dev2 本地零丢失(113 路径三分法:dev2-only 丢失 0、beta-only 未应用 0、both 丢失 0)。

3. 复评发现并修复 1 个真实缺陷(UI token 门禁回归)
   - 文件:app/src/main/res/color/focus_ring_error.xml(beta PR#404 新增);
   - 根因:该文件 XML 注释中含裸十六进制 #93000A / #690005 / #FFDAD6(仅用于解释
     "为何配对 on_error_container 而非 on_error"),而 check_ui_tokens.sh 按整行正则匹配裸 hex,
     导致 --strict 由 violations=1 变为 violations=2;
   - 修复:注释改写为文字描述(保留全部对比度数值 1.40:1 / 7.24:1),仅注释变更、零运行时行为影响;
   - 修复后:violations=1(与合并前基线完全一致,同为既有 item_following.xml)、
     hex_colors=0、contrast failures=0 min=4.28 → 零新增违规。

4. 随合并带入的 beta 增量(原样纳入,未改动)
   - TV 焦点环统一为主题色边框环(ThemeController.focusRingColor 成为唯一代码取值源,
     替换 5 处 Java 内写死的 0xFFFFD166;新增 3 个环色选择器与 webhtv_focus_ring_width);
   - 详情页追更墓碑判定修复(isFollowed 排除墓碑行 + 内联播放中就地处取消,不再跳转追更页);
   - 直播线路回退修复(线路播放失败只在本频道线路间轮换,仅节目列表拉取失败才切下一个直播接口,
     并补齐绕圈耗尽保护与 reload 失败反馈)。

Verification: beta tip 79244f274d 已合并(0 冲突,42 路径自动合入);25 个 beta 回退提交的 1146 行被移除内容行级校验零复活(0 复活行/0 复活文件);beta 546 条新增行零丢失;dev2 113 路径零丢失;合并结果 vs origin/beta 净差异 74 路径全部为 dev2 自身改动;第1轮评审发现并修复 focus_ring_error.xml 注释裸 hex 导致 UI token 门禁新增 1 违规(修复后 violations=1 与基线一致、hex_colors=0);第2轮复评:双 flavor Java+androidTest 编译 BUILD SUCCESSFUL,全量 JVM mobile 5185/9 失败、leanback 4340/10 失败,均为合并前基线(11/12)的严格子集、零新增回归且修好 2 个,定向 cache.*+直播回退+3 Layout 契约 0 失败;第3轮复评通过;git diff --check 退出码 0

Task-Guard: C38-beta-merge-review-dev2
2026-10-05 13:22:30 +08:00
Silent1566
a455e5a6cc fix(following): 详情页追更按钮统一为就地取消并立即生效
详情页 TmdbDetailActivity 此前在未内联播放时点「已追更」会跳转 FollowingActivity,
把一步取消变成两步,且在播放中会打断播放。现移除 isInlineFollowingPlaybackSurface
分支,与播放页同源:点「已追更」一律写墓碑、取消 one-shot 检查、立即刷新按钮并提示
「已取消追更」,全程停留在当前页;列表页仍是追更记录的唯一管理入口。

新增设备用例 TmdbDetailFollowingCancelDeviceTest 用 ActivityMonitor 锁定「不跳页 +
立即落库 + 按钮立即刷新」三条契约;FollowingUiSourceTest 增加源码级断言并把多行片段
断言改为 CRLF 归一化,避免 Windows 检出(core.autocrlf=true)下的假失败。

Verification: JVM: FollowingUiSourceTest 15/15 both flavors (mobile/leanback arm64_v8aDebug); device 127.0.0.1:5561 (API28, arm64-v8a): TmdbDetailFollowingCancelDeviceTest OK (1 test, 24.3s) — real click writes tombstone, button returns to 加入追更, FollowingActivity monitor hits=0, activity not finishing; over-install (adb install -r -t) with matching signer 95e4b2e7…7e4d

Task-Guard: FOLLOW-DETAIL-CANCEL
2026-10-05 13:16:44 +08:00
Silent1566
79244f274d
Merge pull request #405 from Silent1566/dev4
dev4: 合并 beta 最新代码(PR#402/#403)并复评直播线路回退修复
2026-10-05 10:57:57 +08:00
Silent1566
8724d665fb
Merge pull request #406 from Silent1566/dev3
dev3: 合并 beta 最新代码(PR#403/#404)并复评修复详情页追更墓碑判定
2026-10-05 10:57:13 +08:00
Silent1566
c6307261f7 merge: 合并上游 webhtv/webhtv Silent1566 缓存管理(P0-P4)并适配本地主题语义 token
Verification: upstream tip d042cd542b (58 commits / 72 paths) fully merged with 0 unresolved conflicts; 5 union conflicts resolved keeping local theme-semantic tokens (no hardcoded @color/white, #FFFFFFFF, #33FFFFFF); cache package + tests + design doc byte-identical to upstream; compileMobileArm64_v8aDebugJavaWithJavac + compileLeanbackArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL; 13 cache test classes 64 cases 0 failure 0 error; check_ui_tokens.sh --strict shows zero new violations vs pre-merge baseline (violations=1 is pre-existing item_following.xml); leanback emulator-5556 and mobile emulator-5560 real-device verification: dialog renders 15 modules at 90%x90%, all controls focusable, cancel-focused confirm, real module cleanup freed 13.4MB/6 files and 12.5MB/5 files matching cache_mgmt_cleanup_history, settings row auto-refreshed 203.4->190MB and 54->40.8MB via RefreshEvent.CACHE; git diff --check clean; no FATAL EXCEPTION

Task-Guard: C37-upstream-sync-silent1566
2026-10-05 00:18:15 +08:00
Silent1566
b1ce6f88d4 docs(c37): 订正净差异路径数为实测 11 并补 PR 文件集比对证据
Verification: C37 doc-only correction: the committed dev3 net diff vs origin/beta is 11 paths (9 modified + 2 added: TmdbDetailFollowingTombstoneDeviceTest.java and this task doc), not 9; 9 was the pre-commit tracked-only count while the 2 new files were still untracked. Corrected three places in the task record. Verified: git diff --name-only origin/beta HEAD = 11, and gh pr view 406 files set is byte-identical to that list (MATCH). No code, test, or build artifact changed; no re-verification needed.

Task-Guard: C37-beta-merge-review-dev3-20261004-doc
2026-10-05 00:10:00 +08:00
Silent1566
7673a81411 merge: 合并 origin/beta 最新代码(PR#403/#404)并复评修复详情页追更墓碑判定
Verification: C37: merged latest origin/beta (tip 6d152c4a24, PR#403 zero-content + PR#404 24 files) with 0 conflicts and 0 reverted-content revival (fd29d76ee 21/21 paths identical to beta, PR#353 symbols=0, net diff vs beta = 9 task-owned paths). Review round 1 found and fixed a real defect in the unpushed commit aa5345c83: TmdbDetailActivity judged 'already followed' with 'existing != null', but FollowingStore.resolveTmdb deliberately returns the tombstone row (C9 anti-revival guard), so after unfollowing the button stayed on 已追更 and re-following was impossible on inline playback; added isFollowed(item) = item != null && !item.isDeleted() at both decision sites. Evidence: FollowingUiSourceTest 15/15 both flavors; full JVM mobile 5117 tests 0 failures 0 errors, leanback 4273 tests 0 failures 0 errors; assembleMobileArm64_v8aDebug + assembleLeanbackArm64_v8aDebug BUILD SUCCESSFUL; device 192.168.50.3:5559 (overwrite install) TmdbDetailFollowingTombstoneDeviceTest + FollowingMigrationDeviceTest = 3 tests OK; guard proven non-vacuous by re-falsification on the final merged tree (pre-fix code FAILS with expected:<加入追更> but was:<已追更>, fixed code OK); check_ui_tokens.sh --strict identical on merged tree and pure origin/beta tree (violations=2, zero new); git diff --check clean

Task-Guard: C37-beta-merge-review-dev3-20261004
2026-10-05 00:07:21 +08:00
Silent1566
03dd0e76b9 merge: 合并 origin/beta 最新代码(PR#402/#403)并修复直播线路回退的缓冲超时、回退耗尽与 reload 反馈缺陷
Verification: LiveActivityLayoutTest 10/10、LiveSourceFallbackPolicyTest 9/9、LiveActivitySourceFallbackSourceTest 5/5(testMobileArm64_v8aDebugUnitTest,共 24 用例 0 failures/0 errors;LiveActivityLayoutTest 同时断言 mobile+leanback 两变体源码);leanback 变体 LiveSourceFallbackPolicyTest 9/9;:app:compileLeanbackArm64_v8aDebugJavaWithJavac 与 :app:compileMobileArm64_v8aDebugJavaWithJavac 均 BUILD SUCCESSFUL;leanback Live* 102 用例 0 失败、mobile Live* 118 用例 0 失败;合并树 vs origin/beta 净差异恰好 7 路径(全为 dev4 自身改动);beta 上 16 个 revert 提交涉及 33 文件,与净差异交集仅 1 文件且被回退符号 updateStatusBarInset 在合并后源码中 ABSENT(零复活);git diff --check 通过

Task-Guard: C37-beta-merge-review-dev4-20261004
2026-10-05 00:06:13 +08:00
Silent1566
6d152c4a24
Merge pull request #404 from Silent1566/dev1
dev1:合并 beta 最新代码(PR#399-#403)并统一电视版焦点高亮为主题色边框环
2026-10-04 23:28:37 +08:00
Silent1566
f1c64ca0c8 merge: 合并 origin/beta 最新代码(PR#399-#403)并复评统一 TV 焦点环为主题色边框环
- 合并 origin/beta tip e72239063(PR#399-#403 共 19 提交,0 冲突),beta 侧删除项零复活
- 复评未推送提交 94b7fba36:修复 TV 详情页写死 #FFD166 与主题焦点槽并存的两种环色
- 新增唯一取值源 ThemeController.focusRingColor(),6 个 Java 消费点与 shape_episode_photo_focused 改走 ?attr/tvFocusRing
- 回退「代码路径动态跟随主题」的尝试:?attr 为编译期静态资源,binder 不改写前景选择器,单独跟随会重新造出两种环色
- 新增设备端契约测试 TvFocusRingResolutionDeviceTest 钉死单一取值源
- 浅色详情页焦点环对比度由 1.14-1.35:1 提升到主题 FOCUS 槽的 5.03-5.99:1

Verification: 合并 origin/beta e72239063(19 提交,0 冲突);JVM 双 flavor 单测 9390 项 0 失败;双 flavor 编译门通过;UI token 门 PASS;leanback arm64 Debug 打包并 install -r 覆盖安装到 192.168.50.3:5555;设备端 Instrumentation TvFocusRingResolutionDeviceTest 3/3;实机冷启动无 FATAL 且 HomeActivity resumed;首页像素采样主题焦点色 #A8C7FA 命中 390px;beta 侧 3 个删除项零复活;净差异 14 路径

Task-Guard: C36-beta-merge-review-dev1
2026-10-04 23:16:48 +08:00
Silent1566
aa5345c835 fix(following): 播放页追更按钮改为就地取消,不再跳转追更页
已追更时再次点击播放页(mobile/leanback VideoActivity 与内联播放中的
TmdbDetailActivity)的追更按钮,此前会跳转到追更列表页打断播放。现在改为
就地取消:写墓碑、取消该条 one-shot 检查、刷新按钮为“加入追更”并提示
“已取消追更”,全程停留在当前播放页。未播放的详情页保持原有
“已追更→打开追更详情”约定。

Verification: FOLLOW-PLAYBACK-CANCEL: playback-page 追更 button is now an in-place toggle. mobile/leanback VideoActivity and inline-playing TmdbDetailActivity write the tombstone, cancel the per-item one-shot check, refresh the button back to 加入追更 and toast 已取消追更 without navigating. Evidence: :app:testMobileArm64_v8aDebugUnitTest and :app:testLeanbackArm64_v8aDebugUnitTest FollowingUiSourceTest = 15 tests / 0 failures each; :app:assembleLeanbackArm64_v8aDebug and :app:assembleMobileArm64_v8aDebug BUILD SUCCESSFUL; scripts/build_arm64_debug_install.sh --flavor mobile --serial 192.168.50.3:5559 installed over the existing package; device tap on the followed show's playback page stayed on VideoActivity (mResumedActivity unchanged) with deleted_at=1791123588777/enabled=0 and the screenshot shows the 已取消追更 toast plus the button reverted to 加入追更; non-playing TmdbDetailActivity still opens FollowingActivity as documented; git diff --check clean

Task-Guard: FOLLOW-PLAYBACK-CANCEL
2026-10-04 22:27:38 +08:00
Silent1566
d042cd542b fix(cache): 评审修复死代码、测试可移植性与繁体翻译缺失
评审分支相对 origin/main 的全部未合入改动后修复三处问题:

1. EpgParser.clearExpiredCache 为死代码:P2 引入 CacheRetentionManager
   后调用者已被替换,删除该无引用方法。
2. CachePathSafetyTest.finalComponentSymlinkIsStillDetected 在
   File.getCanonicalFile() 不解析符号链接的主机 JVM(如 Windows)上
   必然失败:该检测依赖 Linux/Android 的 canonical 语义,现于断言前
   用 Assume 跳过不遵循链接的平台,测试意图在设备语义上保持不变。
3. zh-rTW 缺失 cache_module_diagnostic_logs 与 cache_module_unclassified
   两条字符串,且 legacy 模块文案与 EN/CN 的「遗留路径」不一致:补齐
   翻译并统一术语,三语 cache_* 键 61/61/61 完全对齐。
   另修正 CacheManagementDialog.moduleButton 一处 } 后语句排版。

验证:缓存包独立 JUnit 63/63 通过;双形态
compileMobileArm64_v8aDebugJavaWithJavac 与
compileLeanbackArm64_v8aDebugJavaWithJavac 均 BUILD SUCCESSFUL。

Verification: cache JUnit 63/63 OK (independent runner; CachePathSafetyTest symlink case platform-guarded); :app:compileMobileArm64_v8aDebugJavaWithJavac + :app:compileLeanbackArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL; zh-rTW strings 61 keys aligned with EN/CN

Task-Guard: cache-mgmt-review-fix
2026-10-04 20:56:47 +08:00
Silent1566
e72239063b
Merge pull request #403 from Silent1566/dev3
dev3: 合并 beta 最新代码(PR#399-#402)并复评手机版深色表面文字对比度修复
2026-10-04 20:20:27 +08:00
Silent1566
96531595dc fix(live): 直播线路失效优先在本频道线路间轮换,仅节目列表拉取失败才切换下一个直播接口
Verification: LiveSourceFallbackPolicyTest 9/9 与 LiveActivityLayoutTest 9/9(testMobileArm64_v8aDebugUnitTest,0 failures/errors,断言覆盖 mobile+leanback 两变体源码)与 Leanback 变体 LiveSourceFallbackPolicyTest 9/9(testLeanbackArm64_v8aDebugUnitTest)均通过;两变体 Java 编译成功;:app:assembleLeanbackArm64_v8aDebug 构建成功;git diff --check 通过;设备 install -r 因全部在线设备为异签名旧包且按约定不卸载而放弃,不作为回归声明

Task-Guard: live-line-fallback-first
2026-10-04 19:57:52 +08:00
Silent1566
08d6cca51e docs(c36): 订正 dev3 净差异路径数为实测 23 并补程序化比对证据
Verification: 文档数值订正:C36 评审文档中 dev3 相对 origin/beta 净差异路径数由笔误 22 改为实测 23(3 个 Java 对话框 + shape_mpv_action_menu.xml + selector_tmdb_flag_item_dark.xml + 12 个手机版 dialog_* 布局 + docs/ui-token-allowlist.txt + 2 个测试 + 3 个文档),并补充 gh pr view 403 --json files 与 git diff --name-only origin/beta HEAD 程序化比对 MATCH 的证据;同步修正 beta 增量提交数(9→11)与主题面隔离表述。校验:git diff --name-only origin/beta HEAD | wc -l = 23;PR#403 files 集合与之一致;纯文档改动无代码影响。

Task-Guard: C36-beta-merge-review-dev3-20261004-doc
2026-10-04 19:56:54 +08:00
Silent1566
06f9af4037 merge: 合并 origin/beta 最新代码(PR#399-#402)并复评 dev3 未推送的主题对比度改动
Verification: 合并 origin/beta faac13dd64b(PR#399-#402,32 文件 0 冲突;合并树重放 git write-tree=abc7eae3c 与提交树逐字节一致);两轮复评通过:dev3 未推送两提交(手机版深色面板文字对比度 + Java 对话框语义前景)无缺陷,dev3 净差异 vs beta 恰好 22 路径、与 beta 增量路径交集 0;被回退内容零复活(mobile/res/values/webhtv_tokens.xml 在 beta 与合并树均不存在,19 个还原为上游字面量的 drawable 抽检仍为裸色,fd29d76ee/5682f2b05 仍在祖先链);beta 横幅删除正确带入且无存活引用;12 个深色面板布局前景属性程序化扫描零遗漏,最不利合成底色对比度 6.34:1 / 4.76:1 均达标;check_ui_tokens.sh --strict 三树对照(纯 beta / 合并前 / 合并后)输出完全一致 violations=1 为既有 item_following.xml,零新增违规;JVM 套件 leanback 176 + mobile 5117 仅 1 项既有 flaky(MultiThreadProxyRouteTest,隔离重跑 4 次全过、文件与 beta 逐字节一致)其余 0 失败 0 错误;mobile arm64 debug 覆盖安装到 192.168.50.3:5559 成功,冷启动 HomeActivity 正常 resume,FATAL EXCEPTION/ANR=0

Task-Guard: C36-beta-merge-review-dev3-20261004
2026-10-04 19:54:16 +08:00
Silent1566
94b7fba363 统一电视版焦点高亮为主题色边框环
Verification: 契约测试 TvFocusRingContractTest 7/7 + NativeEnhancedPlaybackStyleFocusTest 14/14 + FollowingUiSourceTest 15/15 共36项全绿;leanback arm64 Debug 构建并覆盖安装到 dev1 192.168.50.3:5555;实机像素验证焦点环随焦点出现/消失,环/填充对比度 检查更新6.09:1、全部已读6.09:1、取消追更6.41:1(修正前为1.33:1/1.40:1);mobile arm64 编译门通过

Task-Guard: tv-focus-ring-unified
2026-10-04 17:39:29 +08:00
Silent1566
c39e5748a5 fix(ui): Java 构建对话框的前景色改用语义角色,修复夜间深底深字
DebugLogDialog / MpvConfigDialog / PlaybackPerformanceDialog 把前景写死为
Material 灰蓝(#5F6368/#202124/#174EA6 等),但容器 shape_shell_proxy_dialog 的填充是
?attr/colorSurfaceContainerHigh —— 跟随调色板(日间#E7E8EF / 夜间#2A2F34)。
写死的前景只能在其中一种模式下正确:夜间实测仅 1.19-2.23:1。

改为统一从 ThemeController.current() 取语义角色(onSurface / onSurfaceVariant /
primary / primaryContainer / outline / error / surfaceContainerLowest),
使面板与前景成对跟随调色板:日间浅底深字、夜间深底浅字。
与既有范式一致(LightDialog 早已如此,仓库内 13 处先例)。

连带修复 shape_mpv_action_menu.xml:该弹出菜单原本写死白底,
若只改文字会在夜间变成近黑底+近黑字。同步迁移为语义角色,
并从 ui-token-allowlist.txt 移除其豁免条目(文件已无裸色)。

新增 DialogForegroundTokenTest 三项守卫,防止再次写死前景。

Task-Guard: dialog-foreground-semantic-tokens

Verification: DialogForegroundTokenTest 3项全过; theme+setting+ui.dialog+ui.style 322项0失败; check_ui_tokens.sh --strict 相对HEAD无新增违规(allowlist回到191); mobile arm64 debug 覆盖安装到192.168.50.3:5559成功; 实机FATAL EXCEPTION=0; 日间播放性能对话框 标题16.35:1/Tab7.20-8.70:1/行16.35:1; 夜间 标题16.54:1/Tab11.30-11.32:1/行16.54:1(修复前夜间1.19-2.23:1); 守卫逻辑在HEAD源码上全部报违规、修复后全通过; 设备已恢复日间模式并force-stop

Task-Guard: dialog-foreground-semantic-tokens
2026-10-04 16:59:51 +08:00
Silent1566
ef8bed60b5 fix(ui): 修复手机版默认主题下深色表面文字看不清
0af2340d4 把 12 个播放器玻璃子面板的 @color/white* 前景改成 ?attr/colorOnSurface,
但手机版日间调色板把该角色解析为近黑 #1A1C1E,而面板是恒定深色渐变
(#E62F315E→#CC303463)。leanback 同样写法没问题只因其 token 表在所有档位都是深色。
e1ea7ab34 同样把 TMDB 深色页线路芯片的实色换成跟随调色板的浅色表面,
变成浅底+近白字,即用户红圈处。

修复改用三张 token 表取值完全相同的既有语义角色
(webhtvColorOnWallpaper / webhtv_color_player_control_muted / webhtv_color_overlay_light),
不新增资源、不扩大范围、不触发豁免;TMDB 深色页芯片恢复恒定半透明填充。

新增 3 项守卫测试防回归。

Task-Guard: mobile-dark-surface-text-contrast

Verification: ThemeBaseWiringTest 13项全过(含3项新守卫); 相邻套件(theme/ui.style/ui.dialog/VideoActivityLayoutTest/EpisodeAdapterTest)480项0失败; check_ui_tokens.sh --stage B violations=0 legacy=0; --strict 相对HEAD无新增违规; mobile arm64 debug 覆盖安装到192.168.50.3:5559成功; 实机日间模式 dialog_timer 面板实测5.85-7.41:1(修复前反事实1.23-1.50:1)

Task-Guard: mobile-dark-surface-text-contrast
2026-10-04 16:18:42 +08:00
Silent1566
faac13dd64
Merge pull request #402 from Silent1566/dev4
dev4: 合并 beta 最新代码(PR#399-#401)并复评 TV 横幅按密度输出(含 CRLF 断言归一化)
2026-10-04 14:48:57 +08:00
Silent1566
3400cd7b0a merge: 合并 origin/beta 最新代码(PR#399-#401)并复评 dev4 未推送的 TV 横幅按密度输出改动(含 CRLF 断言归一化修复)
Verification: 双 flavor 编译 BUILD SUCCESSFUL;leanback 全量 4259 用例仅 11 失败、mobile 全量 5111 用例仅 10 失败,且失败集合与纯 origin/beta 参照工作树(同机同配置独立构建)完全一致,零个由本任务引入;净差异内测试全通过:AppBrandingContractTest 13/13、EpisodeVersionIdentityTest 17/17、HistoryPlaybackTest 63/63、TmdbConfigCustomRouteModeTest 5/5、following.* 34/34、TmdbSourceDialogInflationContractTest 修复 CRLF 归一化后双 flavor 通过;横幅 PNG 5 档实测 16:9 且字形真实渲染;合并树 vs origin/beta 净差异恰为 255059d48b 文件集,132 个被回退文件零差异

Task-Guard: C35-beta-merge-review-dev4-20261004
2026-10-04 14:38:50 +08:00
Silent1566
255059d48b fix(leanback): TV 横幅改为按密度输出 16:9 位图,移除抢占密度的 anydpi-v26 自适应图标
Verification: bash ./gradlew :app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.setting.AppBrandingContractTest => 13 tests, 0 failures, 0 errors (新增 tvBannerIsProvidedPerDensityAtFullResolution / tvBannerUsesBitmapDensitiesNotAdaptiveIcon 均执行); 重跑 scripts/gen_app_icon.py 后 5 个密度 ic_banner.png md5 与改动前一致(生成幂等),banner 实测尺寸 160x90/240x135/320x180/480x270/640x360 全为 16:9

Task-Guard: tv-banner-density
2026-10-04 02:10:38 +08:00
Silent1566
13f07c8cba
Merge pull request #401 from Silent1566/dev3
TMDB 线路自定义支持(API/图片线路下拉自定义选项 + D-pad 交互)并合并 beta 最新代码
2026-10-03 17:30:14 +08:00
Silent1566
8847705081 merge: 合并 origin/beta 最新代码(PR#395-#398)并复评 dev3 未推送的 TMDB 线路自定义改动
Verification: 合并 origin/beta b056747894cff64fb34062d4f4a1ac416f4206a0(PR#395-#398,16 文件 0 冲突);两轮复评通过:beta 集多版本消歧与 dev3 TMDB 线路自定义 4 提交均无问题,含音频队列/跨线路续播回归核对;被回退内容(fd29d76ee 21 文件与 5682f2b05)未带回;合并树定向单测 Leanback 90 项 + Mobile 258 项 0 失败(含 EpisodeVersionIdentityTest/TmdbConfigCustomRouteModeTest/TmdbSourceDialogInflationContractTest)

Task-Guard: C34-beta-merge-review-dev3-20261003
2026-10-03 17:27:47 +08:00
Silent1566
e224f1b8cd
Merge pull request #400 from Silent1566/dev1
dev1: 合并 beta 最新代码(集多版本消歧修复)并复评启动配置偏好选择修复
2026-10-03 17:16:25 +08:00
Silent1566
f22e24f5f2 merge: 合并 origin/beta 最新代码(PR#397/#398 集多版本消歧修复)并复评启动配置偏好选择修复(含 C34 复评)
Verification: 定向单测 EpisodeVersionIdentityTest+HistoryPlaybackTest(leanback)与 VideoActivityLayoutTest+VideoActivityHistoryTitleTest(mobile)全通过;bean/db 契约 leanback 266+mobile 262 项 0 失败;双flavor arm64 Java编译通过;mobile arm64 debug 覆盖安装 192.168.50.3:5555 冷启动冒烟:猫源就绪后 vod-config-loaded success=1 cost=5021ms,无'配置取得失败'无FATAL,进程存活;三层回退核对(文件级diff唯一差异Config.java/5682f2b05非祖先/revert删除文件反查全部absent)通过

Task-Guard: C34-beta-merge-review-dev1
2026-10-03 17:10:13 +08:00
Silent1566
490218a66e
Merge pull request #399 from Silent1566/dev4
追更取消跨设备同步(墓碑方案)+ 合并 beta 最新代码并复评
2026-10-03 16:48:54 +08:00
Silent1566
62527bec42 merge: 合并 origin/beta 最新代码(PR#394-#397)并复评 dev4 未推送的追更墓碑同步
Verification: merge clean (563 files, beta 8e4dac7606a..59d481e7264); revert fd29d76ee7 的 21 个文件与 origin/beta 逐字节一致(不复活); C9 tombstone 复评通过(迁移SQL与schema 3.json 一致); JVM following 34/34 leanback+34/34 mobile; 双flavor编译通过; 设备 following androidTest 17例16过(唯一失败 FollowingActivityDeviceTest 为历史遗留,纯beta参照worktree复现实证无关); FollowingUiSourceTest 2 失败为 CRLF 环境脆弱断言(三方基线均失败,探针实证),非本任务引入

Task-Guard: beta-merge-review-20261003
2026-10-03 16:44:25 +08:00
Silent1566
e2304fc1d6 fix(task-guard): 分批执行 staged 空白校验,规避 Windows argv 上限
大合并场景下 check_staged_whitespace 一次性把全部 staged 路径传给
git diff --cached --check,563 文件约 42KB 参数超过 Windows
CreateProcess 32KB 上限,报 'Argument list too long' 使 guard finish
误判为空白校验失败。改为每批 100 路径分批校验,语义不变。

验证: bash -n 通过;对 564 staged 文件实际运行 git diff --cached --check
exit 0 零输出(无真实空白违规)。

Task-Guard: MAINTENANCE-TASK-GUARD-ARGV-20261003
2026-10-03 16:39:42 +08:00
Silent1566
f2cd006b01 fix(config): 启动时按 config_<type> 偏好选上次使用的接口,不再盲选 time 最新行
用户反馈:最新版点播 http 开头接口启动显示配置失败,重装或切换其他接口后恢复。

根因:Config.vod()/live()/wall() 用 ORDER BY time DESC 取最新行作为启动配置。
一旦某行(典型是猫源)成功加载过一次,其 time 永远最新;此后每次冷启动都优先
重拉它——猫源需重启 :node 子进程,就绪探测超时后报'配置取得失败',而用户实际
在用的 http 接口根本没被加载。失败不更新 time,无法自愈:切换接口(bump 另一行)
或重装(清表)才能逃出,与反馈完全吻合。

修复:update() 本就持久化 config_<type>=url 偏好;启动选择先按该偏好精确找行,
缺失或行已删除时回退原 time DESC 行为。设备端构造'猫源行time最新+偏好指向http接口'
场景验证:修复后冷启动直接加载 http 接口成功,无 cat-source 分支与超时。

Verification: 双flavor arm64 Java编译通过(compileMobile/LeanbackArm64_v8aDebugJavaWithJavac);定向单测(*Backup*/*Config*相关)0失败;测试包mobile arm64 debug经scripts/build_arm64_debug_install.sh覆盖安装至192.168.50.3:5555;构造猫源行time最新+config_0偏好指向http接口的复现场景后冷启动两次:诊断日志csp-warmup schedule reason=vod-config-loaded config=4(buye-0 http接口)加载成功,无cat-source分支、无3分钟就绪超时、无'配置取得失败';复现前同状态日志显示启动进cat-source分支253457ms后报配置取得失败\n猫源启动失败;设备DB已恢复原状并复验通过

Task-Guard: fix-startup-config-selection
2026-10-03 15:37:18 +08:00
Silent1566
bfbd26bb98 修复 TMDB 线路 Picker 电视端 D-pad 焦点无法进入列表项导致选自定义无效
Verification: 修复 TMDB 线路 Picker 电视端 D-pad 无法选中列表项的根因: AlertDialog 单选列表弹出后焦点停在 listview 容器,DOWN 直接跳到取消按钮,用户选自定义实际取消了 Picker,配置保持 itv666. 修复为 show 后 setSelection(checked)+listview.requestFocus. 纯 D-pad 实测: Picker 打开焦点在 checked 项,DOWN 一次选中自定义,CENTER 确认后显示自定义输入框并聚焦,保存重开回显自定义+值,恢复自动配置也通过 D-pad 完成. 单测(leanback+mobile)通过

Task-Guard: tmdb-picker-dpad-focus
2026-10-03 14:09:15 +08:00
Silent1566
b056747894
Merge pull request #398 from Silent1566/dev2
dev2: 合并 beta 最新代码并修复集多版本消歧误伤跨线路续播
2026-10-03 13:29:55 +08:00
Silent1566
5e6af9e540 fix(tv): 修复集多版本消歧误伤跨线路续播并合并 origin/beta 复评
评审发现 dd37a13fc5 的『季号已知即按 URL 消歧』误伤跨线路/跨源续播
与源站刷新契约(换线路后 URL 必然不同 → 被判换集 → 进度从 0 开始、
选中高亮错回第一集)。改为按『历史 URL 能否定位到当前线路条目』分层:

- Episode.matchesPlayback(Episode) 恢复纯集号容错语义
- 新增 matchesPlayback(Episode, boolean versionAware):同线路内才启用
  版本消歧,保住『点第二版本不再被当作第一版本』的原始修复
- Flag.containsEpisodeUrl:消歧启用判据(与 find 的 URL 优先定位同构,
  含 TMDB 位置冲突防护)
- leanback/mobile 调用方按判据传入 versionAware;leanback
  getSelectedEpisodePosition 增加 URL 优先命中(多版本选中由 URL 锁定)
- TmdbDetailActivity.isHistoryEpisode 同样分层,炫彩内联换线路不再误停

Verification: 合并 b6877389da(dd37a13fc5 × bf9e6bcb19)无冲突;净差异与 dd37a13fc5 逐字节一致(结构性排除被回退内容夹带,5682f2b054/fd29d76ee7 负向核对通过);四轮评审发现并修复 dd37a13fc5 版本消歧误伤跨线路续播回归(versionAware 分层);定向单测 EpisodeVersionIdentityTest 17 + HistoryPlaybackTest 63、源码断言 VideoActivityLayoutTest 153 + VideoActivityHistoryTitleTest 4 全通过;bean/history/playback 契约 404 项 0 失败;修复后定向 248 通过(仅 ReaderPlaybackRoutingSourceTest 2 失败为纯合并树上同样复现的 beta 预存失败,与任务无关)

Task-Guard: C33-beta-merge-review-dev2
2026-10-03 13:11:04 +08:00
Silent1566
9d0deec460 修复 TMDB 线路选官方直连保存后重开误显示为自定义
Verification: 修复 isCustomDisplay 误判: 旧逻辑对任何非自定义文本都返回 true,导致选官方直连保存后重开误显示自定义. 改为 display 未命中任何内置选项标签才判为自定义. 模拟器实测: 选官方图片(直连)保存重开正确回显'官方图片(直连)', 自定义 URL 保存重开回显'自定义'+值, 单测 leanback+mobile 通过

Task-Guard: tmdb-route-custom-fix3
2026-10-03 11:56:58 +08:00
Silent1566
699635fca7 fix(following): propagate unfollow across one-key sync via tombstones
取消追更原为物理删除, 备份快照无法携带删除意图, TV 端 union 合并永远保留该行,
导致手机取消追更后 TV 仍需手动再删一次。

改为墓碑表方案:
- Following 增加 deleted_at 列 (v2->v3 全量重建迁移, v2 时代 enabled=0 行一并转墓碑)
- 取消追更改写墓碑 (markDeleted), 备份捕获/合并均含墓碑行, 删除意图随一键同步传播
- 合并策略墓碑分支: 双墓碑取较新; 取消后重追 (createdAt>deletedAt) 复活胜出; 旧版快照不复活
- 活行查询 (list/find/findDue/unreadCount) 过滤墓碑; 重追经 saveNew 复活并重置 createdAt
- 防复活: TMDB 身份迁移遇墓碑目标直接返回; 订阅导入跳过墓碑候选

验证: JVM Following 套件 34/34; 设备测试 16/17 (唯一失败为 HEAD 历史遗留,
stash 实证与本任务无关); 迁移/复活/防复活设备用例全绿 (emulator-5561 覆盖安装)。

Verification: JVM 34/34 (FollowingMergePolicyTest 7 用例全绿含 5 新墓碑用例); 设备 16/17 (唯一失败 FollowingActivityDeviceTest 为 HEAD 历史遗留, stash 实证无关); 迁移 v1->v3 与 v2->v3 数据保留+enabled=0转墓碑验证通过; 重追复活/订阅导入防复活/旧快照合并防复活设备用例通过

Task-Guard: C9-following-tombstone-sync
2026-10-03 11:55:48 +08:00
Silent1566
024c13b5f9 TMDB 自定义线路输入框移至对应线路下方; 线路 Picker 改为确认键弹出(不再聚焦自动弹出)
Verification: Leanback 模拟器(5559)实测: 1)apiCustomInput 紧跟 apiHostInput 正下方(y:665->792), imageCustomInput 紧跟 imageHostInput 下方, 顺序正确; 2)焦点移到线路下拉框不再自动弹 Picker, 按 DPAD_CENTER/点击才弹出, picker 含自定义选项且选中后输入框显示并自动聚焦, D-pad 焦点链 apiHost<->apiCustom<->imageHost<->imageCustom 全部可达; 单测 leanback+mobile 通过

Task-Guard: tmdb-route-custom-fix2
2026-10-03 11:14:34 +08:00
Silent1566
59d481e726
Merge pull request #397 from Silent1566/dev1
merge: 合并 beta 最新代码(PR#396)并修复影视原生模式播放页简介按钮不显示
2026-10-03 09:44:18 +08:00
Silent1566
41ab47182c TMDB API/图片线路支持下拉自定义选项与自定义输入框(电视版 D-pad 交互)
Verification: Leanback 模拟器(192.168.50.3:5559)实测: API/图片线路 Picker 含自定义选项,选中后自定义输入框显示并自动聚焦,可输入 URL,D-pad 焦点链(apiHostInput<->apiCustomInput<->imageHostInput<->imageCustomInput)可达,保存后重开弹窗回显自定义模式与值,切回内置线路后输入框隐藏;修复重开弹窗 NPE 崩溃;单测 TmdbSourceDialogInflationContractTest(leanback+mobile) 通过

Task-Guard: tmdb-route-custom
2026-10-03 09:38:45 +08:00
Silent1566
a24c85f548 Merge remote-tracking branch 'origin/beta' into dev1 2026-10-03 09:27:14 +08:00
Silent1566
dfd4e5b3f3 fix(tv): 修复影视原生模式播放页简介按钮不显示
934e831de 在隐藏 leanback 追更(following)按钮时,第一个 diff hunk 误命中了
同区块的简介(content)按钮,给它加上了 android:visibility="gone"。影视原生
(DIRECT)模式不运行 TMDB 富集路径(applyTmdbDetailFields),没有任何运行时代码
会把这个按钮恢复可见,导致简介入口永久消失。

移除该误加的 visibility=gone 恢复默认可见;新增
VideoActivityDetailShellSourceTest.directPlaybackKeepsSynopsisButtonVisibleByDefault
回归测试锁定契约。设备实测:简介按钮可见且弹窗正常展示简介。

Task-Guard: fix-direct-content-button

Verification: leanback 全量单测 4226 项 0 失败;设备 192.168.50.3:5555 实测影视原生模式播放页简介按钮可见(text=简介, bounds[896,420][1088,495])且点击后 ContentDialog 弹出完整简介文本

Task-Guard: fix-direct-content-button
2026-10-03 08:18:26 +08:00
Silent1566
b6877389da Merge remote-tracking branch 'origin/beta' into dev2 2026-10-02 23:26:59 +08:00
Silent1566
76a923fcce
Merge pull request #396 from Silent1566/dev1
fix(detail): 详情直放模式跟随光影剧幕主题
2026-10-02 23:05:28 +08:00
Silent1566
6288fd4bd1 fix(detail): 详情直放模式跟随光影剧幕主题
d964faca5 修复炫彩详情的 cinema 主题委托时遗漏了详情直放模式:
PlayerDetailController 未覆写 isCinemaStyle(),导致设置选光影剧幕后
详情直放页仍固定使用清透流彩模板。补上 host.isCinemaStyle() 委托,
并新增 DetailModeControllerTest 测试锁定该行为。

Verification: DetailModeControllerTest 13/13 通过(新增 playerDetailController_followsSelectedCinemaTheme);leanback arm64 debug 覆盖安装到 192.168.50.3:5555;运行时验证:详情直放(detail_open_mode=4)+光影剧幕(detail_theme_mode=1)下 heroSpacer=56px/28dp、title bounds [68,110][924,227]、contentPanel 全宽 radius 0(cinema 模板特征);切清透流彩(detail_theme_mode=0)后 heroSpacer=204px/102dp(profile 模板特征),两主题在直放模式下可正确区分;无崩溃;模拟器配置已恢复原始值

Task-Guard: FIX-DIRECT-CINEMA-THEME
2026-10-02 21:23:17 +08:00
Silent1566
dd37a13fc5 fix(tv): 同一 TMDB 集多版本按季号置信度消歧
Verification: verified: ./gradlew :app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.bean.HistoryPlaybackTest --tests com.fongmi.android.tv.bean.EpisodeVersionIdentityTest => BUILD SUCCESSFUL, 77 tests (15+62), 0 failures

Task-Guard: fix-episode-version-identity
2026-10-02 20:28:02 +08:00
Silent1566
bf9e6bcb19
Merge pull request #382 from Silent1566/dev3
merge: 合并 origin/beta 最新代码(PR#388–#394)并复评 dev3 全部未推送改动
2026-10-02 17:34:37 +08:00
Silent1566
4d434d2c0a
Merge pull request #395 from Silent1566/dev1
fix(tv): 恢复原生增强播放页当前线路绿色高亮描边
2026-10-02 17:32:02 +08:00
Silent1566
125837036d Merge remote-tracking branch 'origin/beta' into dev3 2026-10-02 16:34:11 +08:00
Silent1566
c92ada1015 fix(tv): 恢复原生增强播放页当前线路绿色高亮描边
Verification: leanback FlagAdapter 绑定 state_activated(绿色 2dp tvCurrentRing 描边)恢复当前播放线路高亮

Task-Guard: flag-current-highlight
2026-10-02 16:20:09 +08:00
Silent1566
f33710935c
Merge pull request #394 from Silent1566/dev1
合并 beta 最新代码并交付猫源启动超时修复(dev1)
2026-10-02 15:25:36 +08:00
Silent1566
279c16c125 merge: 增量合并 origin/beta PR#393(dev4 播放器按钮接线与默认隐藏)并复评
创建 PR 时发现远端 beta 前进至 8e4dac760(PR #393 dev4 播放器多线程/硬解
按钮接线 + 多线程按钮默认隐藏种子逻辑),增量合入 dev1 无冲突;第 3 轮评审
通过:mobile/leanback 两 flavor 按钮方法名各自匹配无错绑,HIDDEN_SEEDED
一次性种子注入与 reset 清除核对一致;净差异仍仅猫源链路 7 文件,被剔除提交
未带回。

Verification: 增量合并树 Leanback 定向单测 73 项 0 失败(含 MultiThreadProxyPlayerUiSourceTest 5 项 0 失败)

Task-Guard: C31-beta-merge-review-dev1-20261001-b

Verification: 增量合并树 Leanback 定向单测 73 项 0 失败(含 MultiThreadProxyPlayerUiSourceTest 5 项);PR#393 播放器按钮接线/默认隐藏种子逻辑核对通过;5682f2b05 仍非祖先

Task-Guard: C31-beta-merge-review-dev1-20261001-b
2026-10-02 15:17:37 +08:00
Silent1566
1fb2b558ec merge: 合并 origin/beta 最新代码(PR#391 菜单扩容 / PR#392 站点批量焦点)并复评猫源启动超时修复(含 import 整理)
合并 origin/beta 45d340418(PR #391 首页菜单追更/站点注入 + PR #392 站点批量
动作 D-pad 焦点可达修复)无冲突;两轮评审 dev1 全部未推送改动:65d709a47
猫源启动超时修复整体通过,仅修复 NodeService import 顺序错乱与 4 处 TimeUnit
全限定名冗余(无行为变化);PR #391 菜单扩容 12 项与 PR #392 enabled/clickable
语义解耦契约核对通过;无任何远端已回退内容被顺带提交(5682f2b05/59f438285/
c900dac20 均非祖先)。

Verification: 合并树 Leanback 定向单测 98 项 0 失败;Mobile 定向单测 61 项 0 失败;5555 设备覆盖安装冷启动冒烟无 FATAL/ANR

Task-Guard: C31-beta-merge-review-dev1-20261001

Verification: 合并树 Leanback 定向单测 98 项 0 失败(含 SiteDialogActionFocusTest 3 项) + Mobile 定向单测 61 项 0 失败 + 5555 设备覆盖安装冷启动冒烟无 FATAL/ANR;两轮评审通过(含 PR#391/PR#392 契约核对);被剔除提交(5682f2b05/59f438285/c900dac20)均非祖先未带回

Task-Guard: C31-beta-merge-review-dev1-20261001
2026-10-02 14:41:56 +08:00
Silent1566
8e4dac7606
Merge pull request #393 from Silent1566/dev4
merge: 合并 beta 最新代码(PR#385–#392)并复评 dev4 播放器按钮修复
2026-10-02 14:41:15 +08:00
Silent1566
475abef28c merge: 合并 beta 增量 PR#392(站点批量动作焦点修复)并复评
Verification: r2 merge clean (3 files, PR#392 SiteDialog focus fix); SiteDialogActionFocusTest 3/3 + MultiThreadProxyPlayerUiSourceTest 5/3 pass on merged tree; no revert commits in increment window; r1 evidence carried: mobile 449/0, dual-flavor compile OK

Task-Guard: beta-merge-review-r2-20261002
2026-10-02 14:28:17 +08:00
Silent1566
56f479b1d2 merge: 合并 origin/beta 最新代码(PR#385-#391)并复评 dev4 未推送的播放器按钮修复
Verification: mobile 449 tests/0 failures (MultiThreadProxyPlayerUiSourceTest 5/5), dual-flavor javac compile BUILD SUCCESSFUL, leanback 4077 tests 11 failed all pre-existing CRLF-checkout (incl. beta-new NativeEnhancedPlaybackStyleFocusTest, LF-literal vs CRLF worktree, beta LF env 9/9 documented), zero revert commits in merge window, staged tree f5c67c7144 verified

Task-Guard: beta-merge-review-20261001
2026-10-02 13:58:01 +08:00
Silent1566
45d340418a
Merge pull request #392 from Silent1566/dev2
dev2: 合并 beta 最新代码并修复站点批量动作遥控焦点可达
2026-10-02 13:26:19 +08:00
Silent1566
410b76a4ca docs: 记录 C31 dev2 合并 beta 与站点批量动作焦点修复复评
Verification: 合并 origin/beta 8ba23ac144 无冲突(HEAD..origin/beta=0;带入 diff 与 beta 侧逐字节一致;回退坐标 5682f2b054 非祖先、被删文件仍不存在、净差异仅 2 文件全为批量动作焦点修复);四轮评审 2bf29bc4c8 无需修复;合并树定向单测 SiteDialogActionFocusTest 3 用例 + HomeMenuDialogSourceTest 5 用例 BUILD SUCCESSFUL 0 失败;git diff --check 通过

Task-Guard: C31-beta-merge-review-dev2
2026-10-02 13:10:00 +08:00
Silent1566
01f14fc8ea merge: 合并 origin/beta 最新代码(PR#389/#390/#391)并复评 dev3 全部未推送改动 2026-10-01 23:55:51 +08:00
Silent1566
1b04e7a33b Merge remote-tracking branch 'origin/beta' into dev2 2026-10-01 23:27:14 +08:00
Silent1566
f912cd41ee feat(theme): add draft inline theme editor
Verification: 主题定向测试:mobile 137、leanback 139,零失败/错误/跳过;ThemeColorPickerPrecisionTest 2/2;mobile 与 leanback arm64 Debug 构建并在 192.168.50.3:5559 以 adb install -r 覆盖安装;设备验收通过默认首位、完整模板、浅深预览、草稿不落盘、精确 HEX、清空槽位、连续透明度拖动、取消不保存;任务开始偏好快照恢复后 SHA-256 校验一致;gradlew clean 成功。

Task-Guard: THEME-EDITOR-20261001
2026-10-01 23:22:36 +08:00
Silent1566
65d709a477 fix: extend cat source startup timeout and probe readiness efficiently
Verification: Targeted NodePortSelectionTest, NodeBundleInstallTest, and NodeLocalBundleTest passed via :app:testMobileArm64_v8aDebugUnitTest; mobile arm64-v8a debug APK assembled and covered-installed to 192.168.50.3:5555; device tests confirmed the supplied ghfast and catpaw sources reach 猫源已就绪 without configuration-load timeout; diff check and LSP diagnostics clean

Task-Guard: cat-source-load-timeout-20261001
2026-10-01 23:06:50 +08:00
Silent1566
2bf29bc4c8 fix(tv): keep site bulk actions reachable by remote
Verification: Robolectric SiteDialogActionFocusTest: 3 passed (2 failed before fix); SiteAdapterSelectionTest: 1 passed; assembleLeanbackArm64_v8aDebug BUILD SUCCESSFUL; emulator-5556 adb D-pad select/cancel focus verified by fresh UI XML and screenshots; test APK SHA256 7b4ef8c6a10e52d3f02cdce611961b474eaaaf68e2f093cbc0942598882d9c39; original APK and 18 app data files restored and hash-checked; temporary backups reclaimed; Gradle clean --no-daemon succeeded. Evidence: F:/temp/webhtv-site-focus

Task-Guard: tv-site-action-focus
2026-10-01 21:41:26 +08:00
Silent1566
d2853d20ad feat(tv): apply theme palettes to site dialog
Verification: 定向主题/站点 JVM 测试通过;leanback/mobile arm64 Java 与资源编译通过;leanback Debug 包成功并以 adb install -r 覆盖安装到 192.168.50.3:5559;设备实测主题编辑器 palette style 与 TV 站点弹窗动态主题通过;构建产物已清理;git diff --check 与 task_guard check 通过。

Task-Guard: THEME-TV-SITE-PALETTE-20261001
2026-10-01 20:41:32 +08:00
Silent1566
8ba23ac144
Merge pull request #391 from Silent1566/dev2
fix(tv): 首页菜单键新增追更/站点注入动作并同步 beta(含扩容注释复评修复)
2026-10-01 20:34:12 +08:00
Silent1566
de66627174 fix(tv): 同步首页菜单扩容注释并合并 origin/beta 最新代码
复评 b2e1174d76(菜单新增追更/站点注入动作)发现 4 处扩容后过时注释并修正:HomeMenuDialog Listener javadoc 1..9→1..11、GRID_COUNT 行数注释按 11 项 4 行更新、dialog_home_menu.xml tools:itemCount 9→11、测试英文文案长度 13→14 字符。
合并 origin/beta 890934423d(PR #390:dev1 猫源 node 崩溃恢复修复与 CatSpiderResolveTest、C29 dev1 文档),无冲突、未带回任何远端已回退内容。

Verification: 定向单测 HomeMenuDialogSourceTest 与 CatSpiderResolveTest 通过;git diff --check 通过

Verification: 合并 origin/beta 890934423d 无冲突(dev2..origin/beta=0;无回退内容带回:5682f2b05 非祖先、被删文件仍不存在、净差异仅 8 文件全为菜单改动);四轮评审 b2e1174d76,修复 4 处过时注释(HomeMenuDialog javadoc 1..11、GRID_COUNT 行数注释、tools:itemCount=11、测试英文文案 14 字符);定向单测 HomeMenuDialogSourceTest 与 CatSpiderResolveTest BUILD SUCCESSFUL;git diff --check 通过

Task-Guard: C30-beta-merge-review-dev2
2026-10-01 20:30:21 +08:00
Silent1566
14556212b1 Merge remote-tracking branch 'origin/beta' into dev2 2026-10-01 19:52:56 +08:00
Silent1566
d4b2f04b11 docs(player-button): record decisive device evidence that both wired buttons open their dialogs
Verification: docs-only: records the fourth-session decisive device evidence that closes the last outstanding acceptance item for player-button-wiring. Re-calibrated the device first — emulator-5556 had been re-installed by another worktree with a different mobile build (201,409,966 bytes; has onCodecCapabilityPanel but no player_button_hidden_seeded), so the fix build was re-installed via install -r -d and verified by md5 b1228ac8518d40eb344bab22f2db124b (matches local, same signing key 95E4B2E7). Corrects a prior misdiagnosis: the 0,0-0,0 bounds were parent-relative (bottom container origin 0,920), not an unlaid-out view; and app:id/action is GONE in window mode, so real landscape fullscreen is a prerequisite. With multiThreadProxy center (488,951) and codecCapability center (604,951): tapping 604,951 opened CodecCapabilityDialog (screenshot plus uiautomator dump showing 硬解能力 title, chip hardware qcom / board SM-N9700, four tabs, 当前媒体轨道 2/2, video/avc 854x480, decoder OMX.qcom.video.decoder.avc, 硬解查询 当前规格可硬解, 取消/复制); tapping 488,951 opened MultiThreadProxyDialog, proven by the dumpsys Added Fragments multi-thread-proxy tag count going 0 -> 4 (probe validity itself verified against the known report_fragment_tag) and confirmed by screenshot showing 多线程播放加速, 全局并行线程数 10, 全局分片数 256. No code or test change in this commit; markdown clean.

Task-Guard: player-button-wiring-verify4
2026-10-01 19:48:49 +08:00
Silent1566
b2e1174d76 feat(tv): add following and site injection home menu actions
Verification: 定向 Leanback 单元测试 HomeMenuDialogSourceTest 通过;覆盖首页菜单键 12 项资源、追更/站点注入动作映射、默认选项弹窗与三种语言资源;task_guard check 和 git diff --check 通过

Task-Guard: home-menu-following-site
2026-10-01 19:15:17 +08:00
Silent1566
890934423d
Merge pull request #390 from Silent1566/dev1
merge: 合并 beta 最新代码并复评修复猫源远端源误改写(猫源 node 死进程恢复 + C29 复评)
2026-10-01 19:08:05 +08:00
Silent1566
5decbb96bf merge: 合并 origin/beta 最新代码(PR#387/#388/#389)并复评修复猫源远端源误改写(含 C29 复评)
Verification: catnode dead-proc recovery + beta merge: 合并 origin/beta tip 6ee8a41dc(PR#387/#388/#389)零冲突,净差异只剩猫源修复;复评修复 CatSpider.resolve 远端 T4 api 误改写 127.0.0.1 的实质 bug(isLoopbackBase 收窄)+ NodeRuntime javadoc 与重复探活;新增 CatSpiderResolveTest 6 用例锁定契约;定向单测/双flavor编译 PASS,全量单测 --rerun-tasks 4075 项 0 失败,leanback debug APK 覆盖安装 5555 Success,冷启动 HomeActivityCurrent 无崩溃,合并清单 0 queries(Android 9 修复生效),dex 含修复字符串;被剔除提交 5682f2b05 非祖先,无远端删除文件带回

Task-Guard: C29-beta-merge-review-dev1-20261001
2026-10-01 18:58:49 +08:00
Silent1566
6ee8a41dc9
Merge pull request #389 from Silent1566/dev2
fix(tv): 搜索结果进入的播放页在详情为空时不再退出回搜索页
2026-10-01 18:28:06 +08:00
Silent1566
78c8aa4afa docs: 记录 C29 dev2 同步 beta 复评与搜索空详情修复交付
Verification: VideoActivityDetailShellSourceTest BUILD SUCCESSFUL in 2m 23s; git diff --check origin/beta dev2 passed; 2-round review passed with no code change required

Task-Guard: c29-beta-merge-review-dev2
2026-10-01 18:24:17 +08:00
Silent1566
02d81552ff docs(player-button): record third-session decisive device evidence and correct the pre-fix-APK root cause
Verification: docs-only: records the third-session decisive device evidence for player-button-wiring — (1) dex-level APK comparison proves emulator-5554/5558 were running pre-fix builds (player_button_hidden_seeded and onCodecCapabilityPanel absent), falsifying the prior sessions' implicit premise; (2) overwrite-install of the local mobile debug APK on emulator-5556 (same signing key 95E4B2E7, install -r -d, md5 b1228ac8518d40eb344bab22f2db124b) yields player_button_hidden=multi_thread_proxy plus seeded=true on real device, and View Hierarchy shows multiThreadProxy GONE / codecCapability VISIBLE by default and VISIBLE after the user enables it — three-state end-to-end proof for the default-hidden contract; (3) remaining §2.1 click->dialog evidence scope and reproduction recipe documented. No code or test change in this commit; markdown clean.

Task-Guard: player-button-wiring-verify3
2026-10-01 18:06:17 +08:00
Silent1566
0a1ca102e1 fix(tv): keep failed search detail on playback page
Verification: :app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.activity.VideoActivityDetailShellSourceTest passed; git diff --check passed; bash ./gradlew clean passed; Gradle daemon stopped

Task-Guard: tv-search-result-empty-detail
2026-10-01 16:43:31 +08:00
Silent1566
bba9e17dbb fix(tv): 猫源 node 子进程崩溃后无法感知与恢复(配置加载/搜索一直失败)
Verification: cat source dead-proc recovery: NodeRuntime now probes :node process liveness before reuse (serviceAlive), resets stale state on death; CatSpider resolves current NodeRuntime port per request and triggers restartIfDead on connection failures. Verified: Mira battle ground truth (search 404 matches user log then node dies), --rerun-tasks compile SUCCESSFUL 1m10s, 154 unit tests pass (Node 60 / Cat* 37 / SiteApi 16, 0 failures), fixed strings confirmed in dex, debug APK streamed install to 5555, app boots no crash.

Task-Guard: catnode-dead-proc-recovery
2026-10-01 16:10:58 +08:00
Silent1566
bbe7062f42
Merge pull request #388 from Silent1566/dev2
fix(tv):移除 Android 11 manifest queries,修复 Android 9 TV 启动
2026-10-01 14:55:32 +08:00
Silent1566
59f438285b merge: 合并 origin/beta 最新代码(含 PR#386/PR#387)并复评 dev3 全部未推送改动
- 合入 beta 最新 tip b184f7363:原生增强播放页统一焦点规范(tvFocusRing/tvCurrentRing/
  tvNormalStroke 三主题属性 + 4 个 selector)、纵向焦点链与海报行 rowHeight 修复、
  详情直放/沉浸融合切集旧位置回写守卫(inlinePlayerMediaReady)、历史卡片重复已看时间
  移除、融合/原生唤醒记住用户焦点修复(PR#387)。
- 保留 dev3 统一语义主题系统为存活方,删除 beta 旧 ThemeCatalog 主题系统落地文件,
  双 flavor Theme.Base 同时绑定 tv* 三属性以支撑共享 selector。
- 复评修复:演员卡焦点环圆角改用与卡片同一个尺寸 token(消除描边内缩/外溢);
  dev3 既有断言改随‘焦点环走前景 selector’新契约(消除双重描边);清理未用 import。
- 未把远端已移除/回退的提交带回(5682f2b05 非祖先,beta 回退删除文件均未恢复)。

Verification: 双flavor全量单测9235项0失败(leanback4186/mobile5049,各2跳过);双flavor Java编译通过;mobile与leanback Debug打包并覆盖安装到192.168.50.3:5559成功;设备实测设置→外观与语言→主题色彩→焦点色→精确十六进制全链路无崩溃、v2主题键完好;tvFocusRing/tvCurrentRing/tvNormalStroke三属性双flavor绑定闭环;git diff --cached --check通过、无冲突标记、无重复view id/资源名;MERGE_HEAD=b184f7363(beta tip)、0未解决冲突、被剔除提交5682f2b05非祖先、beta回退删除文件未带回

Task-Guard: C29-BETA-MERGE-REVIEW-DEV3-20260930
2026-09-30 19:30:52 +08:00
Silent1566
8cd77ba46e fix(tv): remove Android 11 manifest queries for Android 9
Verification: Android 9/API 28 emulator-5556: adb install -r leanbackArmeabi_v7a debug APK succeeded; app launched and mResumedActivity=HomeActivityCurrent; no Unknown element under manifest, FATAL EXCEPTION, or process death; merged manifest HAS_QUERIES=False; git diff --check passed

Task-Guard: tv-android9-update-crash-final
2026-09-30 18:35:56 +08:00
Silent1566
b184f7363c
Merge pull request #387 from Silent1566/dev2
fix(tv):修复控制栏唤醒焦点错位并同步 beta
2026-09-30 16:54:26 +08:00
Silent1566
7e0ae4af6f docs: 记录 dev2 合并 beta 与焦点修复复审
Verification: origin/beta 已完整合入且 dev2..origin/beta=0;合并后仅保留 3 个本地焦点修复的 4 文件净差异;远端已移除提交 5682f2b054 不在 dev2;Mobile 定向 298 项与 Leanback 定向 12 项共 310 项通过;assembleLeanbackArm64_v8aDebug 成功,emulator-5556 使用 adb install -r 覆盖安装并启动到 HomeActivityCurrent,无 FATAL EXCEPTION/ANR/Fatal signal;已执行 ./gradlew clean

Task-Guard: beta-merge-review-dev2-20260930
2026-09-30 16:47:15 +08:00
Silent1566
4cb165a0fc
Merge pull request #386 from Silent1566/dev1
fix(tv): 统一原生增强播放页 TMDB 焦点环并修复海报行与纵向焦点链(含合并 beta 最新代码)
2026-09-30 15:04:29 +08:00
Silent1566
fc36522d2e fix(tv): 统一原生增强播放页 TMDB 焦点环并修复海报行与纵向焦点链(含合并 origin/beta 最新代码)
Verification: C28: 合并 origin/beta@8f7376295 后 2 轮复评 dev1 净差异(3 个未推送提交/7 文件);修复 3 处中文文案错别字(塔陷->塌陷)与 1 处文件末尾缺换行;定向单测 TmdbRowFocusChainTest 10/10 + NativeEnhancedPlaybackStyleFocusTest 14/14 全通过,双 flavor Java 编译通过;Leanback 全量单测 4068 项 0 failure/0 error;leanback arm64 Debug 打包 196M 并以 adb install -r 覆盖安装成功(未卸载);设备 192.168.50.3:5555 端到端实测焦点链 剧照->海报->相关视频->主创->推荐->个性推荐 全部命中、向上反向完整、空行自动跳过,海报行 h=444(原塌陷),三处卡片焦点环像素扫描均为 6px=3dp #FFD166 矩形环,logcat 无 FATAL/ANR;5965b 与主题系统文件未随净差异带回(diff --diff-filter=D 为空)

Task-Guard: C28-beta-merge-review-dev1-20260930
2026-09-30 14:20:45 +08:00
Silent1566
c53fce8d61 fix(ui): 主题色彩弹窗保留主题面板,不再把窗口背景换成透明
Verification: dev3 192.168.50.3:5559 覆盖安装 mobile arm64 后真实点击路径(设置→外观与语言→主题色彩)截图确认面板恢复不透明主题圆角面板,外框 [28,48][1892,1032]=1864x984 与 4.32 实测一致(放大占比未回退),标题/预设芯片/8 行色槽/恢复默认-取消-应用 均可见,底层设置页不再透出;根因由 Material 1.14.0 MaterialAlertDialogBuilder.create() 源码(window.setBackgroundDrawable(insetDrawable(background, insets)))与 WebHtvAlertDialogBuilder 现有注释(面板即 window background)双向确认;:app:testMobileArm64_v8aDebugUnitTest 与 :app:testLeanbackArm64_v8aDebugUnitTest 的 ThemeDialogLayoutTest 各 5 项 0 failure/0 error,两个 flavor 的 ThemeDialog 均编译通过(两文件逐字节相同)

Task-Guard: THEME-EDITOR-DIALOG-PANEL-REGRESSION-20260930
2026-09-30 14:11:52 +08:00
Silent1566
c14d146f0b Merge remote-tracking branch 'origin/beta' into dev2 2026-09-30 14:04:37 +08:00
Silent1566
41c5e904a4 fix(ui): 主题色彩弹窗放大占比,对齐广告拦截统计弹窗窗口契约
Verification: leanback 1920x1080 设备实测主题色彩弹窗外框 [48,48][1872,1032]=1824x984 (95.0%x91.1%),mobile 实测 [28,49][1892,1073]=1864x1024 (97.1%x94.8%),与同设备参考弹窗 AdBlockStatsDialog 实测数值完全一致;13 色槽+3 透明度滑块+实时预览滚动可达,恢复默认/取消/应用三按钮完整可见;:app:testMobileArm64_v8aDebugUnitTest 5041 项、:app:testLeanbackArm64_v8aDebugUnitTest 4169 项,0 failure / 0 error;:app:compileMobileArm64_v8aDebugJavaWithJavac 通过

Task-Guard: THEME-EDITOR-DIALOG-SIZE-20260930
2026-09-30 13:55:38 +08:00
Silent1566
678a7d1483 fix(tv): 修复融合控制栏点击后唤醒焦点落错按钮
用户反馈:点击播放参数后再唤醒控制栏,焦点落在选集按钮上,而非上次点击的按钮。

两处同源缺陷:
1) setupInlineControl 只监听 OnFocusChange。鼠标/触摸点击不移动焦点,
   用户点过的按钮从未进入 inlineControlFocus;唤醒时只能落到默认候选,
   而候选里 next/fullscreen/prev/reset 被隐藏,第一个可见的正是选集按钮。
   补 OnTouchListener 在 ACTION_DOWN 记录被点击按钮,返回 false 不吞事件。
2) PlayerControlFocusHelper.ensureFocus 在 root 内已有焦点时提前返回,
   使调用方明确传入的目标被静默忽略。改为显式目标优先,其次沿用 root
   内已有焦点,最后回退 firstFocusable(root)。

手机端不挂触摸监听,触控语义不变。

验证:PlayerControlFocusIntegrationTest 10/10 通过。

Verification: 定向单测 :app:testMobileArm64_v8aDebugUnitTest --tests PlayerControlFocusIntegrationTest BUILD SUCCESSFUL,结果 XML tests=10 skipped=0 failures=0 errors=0(新增 tvControlClickIsRememberedAndPreferredFocusWinsOnWake,既有 9 项无回归),2026-09-30 12:26;assembleLeanbackArm64_v8aDebug BUILD SUCCESSFUL(4m49s)并 -r 覆盖安装到 127.0.0.1:5557(lastUpdateTime 2026-09-30 12:36:07,未卸载);设备实测未取证:模拟器窗口焦点反复漂移到 launcher/null(mCurrentFocus=null)、控制栏 10s 自动隐藏与 uiautomator dump 时序冲突,多次尝试后按契约停止该路线

Task-Guard: TV-fusion-click-focus-20260930
2026-09-30 13:22:15 +08:00
Silent1566
5026e2147f fix(tv): restore poster row height and TMDB row focus chain
Verification: leanback 全量单测 4068 tests/0 failures(含 TmdbRowFocusChainTest 10、NativeEnhancedPlaybackStyleFocusTest 14),构建 11:34:37 晚于最终编辑 11:32:18;设备 192.168.50.3:5555 端到端验证:播放页 TMDB 行向下链条 剧照->海报(缺相关视频行自动跳过)->相关视频->主创->推荐->个性推荐 全部命中,向上链条反向完整;海报行占位 y=907..1080(原塌陷为0)且卡片显示、聚焦有 3dp 黄环

Task-Guard: tv-poster-row-height-focus
2026-09-30 13:17:21 +08:00
Silent1566
cbe19f945a docs(player-button): append second-session device-verification findings and final evidence scope
Verification: docs-only: appends the second-session device-verification findings (double-tap pause works but dump still fails; fragment-name signal confirms the click does not reach MultiThreadProxyDialog; BACK exits fullscreen; show-bar tap is a toggle and backfires). No code or test change in this commit.

Task-Guard: player-button-wiring-verify2
2026-09-30 02:53:54 +08:00
Silent1566
5e88018541 docs(player-button): record device-verification blocker and exact action-row coordinates for the 多线程/硬解能力 fixes
Verification: docs-only: records the emulator-5556 device-verification blocker for the player-button-wiring fix (no code or test change in this commit); markdown lint clean

Task-Guard: player-button-wiring-verify
2026-09-30 02:26:35 +08:00
Silent1566
e82cdce5cf fix(tv): restore related video focus highlight and row focus chain
Verification: 全量 Leanback 单测 BUILD SUCCESSFUL;git diff --check 通过;设备 192.168.50.3:5555 实测:动画缩放恢复 1.0 后加载指示器三帧旋转角度不同(点→短弧→长弧)证明转圈动效恢复;uiautomator 焦点节点判定剧照行卡片[48,546][488,794]按向下可落到相关视频行卡片[37,552][611,876](16:9);像素检测相关视频卡焦点环为 rgb(255,209,102)=#FFD166 且构成长直边矩形环

Task-Guard: tv-related-video-focus-navigation
2026-09-29 20:04:34 +08:00
Silent1566
46505877d5 fix(ui): 可选中的壁纸条目恢复状态色表,修正选中态白字压亮底
修正 e66a7d3cb 引入的回退:该提交把 21 个布局一律改成恒亮
?attr/webhtvColorOnWallpaper,但这些条目里有 7 个的填充是
「随状态变化」的,单一颜色必然在其中一个状态上失配。

根因(移动版 selector_item):
    state_selected -> ?attr/colorSecondaryContainer @0.65 alpha  = 日间亮灰
    默认           -> @color/black @0.15 alpha                   = 深色
实测首页类型芯片:选中填充 #BAB9C5(原色 #DFE2E6 叠壁纸),未选填充
#645C74;白字在选中态仅 1.94:1(不可读),深字在未选态仅 2.71:1。
两边都错,必须用状态色表。

这不是新设计:统一改造 f63b0a81b 之前,dev3 这 7 个文件本来就用状态色
表,是那次改造把「文字这一半」压平成了单一 ?attr/colorOnSurface,既变暗
又丢掉了选中高亮。

修复 = 精确还原到 f63b0a81b^ 的文字色(已逐文件 diff 验证):
  adapter_collect / adapter_type            -> @color/selector_text
  adapter_episode_grid/group/hori/flag/quality -> @color/selector_video_text
  其中 5 个 textColor 与改造前逐字节一致;adapter_episode_grid 与
  _hori 的 overview 由 #E6FFFFFF 改为 ?attr/webhtvColorOnWallpaper
  (同义,且避免新增硬编码 hex 触发 check_ui_tokens 门禁)。

两者 dev3 都仍在且未被引用,本次重新启用:
  selector_text       : selected -> ?attr/colorOnSecondaryContainer, 默认 @color/white
  selector_video_text : selected -> @color/yellow_500,              默认 @color/white

保留恒亮 token 的 14 个布局其填充在所有状态下都是深的
(shape_live #47000000/#5C000000、shape_vod_list/shape_vod_name #33000000、
shape_video_episode_grid #99000000、shape_quick_search_item、
?attr/colorSurfaceContainer*),且 TypeAdapter/CollectAdapter 之外的适配器
经核查均不调用 setSelected(RecordAdapter/WordAdapter/HotWordAdapter/
QuickAdapter 均为 0 次),故无须状态色表。

Verification: 静态:7 个文件 textColor 与 f63b0a81b^ 逐文件 diff(5 个完全一致,2 个仅 hex->语义 token);全部 0 处残留 ?attr/colorOnSurface;check_ui_tokens.sh --strict 对比度 38 组 0 失败(min 4.28),唯一 violation item_following.xml 为改动前既有。单测::app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.theme.* 与 ui.style.UiStyleSourceTest 全绿(含新增 selectableWallpaperItemsKeepAStateList 与 wallpaperStateListsAreLightByDefaultAndDistinctWhenSelected 两个门禁)。设备:dev3 192.168.50.3:5559 经 scripts/build_arm64_debug_install.sh --flavor mobile 覆盖安装;logcat InflateException/ResourceNotFound/FATAL EXCEPTION 均为 0(仅出现 WorkManager SystemJobService ANR 一次,与本次纯 textColor 改动无关)。实测像素:首页类型芯片选中「电影」填充 (186,185,197),文字实测 (27,27,27) -> 8.89:1(修复前同一处白字仅 1.94:1);未选「电视剧」填充 (100,92,116),白字 6.32:1。剧集/线路行 selector_video_text:填充为 black_30/50/60 叠暗底(实测约 (12,12,12)),白字 19.56:1、选中黄字 16.02:1(旧深字仅 1.14:1)。遗留:视频源解析失败(播放地址解析失败),未能进到剧集列表对话框内实测选中黄字;该项已由状态色表定义与静态对比度计算佐证。

Verification: 7 文件 textColor 与 f63b0a81b^ 逐文件 diff(5 完全一致);0 处残留 colorOnSurface;theme.* 与 UiStyleSourceTest 全绿(+2 门禁);check_ui_tokens --strict 对比度 38 组 0 失败;dev3 覆盖安装无布局异常;首页选中芯片实测 8.89:1(修前 1.94:1)、未选 6.32:1

Task-Guard: WALLPAPER-STATE-TEXT-20260929
2026-09-29 18:33:27 +08:00
Silent1566
593c04d052 fix(tv): 沉浸融合唤醒控制栏不再被片头/片尾抢占
融合模式 getInlineControlFocus() 把片头/片尾按钮当成合法「上次焦点」,
遥控端唤出控制栏时会被还原到片头/片尾,覆盖用户真正选中的按钮,
与影视原生模式已修的问题同源但判定不对称。

抽出 hasRememberedInlineControlFocus(),遥控端仅「用户真实选中过的普通
控件」算有效记忆焦点,片头/片尾一律排除;手机端保持原有触控语义不变。
落点回退仍为 playerNext,非片头。

验证:PlayerControlFocusIntegrationTest 9/9 通过(新增
fusionControlWakeKeepsUserChosenFocusOutsideTheIntroRange)。

Verification: 定向单测 :app:testMobileArm64_v8aDebugUnitTest --tests PlayerControlFocusIntegrationTest BUILD SUCCESSFUL;结果 XML tests=9 skipped=0 failures=0 errors=0(含新增 fusionControlWakeKeepsUserChosenFocusOutsideTheIntroRange 与既有 leanbackControlWakeKeepsUserChosenFocusOutsideTheIntroRange,无回归),2026-09-29 17:10;设备实测:emulator-5556(leanback 包)可进入 TmdbDetailActivity 内嵌播放器并 dump 到 playerControls/playerOpening/playerDanmaku 等控件,但注入 CENTER/DPAD_UP 无法稳定进入融合全屏控制栏(bar=hid),故融合模式端侧行为本次仍未取证

Task-Guard: TV-fusion-focus-20260929
2026-09-29 17:27:31 +08:00
Silent1566
e66a7d3cb4 fix(ui): 壁纸之上的页面列表文字统一为亮色
承接 59ea0fe6c(设置页 257 处),补完同类遗漏:列表项与叠加视图同样压在
深色壁纸/视频上,却仍用 ?attr/colorOnSurface —— 日间模式解析为 #1A1C1E,
深字压深底。

判定依据不是文件类型,而是「文字最近祖先背景 + 宿主是否对话框」:
  · 半透明黑或透明背景(shape_live #66000000、shape_item/shape_item_round
    /shape_search_hot_word → @color/selector_item 15%% 黑、shape_vod_list
    #33000000、shape_vod_name、shape_video_item → selector_video_item
    #80000000/#4D000000、shape_video_episode_grid #99000000)→ 需亮字
  · 不透明亮底(shape_light_dialog_item #FFFFFF、selector_custom_csp_item
    #FFFFFF/#E8F0FE、selector_git_cloud_card #E8F0FE、colorSurfaceContainer
    /Lowest)→ 深字本就正确,不动

上游权威证据(/home/maple/orca/webhtv):这些项目原本全是亮色 ——
@color/white、@color/white_60/80、@color/selector_video_text(默认项为白)。
dev3 的「统一为 colorOnSurface」才是回归。

关键结论:6 个双上下文布局无需分上下文着色。上游在 dialog_quick_search、
dialog_episode_list、dialog_receive 里复用的正是同一批 item 布局,且同样是
亮色;这两个对话框还是透明窗口 + #66FFFFFF 玻璃面板悬于视频之上。
因此单一恒亮角色在页面与对话框两侧都正确,无需给
ThemeOverlay.WebHTV.Dialog 加重映射(该 overlay 也只挂在 materialAlertDialogTheme
上,够不到 BottomSheetDialogFragment)。

改动:
  15 个仅页面布局 19 处 + 6 个双上下文布局 9 处,共 28 处 android:textColor
  由 ?attr/colorOnSurface 改为 ?attr/webhtvColorOnWallpaper,零结构改动。
  测试:ThemeBaseWiringTest 新增 WALLPAPER_ITEMS 清单(21 项,含上游依据注释),
  并让既有 wallpaperPagesUseTheWallpaperForegroundRole 同时覆盖页面与列表。

Verification: 静态:21 个布局残留 colorOnSurface=0、新引用=28(15 个 19 处 + 6 个 9 处);替换前逐处断言全部落在 android:textColor 上。check_ui_tokens.sh --strict 对比度 38 组 0 失败(min 4.28),唯一 violation item_following.xml 为动手前既有、不在本次变更集。单测::app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.theme.* 与 ui.style.UiStyleSourceTest 全绿(含新清单)。设备:dev3 192.168.50.3:5559 经 scripts/build_arm64_debug_install.sh --flavor mobile 覆盖安装成功,无崩溃(logcat 无 AndroidRuntime/FATAL/InflateException)。实测像素(搜索页芯片 = shape_item_round,背景均匀最适合测量):芯片「中文字幕」底 (115,106,134),白字 5.08:1;芯片「兰香如故」底 (113,104,132),白字 5.23:1;两处若仍用 colorOnSurface(#1A1C1E) 仅 3.37:1 / 3.27:1,不达 WCAG AA 4.5。遗留未测:设备在验证中途掉线(No route to host),直播页 adpter_channel/group/epg_data 与 6 个双上下文布局在对话框内的呈现未取得设备截图;两者均已由上游同款布局+同款亮色与静态检查佐证,但未获本机实测像素。另一处已知同类残留(未处理、需另行授权):这些 item 里作次要文字用的 ?attr/colorOnSurfaceVariant 日间为 #44474F,同样偏暗;仓库无「壁纸上的次要前景色」token,上游对应值是 @color/white_60/80,需要新增语义角色才能修。

Verification: 21 布局残留 0 / 新引用 28;theme.* 与 UiStyleSourceTest 全绿;check_ui_tokens --strict 对比度 38 组 0 失败;dev3 覆盖安装无崩溃;搜索页芯片实测白字 5.08:1/5.23:1(改前口径 3.37:1/3.27:1)

Task-Guard: PAGE-LIST-FOREGROUND-20260929
2026-09-29 14:44:04 +08:00
Silent1566
4432937d2f fix(tv): highlight enhanced media focus
Verification: LSP diagnostics clean for both changed Java presenters; git diff --check passed; ./gradlew :app:assembleLeanbackArm64_v8aDebug --stacktrace completed BUILD SUCCESSFUL

Task-Guard: tv-enhanced-media-focus
2026-09-29 13:58:16 +08:00
Silent1566
8f73762950
Merge pull request #385 from Silent1566/dev1
fix(tv): 统一原生增强播放页焦点视觉并补全纵向焦点链
2026-09-29 13:06:13 +08:00
Silent1566
15b738cc83 fix(tv): 统一原生增强播放页焦点视觉并补全纵向焦点链
Verification: 已同步并确认 origin/beta@5cba7b00b 为最新基线;最终复评通过,git diff --cached --check 通过且无冲突标记,未夹带远端已移除或回退的独立提交;定向回归 NativeEnhancedPlaybackStyleFocusTest 与 VideoActivityLayoutTest BUILD SUCCESSFUL;Leanback 与 Mobile 全量回归共 4951 项,2 项失败、2 项跳过,其中两项 TmdbUIAdapterTest 失败已在 origin/beta@5cba7b00b 独立工作树按正确包名复现为 2/2 失败,确认属于 beta 基线既有问题

Task-Guard: NATIVE-ENHANCED-PLAYBACK-STYLE-FOCUS-BETA-REVIEW-20260929
2026-09-29 13:00:56 +08:00
Silent1566
c7fba76a46 fix(tv): 影视原生唤醒控制栏优先恢复用户记忆焦点
片头/片尾区间内按 DPAD_UP 唤醒控制栏时,焦点被无条件抢占到片头按钮,
覆盖用户上次选中的按钮(弹幕/字幕等),表现为「开完面板回来被拽回片头」。

抽出 hasRememberedFocus() 共享判定,仅在无可用记忆焦点时才走片头/片尾
快捷聚焦;getFocus2() 与之复用同一判定,语义与改动前严格等价。
上游「片头区间快捷聚焦」意图保留。

验证:PlayerControlFocusIntegrationTest 8/8 通过(新增回归用例
leanbackControlWakeKeepsUserChosenFocusOutsideTheIntroRange);
assembleLeanbackArm64_v8aDebug 构建通过。设备行为未取证。

Verification: 定向单测 testMobileArm64_v8aDebugUnitTest 的 PlayerControlFocusIntegrationTest 8 tests / 0 failures / 0 errors(含新增 leanbackControlWakeKeepsUserChosenFocusOutsideTheIntroRange),结果 XML 于 2026-09-29 09:31;assembleLeanbackArm64_v8aDebug BUILD SUCCESSFUL(APK 201,288,697 bytes,10:25);设备实测未完成:emulator-5556 覆盖安装 leanback 包成功(签名 95e4b2e7 一致,未卸载),但注入 CENTER 未能进入全屏,onKeyUp 唤醒路径未被触发,且原外网源 一瓯春 已失效(連接超时/这里什么都没有),故设备侧行为未取证

Task-Guard: TV-focus-return-20260929
2026-09-29 12:11:00 +08:00
Silent1566
59ea0fe6c8 fix(ui): 壁纸之上的页面文字改用专用前景色角色
页面与弹窗争用同一个 ?attr/colorOnSurface,是 9/28 两次返工的根因:
  mobile 页面画在深色壁纸(CustomWallView)上,弹窗画在浅色面板上。
  一张色表只能满足一边——亮表让页面近黑压深壁纸(实测 3.36:1,
  不达 WCAG AA),暗表让弹窗浅色卡片配亮字(1.24:1)。
修法:新增 webhtvColorOnWallpaper 角色(恒为 #FFFFFF),只给壁纸之上的页面用。

改动:
  tokens:三张表(light/night/leanback)各加 webhtv_on_wallpaper = #FFFFFF。
    命名避开 webhtv_color_ 前缀,与 webhtv_on_surface_20/70/80/90 同族,
    不进入 ThemeContractTest 冻结的 49 项 Material 角色契约。
  attrs/styles:声明 webhtvColorOnWallpaper 并在 Theme.WebHTV 赋值;
    弹窗(ThemeOverlay.WebHTV.Dialog)、卡片 drawable 一律未动。
  layouts:9 个设置页共 257 处 android:textColor 由 ?attr/colorOnSurface
    改为 ?attr/webhtvColorOnWallpaper,零结构改动、零 Variant 混入。
  test:ThemeBaseWiringTest 新增两个守门测试——壁纸页不得再用
    colorOnSurface;该角色须三表齐备且 ThemeBinder 永不重写它。

Verification: 静态:9 个设置页残留 colorOnSurface=0、新引用=257;全仓仅这 9 个布局使用新 attr,弹窗布局 0 处使用。check_ui_tokens.sh --strict 对比度 38 组 0 失败(min 4.28),唯一 violation item_following.xml 为动手前既有、不在本次变更集。单测::app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.theme.* 与 ui.style.UiStyleSourceTest 共 117 项 0 失败(含两个新增守门测试;期间修正了一次断言错误——dark 表 0xFFFFFFFF 无任何 ThemeRole 承载,light 表由 4 个角色共享,两者均返回 null,故守门断言改为行为不变量而非机制)。设备:dev3 192.168.50.3:5559 经 scripts/build_arm64_debug_install.sh --flavor mobile 覆盖安装成功(未卸载)。实测像素:设置页与播放设置子页标签均为纯 #FFFFFF,白字 vs 行背景 6.47:1、vs 壁纸 5.09:1,修前深字 #1A1C1E vs 同壁纸仅 3.36:1;同屏弹窗仍为浅面板 #E1E2E9 + 深字,对比度 13.23:1,确认弹窗未被本次改动影响。遗留(不在本次范围,需另行授权):其余 mobile 页面(约 23 个 adapter_*、view_empty、view_progress)仍用 ?attr/colorOnSurface,同样压在壁纸上,存在同类低对比;dialog_* 布局属浅色面板,不可改。

Verification: 9 页 257 处替换+残留 0;theme/UiStyleSource 单测 117 项 0 失败;check_ui_tokens --strict 对比度 38 组 0 失败;dev3 覆盖安装实测 白字 6.47:1/5.09:1、弹窗 13.23:1

Task-Guard: PAGE-ON-WALLPAPER-ROLE-20260928
2026-09-29 11:14:24 +08:00
Silent1566
62670b6413 fix(player): wire mobile multi-thread and codec-capability buttons and hide multi-thread by default
Verification: MultiThreadProxyPlayerUiSourceTest 5/5 pass on mobile flavor (incl. new multiThreadButtonIsHiddenByDefaultButStillUserConfigurable); compileMobileArm64_v8aDebugJavaWithJavac + compileLeanbackArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL; mobile targeted set 413 tests/1 failed and leanback full 4045 tests/10 failed, all reproduced on clean baseline HEAD (pre-existing CRLF multi-line source-text assertions in untouched files)

Task-Guard: player-button-wiring
2026-09-29 09:54:53 +08:00
Silent1566
5cba7b00b0
Merge pull request #384 from Silent1566/dev4
fix(mobile): 移除手机版历史卡片重复的已看时间并清理死代码
2026-09-28 21:52:24 +08:00
Silent1566
fd29d76ee7 revert: 撤销把电视版暗色配色搬到手机版的两个提交
上游手机版与电视版配色本就不同,不应统一:
  mobile   Theme.Base parent = Theme.Material3.DynamicColors.DayNight
  leanback Theme.Base parent = Theme.Material3.Dark
上游弹窗面板 shape_shell_proxy_dialog 用 @color/white 硬编码,
弹窗行文字硬编码 #202124/#5F6368;上游无 values-night、无 webhtv_tokens。

问题根因:?attr/colorOnSurface 同时被「页面(深色壁纸)」与「弹窗(浅色面板)」
引用,单张色表无法同时满足两者。

撤销:
  a6a470c2f 为 mobile 新增暗色表(使弹窗面板变深)
  db793d5af 把 19 个白底卡片改为跟随主题(使卡片也变黑)

还原后弹窗恢复上游浅色观感:面板 #E7E8EF、卡片 #F8F9FA、文字 #1A1C1E。

Verification: 回退把电视版暗色表搬到手机版的两个提交,恢复上游「浅色弹窗 + 白卡片」正确观感。背景:12:04 a6a470c2f 给 mobile flavor 新增 values/webhtv_tokens.xml(内容=leanback 暗色表),使手机版弹窗面板由浅色变深色;16:16 db793d5af 又把 19 个白底卡片改成跟随主题,把卡片也弄黑。用户指出上游手机版弹窗本就是白底深字,暗色是电视版专属——证据:上游 mobile/res/values/styles.xml 的 Theme.Base parent=Theme.Material3.DynamicColors.DayNight.NoActionBar(DayNight),leanback=Theme.Material3.Dark.NoActionBar(固定深色);上游 shape_shell_proxy_dialog.xml 面板用 @color/white 硬编码,AppearanceDialog 行文字硬编码 #202124/#5F6368 深色;上游无 values-night、无任何 webhtv_tokens.xml。根因:?attr/colorOnSurface 同时被「页面(深色壁纸+15%黑行背景)」和「弹窗(浅色面板)」引用,单张色表无法同时满足两者——暗表修好页面却弄坏弹窗,亮表反之。实施:git revert --no-commit db793d5af a6a470c2f,精确还原到 a6a470c2f 之前的 9554195c9 状态(mobile 暗色表删除、19 个 drawable 恢复上游字面量)。验证:git diff 9554195c9 对全部 21 个变更文件为空(逐字节还原);单测 UiStyleSourceTest/ThemeBaseWiringTest/ThemeContractTest 共 17 项 0 失败;check_ui_tokens.sh --strict 对比度 38 组 0 失败 min=4.28(violations=1 为预存 item_following.xml,非本次引入);设备 dev3 192.168.50.3:5559 mobile arm64 debug 覆盖安装后冷启动,打开「外观与语言」弹窗实测面板 #E7E8EF、卡片 #F8F9FA、卡片文字 #1A1C1E(对比度 81.33:1),与上游一致。遗留(下一单元处理):页面侧 ?attr/colorOnSurface 仍解析为 #1A1C1E 近黑,压在深色壁纸上,即用户 11:17 首次投诉的「半黑半白」,需按上游 @color/white 白字语义单独修复。

Task-Guard: REVERT-TV-PALETTE-20260928
2026-09-28 21:12:21 +08:00
Silent1566
127d335951 docs: 收口观看历史任务状态与交付坐标
Recovery anchor 原记录停留在提交前状态(写有'不 push'与'由 guard finish 提交'),与已完成的推送和 PR 创建不一致;更新为已交付状态并记录 PR Silent1566/webhtv#384(base beta,保持 OPEN 不代为合并)。仅文档变更。

Verification: 文档收口修正:Recovery anchor 的当前状态与唯一下一动作已更新为已交付(dev4 已推送、PR Silent1566/webhtv#384 base beta 已创建且保持 OPEN 未合并),删除了误导性的'不 push'与'由 guard finish 提交'表述;仅文档变更,无代码/资源/依赖改动,不影响已在 PR#384 中验证的 3/3 定向单测与 TV 编译结果

Task-Guard: beta-merge-review-r3-dev4-doc-20260928
2026-09-28 21:09:06 +08:00
www.xueximeng.com
ff3f8d7045 fix(cache): 修复自动清理与临时文件清理的评审问题
评审发现并修复三项问题:

1. 临时文件"报告≠删除":清理候选此前按另一份手写前缀白名单匹配,
   与注册表统计集合(.apk/.zip/.tmp/.log 后缀)不一致,导致同步 zip、
   goProxy.log 等界面报告的临时文件永远清理不掉。现改为从注册表
   TEMP_FILES 模块定义派生候选集合(单一来源),保留在用传输保护。
2. 自动清理计划忽略 allowAutomaticCleanup 声明:设计 §13.2 要求"只对
   allowAutomaticCleanup 模块生成 plan",原实现仅排除诊断日志,导致
   GLIDE、WEBHOME_RAW 虽声明不可自动清理仍会进入自动 STANDARD 计划。
   现按 CachePolicyEngine.allowsAutomatic 过滤。
3. 自动清理开关关闭后进程内定时任务仍会清理:startup/periodic/limit
   三项检查现每次 tick 重新读取开关,与 cancelPersistent 取消平台作业
   的行为一致。

Verification: 63 cache 单元测试全通过(含新增 CacheAutoPlanAndTempFamilyTest 6 例);mobile/leanback 双形态编译 BUILD SUCCESSFUL

Task-Guard: review-cache-temp-and-auto-filter
2026-09-28 20:49:12 +08:00
Silent1566
b25377f169 fix(mobile): complete removal of duplicate watched time dead code
复评上一轮提交发现文档断言不实:HistoryProgressFormatter 的最后生产调用已由 TV 清理 7605a7d589 移除,上一轮删掉手机端调用后该类及其资源已无任何生产引用,属死代码。

- 删除 app/src/main/java/com/fongmi/android/tv/utils/HistoryProgressFormatter.java 及其单测
- 删除 values/values-zh-rCN/values-zh-rTW 三处已无引用的 history_watched_time
- HistoryAdapterTest 将单文件字符串断言升级为手机布局+双端适配器+三语言字符串的结构断言,并新增死代码回流防线
- 修正 docs/HISTORY-COVER-PROGRESS.md 中不实记载并补录复评修正与验证证据

Verification: 复评发现上一轮提交的文档断言不实:HistoryProgressFormatter 在合并基线的 TV 清理 7605a7d589 后已无生产调用,上一轮又删掉其最后调用者,故该类/其单测/history_watched_time(三语言)成死代码。修正为删除死代码并升级断言:JAVA_HOME='C:\Program Files\Android\Android Studio\jbr' bash ./gradlew :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.adapter.HistoryAdapterTest → BUILD SUCCESSFUL,JUnit XML tests=3 skipped=0 failures=0 errors=0(含新增 removedBelowPosterTimeHasNoLeftoverProductionReferences);判别力负向对照:把 @+id/historyProgress 节点插回手机布局后同一命令 3 tests completed, 2 failed(BUILD FAILED),还原布局后恢复通过;同批 :app:compileLeanbackArm64_v8aDebugJavaWithJavac → BUILD SUCCESSFUL;grep 确认非 build 路径下无 HistoryProgressFormatter/history_watched_time 残留

Task-Guard: beta-merge-review-r3-dev4-20260928
2026-09-28 20:42:08 +08:00
Silent1566
db793d5af6 fix(ui): 弹窗亮底卡片改用语义 token 消除亮字压亮底
19 个 drawable 硬编码 Google 亮色调色板(#F8F9FA/#E8F0FE/#DADCE0 等),
dev3 统一主题系统时只替换了文字色这一半(956 处 ?attr/colorOnSurface),
未替换背景那一半,导致单一 token 无法同时适配深色壁纸与浅色卡片:
亮表下页面文字全黑,暗表下弹窗浅底配浅字(实测 #E2E2E9 on #F8F9FA = 1.24:1)。

按仓库既有 dialog_card_bg.xml/dialog_card_stroke.xml 约定改为语义 token:
primary_container / primary / surface_container_low / surface_container_high /
surface_container / outline_variant / success_container / success / transparent。

纯字面量替换、零结构改动。亮暗双表最差配对 7.04:1;受影响界面:
外观与语言、Git 云备份、代理规则、播放器 OSD、MPV 配置、去广告规则、
退出确认、快捷搜索、Ad 统计。

Verification: 深色弹窗亮底卡片语义化,消除「亮字压亮底」失效配对。目的:用户反馈手机版默认场景下外观与语言弹窗观感变丑、与上游基准不符。根因:上游靠「硬编码成对」成立(页面深壁纸配 @color/white 白字;弹窗浅面板配 #F8F9FA 亮卡片 + #202124 深字),dev3 统一主题系统时只把「文字」这一半换成单一 token ?attr/colorOnSurface(956 处),未替换「背景」那一半——19 个硬编码亮底 drawable(selector_git_cloud_card/css_item/dialog_switch/mpv_icon_button 等),于是一字一色无法同时适配深壁纸与浅卡片:亮表下页面全黑字、暗表下弹窗亮字压亮底。A/B 方案否决:纯 revert a6a470c2f 会精确退回用户 11:17 投诉态且波及全部 956 处。实施:按仓库既有 dialog_card_bg.xml/dialog_card_stroke.xml 约定,把 19 个 drawable 的字面量替换为语义 token(#E8F0FE/D2E3FC/DCEAFF/F4F8FF/F1F6FF→webhtv_color_primary_container,#1A73E8/0B57D0→primary,#F8F9FA/FFFFFF/F3F5F7/FAFBFC/F8FAFD→surface_container_low,#FAFBFC/FBFCFF→surface_container_high,#F4F7FB→surface_container,#DADCE0/E1E5EA/E2E8F0/E5EAF3/E5E7EB/C7DBFF/AECBFA→outline_variant,#E8F5E9/EAF6EE→success_container,#4CAF50/B8DFC4→success,#00FFFFFF→transparent),纯字面量替换、零结构改动。静态验证:19 文件 XML 全部合法、残留裸 hex=0;scripts/check_ui_tokens.sh --strict 对比度 pairs=38 failures=0 min=4.28(与改动前一致,唯一 violations=1 为预存 item_following.xml,非本任务引入);自算新配对亮/暗双表最差 7.04:1(on_primary_container/primary_container),修复项由 #E2E2E9 on #F8F9FA 1.24:1 提升至 on #181C20 66.57:1。单元验证::app:testMobileArm64_v8aDebugUnitTest 定向 28 套件/391 项/0 失败/0 错误(UiStyleSourceTest、ThemeBaseWiringTest 等)。设备验证:dev3 192.168.50.3:5559 mobile arm64 debug 经 scripts/build_arm64_debug_install.sh 覆盖安装;用户新截图 QQ20260928-161219.png 实测弹窗卡片带由 #F8F9FA 变为 #181C20,5 张卡片文字与卡底对比度 25.11/42.89/47.16/—/42.42:1 均远超 WCAG AA 4.5:1,亮底 #F8F9FA 残留像素由 289004 降至 769;进程 pid=29138 FATAL EXCEPTION=0。

Task-Guard: DIALUIGHT-CARD-TOKENS-20260928
2026-09-28 16:16:03 +08:00
Silent1566
18fad44d66 fix(mobile): remove duplicate watched time below history cards
Verification: 手机版历史卡片下部“已看 mm:ss”重复行移除:HistoryAdapterTest 2/2 通过(新增 mobileHistoryCardDoesNotRepeatWatchedTimeBelowThePoster,且基线代码对该断言计数=2 证明有判别力),grep 确认 historyProgress 无残留,APK 覆盖安装到签名一致的 emulator-5560 后 dumpsys activity top 视图树中 historyProgress=0、history_info 仅剩 name+remark、playback 封面标签仍在,截图为证

Task-Guard: ui-remove-duplicate-history-watched-mobile
2026-09-28 16:03:10 +08:00
Silent1566
908774597a
Merge pull request #383 from Silent1566/dev4
fix: 修复切集加载期旧集残留位置回写新集进度(偶现根因) + 合并 beta 最新代码
2026-09-28 12:30:46 +08:00
www.xueximeng.com
e092453640 Merge remote-tracking branch 'origin/main' into Silent1566 2026-09-28 12:21:52 +08:00
Silent1566
a6a470c2fa fix(mobile): 统一深色语义表使设置页文字颜色一致
mobile flavor 的 values/webhtv_tokens.xml 编译的是亮色表,而 BaseActivity 为每个
Activity 插入全屏 CustomWallView 使页面背景始终为深色壁纸,导致 ?attr/colorOnSurface
解析为近黑 #1A1C1E,工具栏标题与矢量图标却仍是硬编码白色,同一页面两种文字色。

改为与 leanback flavor 及 main/res/values-night 逐字节同值的深色表,两个 flavor 由此
对称:前景角色统一为亮色,夜间与非夜间模式解析同一张表。

新增守门测试断言 mobile/leanback/night 三张表颜色值一致且等于深色表,防止未来只把
单个 flavor 改回亮色。设备实测:13 行文案像素全部为 #E2E2E9,与标题一致。

Verification: mobile 统一深色语义表修复设置页半黑半白。目的:设置页部分文字为亮色(标题/返回箭头/图标硬编码 white)而部分为近黑(?attr/colorOnSurface),同一页两种文字色不协调。根因:BaseActivity 为每个 mobile Activity 在 content 下插入全屏 CustomWallView,内置壁纸全部为深色,页面背景实际是壁纸而非 webhtv_color_surface;但 mobile flavor 的 values/webhtv_tokens.xml 仍是亮色表(main/res/values 的 #1A1C1E),而 leanback flavor 的 values/ 直接编译深色表故无此缺陷。修复:app/src/mobile/res/values/webhtv_tokens.xml 改为与 leanback 及 main/res/values-night 逐字节同值的深色表。单元验证::app:testMobileArm64_v8aDebugUnitTest ThemeBaseWiringTest 7/7 通过(含新增守门测试 bothFlavoursCompileTheSameDarkTableAsTheNightPalette)、ThemeContractTest 5/5 通过;反向验证把 mobile tokens 换回亮色表时新守门测试 FAILED(18s) 证明断言有效。设备验证:dev3 192.168.50.3:5559,mobile arm64 debug 经 scripts/build_arm64_debug_install.sh 覆盖安装,uimode night=no,冷启动进入设置页;uiautomator dump 13 行文案完整无崩溃,像素采样全部文字/值/图标为 #E2E2E9(亮度228.3) 与标题一致,修复前 '点播''薰衣水晶' 等为 #1A1C1E(亮度28)。

Task-Guard: MOBILE-DARK-TOKENS-20260928
2026-09-28 12:04:47 +08:00
www.xueximeng.com
e24d6db5cd fix(cache): refresh settings cache value right after cleanup
Verification: cache package independent JUnit 57/57 OK; :app:compileMobileArm64_v8aDebugJavaWithJavac + :app:compileLeanbackArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL; device 5563 leanback arm64 debug covered install (applicationId temporarily patched to com.silent.android.webhtv, build.gradle restored byte-identical md5 c6ad2a8176046335686bac30be2c9c45): settings row refreshed immediately after LIGHT cleanup with NO page switch and NO activity recreate (same ActivityRecord t31, same pid 20949, logcat shows no SettingActivity START/Displayed) - row 22.1 MB -> 14.2 MB matching the reopened dialog summary '14.2 MB'; journal bytesBefore=17825792 bytesAfter=0 deletedFiles=2 COMPLETED matching the two fixtures; mobile flavor covered install then row 23.5 MB -> 14.5 MB under same ActivityRecord t32/pid 22345 stayed on settings tab, matching dialog summary '14.5 MB', journal bytesBefore=9437184 deletedFiles=1 COMPLETED; test fixtures and temp cache/restore-legacy dir removed, cache entry list restored, leanback flavor reinstalled on device; no FATAL EXCEPTION

Task-Guard: CACHE-MGMT-01-settings-refresh-after-cleanup
2026-09-28 11:52:26 +08:00
Silent1566
9554195c98 docs(beta-sync): 记录 dev3 合并 beta 的提交、tag 与 PR #382
Verification: 文档收尾:记录合并提交 c900dac20 与双父提交、recovery tag、origin/dev3 推送结果与 PR #382 编号;仅改动 docs/BETA-SYNC-DEV3-20260927.md,未重新构建或重跑测试

Task-Guard: BETA-SYNC-DEV3-20260927-CLOSE
2026-09-28 11:06:02 +08:00
Silent1566
c900dac20e merge: 合并 origin/beta 最新代码并保留 dev3 统一主题系统
Verification: 双 flavor 全量单测 BUILD SUCCESSFUL(mobile 5032 项 / leanback 4160 项,0 failure 0 error);双 flavor Java 编译通过;git diff --cached --check 通过且无冲突标记残留;mobile arm64 debug 打包成功并以 adb install -r 覆盖安装;dev3 机位 192.168.50.3:5559 冷启动与主题编辑器实测无崩溃;被剔除提交 5682f2b05 经 merge-base --is-ancestor 判定非 origin/beta 祖先

Task-Guard: BETA-SYNC-DEV3-20260927
2026-09-28 11:04:41 +08:00
Silent1566
96a4546b77 Merge remote-tracking branch 'origin/beta' into dev4 2026-09-28 09:27:15 +08:00
Silent1566
b55d52bf64 修复切集加载期旧集残留位置回写新集进度(偶现根因)
Verification: 第二轮修复实测: 5561(用户偶现同款环境, 红果短剧详情直放)修复前抓到 plan ready resumeMs 跨集延续铁证(139218连两集/110396>本集时长91710/84595连两集); 根因为 ExoPlayer stop 后 getPosition() 返回旧集残留位置, 新集 READY 前 tick 经 inlineStartPositionApplied回退分支 写入新集 history; 引入 inlinePlayerMediaReady 媒体就绪守卫(stop前置false/STATE_READY置true/清空置true, 三处写入守卫升级为 settled&&mediaReady 双条件)后 testMobileArm64_v8aDebugUnitTest TmdbDetailActivityLayoutTest 129/129 通过; assembleLeanbackArm64_v8aDebug 编译成功; 5561 覆盖安装实测: 三轮手动快滑切集起播位置全部 positionMs=0(上一集71秒位置无污染), 自动连播 78563→0 连续推进无位置跳变事件

Task-Guard: fix-inline-switch-position-r2-20260928
2026-09-28 04:30:05 +08:00
Silent1566
163cdf037d
Merge pull request #381 from Silent1566/dev4
修复详情直放与沉浸融合模式切集沿用上一集播放进度
2026-09-27 21:46:34 +08:00
Silent1566
5306e1bce1 修复详情直放与沉浸融合模式切集沿用上一集播放进度
Verification: testMobileArm64_v8aDebugUnitTest: TmdbDetailActivityLayoutTest 129/129 通过(含新增回归测试 inlineEpisodeSwitchDoesNotCarryPreviousEpisodePosition); assembleLeanbackArm64_v8aDebug 编译通过; emulator-5556 覆盖安装实测: 详情直放手动切下一集从0开始(第3集6:29→第4集从0连续播放)、片尾自动连播从0开始、同集退出重进续播381946ms正常、切集窗口期进度/缓存写入守卫生效

Task-Guard: fix-inline-switch-position-20260927
2026-09-27 21:01:25 +08:00
www.xueximeng.com
5e59ef54d9 fix(cache): clean legacy paths by a versioned rule table
Verification: cache package independent JUnit 57/57 OK; :app:compileMobileArm64_v8aDebugJavaWithJavac + :app:compileLeanbackArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL; device 5563 leanback arm64 debug covered install (applicationId temporarily patched to com.silent.android.webhtv, build.gradle restored byte-identical md5 c6ad2a8176046335686bac30be2c9c45): legacy row no longer misreports live caches (was 'legacy/orphan 17MB/93 files', now 'diagnostic logs 13.3MB/5', 'unclassified 3.7MB/87' owner-managed, 'legacy paths 20 bytes/2'); legacy MODULE clean reported 20 bytes/2 files and both fixtures actually deleted (journal bytesBefore=20 bytesAfter=0 deletedFiles=2 COMPLETED); diagnostic logs MODULE clean released 13.3MB/3 files (journal 13987893->4048) with live segment recreated by owner; L1 deleted 0 files and L3 deleted 16 files without touching diagnostic logs or the 82 plugin-preheat files; no FATAL EXCEPTION, pid stable

Task-Guard: CACHE-MGMT-01-legacy-orphan-cleanup-fix
2026-09-27 19:07:38 +08:00
Silent1566
09f8882251
Merge pull request #380 from Silent1566/dev1
合并 dev1:站点注入首页按钮默认不开启并完成 beta 同步复核
2026-09-27 11:17:07 +08:00
Silent1566
dee7979040 fix(webhome): restore Eclipse token root scope
Verification: WebThemeTokenSourceTest passed: ./gradlew :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.web.WebThemeTokenSourceTest; git diff --check passed; no top-level --eclipse-color/--eclipse-detail-color declarations remain

Task-Guard: WEBHOME-ECLIPSE-CSS-20260927
2026-09-27 11:13:40 +08:00
Silent1566
08d6d3e0de docs: 补录 dev1 未推送提交组合回归验证证据
Verification: docs-only: 补录未推送提交组合回归证据(QuickAdapterSelectionTest 2/2 + SiteAdapterSelectionTest 1/1 + SiteInjectHomeButtonSourceTest 4/4 + SiteInjectHomeButtonDefaultStateTest 5/5,合计 12 项 0 failure/0 error,BUILD SUCCESSFUL in 36s)

Task-Guard: beta-merge-dev1-review-verify
2026-09-27 11:12:52 +08:00
Silent1566
b32406d7ad docs: 记录 dev1 合并 beta 后的复评与站点注入默认态实测
Verification: review: origin/beta@b5a110516 已是 dev1 祖先(dev1..origin/beta=0),净差异仅 2 提交/4 文件;被剔除提交 5682f2b05 非 dev1 祖先;2 轮复评无必须修改项;unit SiteInjectHomeButtonSourceTest 4/4 + SiteInjectHomeButtonDefaultStateTest 5/5 通过;compileLeanbackArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL;build_arm64_debug_install.sh leanback/192.168.50.3:5555 打包 129 tasks 成功并 adb install -r 覆盖安装;启动冒烟无 FATAL/ANR;设备清空 home_button key 后首页功能按钮行 7 项不含站点注入;设备 prefs 已回滚 md5 一致

Task-Guard: beta-merge-dev1-review-20260927
2026-09-27 11:10:05 +08:00
Silent1566
3aae6d9e5b docs(tv): 记录站点注入默认不开启的设备实测
Verification: docs-only: 记录 2026-09-27 设备实测证据(新安装默认态首页功能按钮行 7 项不含站点注入;重置后个性设置->首页按钮摘要 6/10 且站点注入未勾选;手动勾选后 7/10 且首页出现 站点注入:开),设备 prefs 已按备份原样恢复并校验 md5 一致

Task-Guard: TV-CUSTOM-CSP-DEFAULT-OFF-doc
2026-09-27 10:39:08 +08:00
Silent1566
2072bf4d65 fix(tv): 站点注入首页按钮默认不开启
Verification: tv-device: 192.168.50.3:5555 leanback debug 覆盖安装后 个性设置→首页按钮 重置默认值摘要由 8/10 变为 6/10 且 站点注入 复选框未勾选,仍可手动勾选(7/10)并在首页出现「站点注入:开」;unit: SiteInjectHomeButtonSourceTest 4/4 + SiteInjectHomeButtonDefaultStateTest 5/5;regression: testLeanbackArm64_v8aDebugUnitTest 全量 4051 tests 0 failure 0 error;compile: compileLeanbackArm64_v8aDebugJavaWithJavac

Task-Guard: TV-CUSTOM-CSP-DEFAULT-OFF
2026-09-27 10:36:03 +08:00
Silent1566
b5a1105163
Merge pull request #379 from Silent1566/dev2
同步 beta 并复审 dev2 选源高亮
2026-09-27 10:08:35 +08:00
Silent1566
7465b91f0b docs: 记录 beta 合并与 dev2 选源高亮复审
Verification: .:app:testLeanbackArm64_v8aDebugUnitTest --tests QuickAdapterSelectionTest --tests SiteAdapterSelectionTest 通过;git diff --check origin/beta..HEAD 通过

Task-Guard: beta-merge-dev2-review-20260927
2026-09-27 09:55:45 +08:00
Silent1566
1a27828360 Merge remote-tracking branch 'origin/beta' into dev2 2026-09-27 09:16:35 +08:00
Silent1566
746c015908 docs(theme): record scrim pixel verification commit
Verification: 仅文档闭环:记录 THEME-SCRIM-PIXEL-20260927 的提交 401b65b83f 和 recovery tag;无代码/构建变更。

Task-Guard: THEME-SCRIM-PIXEL-DOC-20260927
2026-09-27 03:50:48 +08:00
Silent1566
401b65b83f test(theme): prove scrim opacity changes only the modal scrim
Verification: THEME-SCRIM-PIXEL-20260927: dev3 192.168.50.3:5559 上新增 debug-only 宿主和 instrumentation 像素测试;scrimOpacity 未设置遮罩采样 #ff9fbad6,最大值 0.85 为 #ffd5e0ed,弹窗面板中心均为 #fff4f7fa;测试 OK (1 test),无生产运行时行为修改。

Task-Guard: THEME-SCRIM-PIXEL-20260927
2026-09-27 03:46:58 +08:00
www.xueximeng.com
5f2277724c fix(cache): restore focus to cleanup trigger
Verification: 双形态 Java 编译通过;5563 覆盖安装实测确认框关闭后焦点回到原 Exo 清理按钮;git diff --check 通过

Task-Guard: CACHE-MGMT-01-CONFIRM-RETURN-FOCUS
2026-09-27 01:23:30 +08:00
Silent1566
e55f03f57f
Merge pull request #378 from Silent1566/dev1
合并 dev1:同步 beta 代理重定向修复并复评配置/站点主题改动
2026-09-27 01:03:07 +08:00
Silent1566
e55a3a3f78 docs(c25): record delivery coordinates
Verification: Docs-only closure: recorded commit 720d2bcbd3, recovery tag recovery/C25-beta-sync-review-dev1-20260926/20260927005542-720d2bcbd3d1 and PR https://github.com/Silent1566/webhtv/pull/378; no code, build or test change in this commit

Task-Guard: C25-beta-sync-review-dev1-20260926-doc-closure
2026-09-27 00:56:48 +08:00
Silent1566
720d2bcbd3 chore(tv): remove superseded config name drawables
Verification: Mobile targeted tests ProxyRedirectResponseTest 8/8, ProxyRangeResponsePolicyTest 4/4, SiteDialogThemeSourceTest 7/7, InterfaceEntryInteractionTest 10/10 passed; :app:compileLeanbackArm64_v8aDebugJavaWithJavac passed; leanback Arm64 debug APK assemble succeeded; adb install skipped because 192.168.50.3:5555 and all assigned emulators are offline; removed commits 5682f2b054 and 2faa1f37757f absent from merge result; superseded drawables have no remaining references

Task-Guard: C25-beta-sync-review-dev1-20260926
2026-09-27 00:55:42 +08:00
Silent1566
c1645a3745 merge: sync beta proxy redirect fixes (PR #377) 2026-09-27 00:49:41 +08:00
Silent1566
ec6730cc88
Merge pull request #377 from Silent1566/dev4
合并 dev4 最新修复到 beta
2026-09-26 23:08:50 +08:00
Silent1566
1e278a3a7f Fix short proxy responses and redirect tests
Verification: ProxyRedirectResponseTest and ProxyRangeResponsePolicyTest passed; git diff --check passed; second review passed

Task-Guard: beta-sync-review-20260926
2026-09-26 23:04:55 +08:00
Silent1566
83e0a3159b fix(tv): keep config name border visible
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.dialog.InterfaceEntryInteractionTest BUILD SUCCESSFUL; scripts/build_arm64_debug_install.sh --flavor leanback --serial 192.168.50.3:5555 build+install success; device verified normal/focused borders and DPAD_DOWN keeps name column, DPAD_RIGHT enters same-row edit column

Task-Guard: TV-CONFIG-NAME-BORDER-CONTRAST
2026-09-26 22:21:01 +08:00
Silent1566
e65243842b fix(tv): make selected site cards readable in site dialog
Verification: SiteAdapterSelectionTest passed; assembleLeanbackArm64_v8aDebug passed; 5557 pixel verification: selected site cell now 30129 px #381E72 fill with #FFFFFF text

Task-Guard: tv-site-dialog-contrast
2026-09-26 20:56:55 +08:00
www.xueximeng.com
689c2b5b37 feat(cache): migrate cache policy schema
Verification: CachePolicyStoreTest 3/3 通过;:app:compileMobileArm64_v8aDebugJavaWithJavac 与 :app:compileLeanbackArm64_v8aDebugJavaWithJavac 通过

Task-Guard: CACHE-MGMT-01-SCHEMA
2026-09-26 19:29:28 +08:00
Silent1566
67849819db Fix Hongguo redirect proxy responses
Verification: ProxyRedirectResponseTest passed; assembleLeanbackArm64_v8aDebug passed; device 127.0.0.1:5561 Hongguo proxy now returns 302 Location and target returns 200; app entered VideoActivity/ExoPlayer session

Task-Guard: fix-hongguo-302-proxy
2026-09-26 18:36:22 +08:00
www.xueximeng.com
45734f7b48 fix(cache): focus cancel by default in cleanup confirmations
Verification: 双形态 Java 编译通过;5563 覆盖安装实测:清理确认框打开后无障碍树 focused 立即为 android.widget.Button '取消'(修复前 focused 为空,按确认键无反应);预置 4 个过期 .tmp 后单击一次确认键,文件数清理前后均为 4、确认框关闭且未清理,证明单次确认键执行的是「取消」;深度清理第一步同样默认聚焦「取消」;测试文件已清理

Task-Guard: CACHE-MGMT-01-CONFIRM-FOCUS
2026-09-26 15:33:07 +08:00
Silent1566
677aca7156 docs(theme): refresh the plan status and its single next action
Brings the plan's authoritative summary back in line with what is actually committed. The status line now records that the remaining two matrix rows were closed (playback regression in 4.27, TV remote in 4.29, with WebHome left independent by the user's decision), that the TV theme channel's wholesale failure was located and fixed in 4.28 (the baseline was inferred from uiMode instead of the palette the flavour actually compiles), and that two real defects were then fixed: semantic attrs that were declared but assigned by no theme, which crashed several dialogs during inflation (4.30), and the standalone input style inheriting a container style, which left the fields borderless with clipped text (4.31). The single next action now states the real position: scrimOpacity is wired per the approved path 1 (task THEME-SCRIM-WIRE-P1-20260926, commit 350ea614b, implementation and acceptance recorded in docs/THEME-SCRIM-OVERLAY-20260925-design.md sections 6 and 13) - both dialogs keep their own scrim hue and only let the user drive alpha, a strict no-op while unset - with one device-level pixel confirmation still outstanding (compare the two extreme scrimOpacity values on a device that can open the TMDB person dialog and show a non-zero difference in the scrim region); overlayOpacity has no semantically correct native landing site and is now labelled web-theme-only in the editor; and the remaining uncovered areas are translucent-fill matching, StateListDrawable/RippleDrawable backgrounds and remote web theme pages. The stale task id and doc reference were corrected to the actual commit and standalone document.

Task-Guard: THEME-PLAN-REFRESH-20260926

Verification: 刷新主题计划的权威状态与下一步(仅文档,无代码变更)。当前状态行补充:4.7 设备矩阵其余两行已收口(播放回归 4.27、TV 遥控 4.29,WebHome 经用户决定独立)、TV 主题通道整体失效已定位并修复(4.28,根因是基线误用 uiMode 推断而非按 flavor 实际编译的调色板)、此后修复两个真实缺陷(4.30 声明但无主题赋值的语义属性导致多个弹窗 inflate 崩溃;4.31 独立输入框误用容器样式导致无边框且文字裁切)。下一步唯一动作改为本轮真实结论:scrimOpacity 已按用户批准的路径 1 接线完成(任务 THEME-SCRIM-WIRE-P1-20260926,提交 350ea614b,实现与验收记录在 docs/THEME-SCRIM-OVERLAY-20260925-design.md 第 6/13 节;两个弹窗保留自身遮罩色相、仅由用户控制 alpha、未设置时严格 no-op),仍缺一次设备级像素确认(需在有内容源且能打开 TMDB 人物详情弹窗的设备上取两极值比对遮罩区差异>0);overlayOpacity 经查无语义正确的原生落点,已在编辑器标注仅 Web 主题生效;其余未覆盖项为半透明填充匹配策略、StateListDrawable/RippleDrawable 背景、远程 Web 主题页面。原第二项引用的任务 ID 与文档链接已校准为实际提交号与独立文档路径。

Task-Guard: THEME-PLAN-REFRESH-20260926
2026-09-26 15:18:46 +08:00
Silent1566
6cdd491fed docs(theme): record the standalone input style fix
Documents 4.31, the record for 336c471b8 whose code and tests were already committed and verified; this commit only writes the acceptance record. It captures the root cause (the unification commit pointed these fields at Widget.WebHTV.Input, whose parent was a TextInputLayout container style, while none of the layouts contains a TextInputLayout, so nothing drew a border, and the style it replaced was the one carrying @drawable/selector_dialog_input plus the text metrics - together producing borderless fields with clipped text inside their fixed 44dp heights), the fix (Widget.WebHTV.Input is now a standalone field style drawing its own themed background and text colours, matching the bare AppCompatEditText fields already used correctly in dialog_ad_block_stats, with no new resources), the new UiStyleSourceTest guard, the device evidence from real taps on dev3 5559 for both the TMDB data configuration and AI general configuration dialogs, the style test result, and the rollback anchor.

Task-Guard: THEME-INPUT-STYLE-DOC-20260926

Verification: 文档记录 4.31(补 336c471b8 的验收记录,代码与测试已在上一提交完成并验证,本次只写文档)。内容:记录根因(0af2340d4 把输入框样式换成 Widget.WebHTV.Input,而后者父为 TextInputLayout 容器样式;这些布局无 TextInputLayout 故无边框,且被替换的旧样式自带 @drawable/selector_dialog_input 与文字样式,叠加导致固定 44dp 内文字裁切)、修复内容(Widget.WebHTV.Input 改为独立输入框样式,自带主题感知背景 ?attr/colorPrimary/colorOutline/colorSurfaceContainerHighest、textColor/textColorHint/cursor/14sp,与 dialog_ad_block_stats 既有正确做法一致,无新增资源)、守门测试 UiStyleSourceTest#standaloneInputStyleProvidesItsOwnBox、设备证据(dev3 5559 真实点击:TMDB 数据配置 与 AI 通用配置 两个弹窗输入框均恢复边框与完整文字,FATAL=0)、自动化证据(:app:testMobileArm64_v8aDebugUnitTest --tests 'com.fongmi.android.tv.ui.style.*' BUILD SUCCESSFUL)与回滚锚点。本任务仅文档,无代码或资源变更。

Task-Guard: THEME-INPUT-STYLE-DOC-20260926
2026-09-26 13:05:04 +08:00
Silent1566
336c471b8c fix(ui): give standalone dialog inputs their own box again
The unification commit moved the TMDB/AI input fields from Widget.WebHTV.LightDialog.Input to Widget.WebHTV.Input, whose parent was Widget.Material3.TextInputLayout.OutlinedBox - a TextInputLayout container style that draws the outline on the container and reserves space for a floating label. Two facts made that a total failure: none of those layouts contains a TextInputLayout (19 bare TextInputEditText fields across dialog_tmdb_source, dialog_ai_config, dialog_ai_prompt_config and dialog_group_rule_edit), so nothing drew a border at all; and the style it replaced was the one carrying android:background=@drawable/selector_dialog_input plus the text size, colour and cursor. The result was exactly what was reported - borderless fields whose text is squeezed and clipped inside their fixed 44dp heights. Widget.WebHTV.Input is now a standalone field style with no container parent, drawing @drawable/selector_dialog_input (whose focused and default states resolve through ?attr/colorPrimary, ?attr/colorOutline and ?attr/colorSurfaceContainerHighest) and setting ?attr/colorOnSurface text, ?attr/colorOnSurfaceVariant hints, the themed cursor drawable and 14sp - the same shape the tree already uses correctly elsewhere, such as the bare AppCompatEditText fields in dialog_ad_block_stats, with no new resources. UiStyleSourceTest#standaloneInputStyleProvidesItsOwnBox parses the style and fails if it regains a TextInputLayout parent or loses its own box and text colour. Verified on dev3 192.168.50.3:5559 by real taps: Settings > TMDB > TMDB data configuration now shows bordered fields with the full API key, language, API host and image host no longer clipped, and Settings > AI service > AI general configuration shows the same recovery - FATAL EXCEPTION stayed 0 in both, confirming a class-wide fix rather than a one-off. The style unit tests pass. Documentation for this fix lives in a separate commit because it falls outside this session's declared scope.

Task-Guard: THEME-INPUT-STYLE-REGRESSION-20260926

Verification: 修复 4.31 输入框无边框且文字裁切。根因(0af2340d4 引入):该提交把 TMDB/AI 等布局的输入框样式从 Widget.WebHTV.LightDialog.Input 换成 Widget.WebHTV.Input,而后者父样式是 Widget.Material3.TextInputLayout.OutlinedBox——这是给 TextInputLayout 容器用的样式,描边由容器绘制、内边距为浮动标签预留。但 (1) 这些布局里根本没有 TextInputLayout(dialog_tmdb_source/dialog_ai_config/dialog_ai_prompt_config/dialog_group_rule_edit 共 19 处全是裸 TextInputEditText),没有任何东西画边框;(2) 被替换掉的旧样式恰恰含 android:background=@drawable/selector_dialog_input(可见输入框外观)以及 textSize/textColor/cursor。两者叠加 = 无边框 + 文字在固定 44dp 高度里被挤压裁切,与用户截图一致。修复:Widget.WebHTV.Input 改为独立输入框样式(不再继承任何容器样式),自带 android:background=@drawable/selector_dialog_input(焦点/默认两态,颜色为 ?attr/colorPrimary / ?attr/colorOutline / ?attr/colorSurfaceContainerHighest)、android:textColor=?attr/colorOnSurface、android:textColorHint=?attr/colorOnSurfaceVariant、@drawable/shape_cursor_dialog、14sp;该写法与仓库既有正确做法一致(dialog_ad_block_stats 三套 source set 的独立输入框就是裸 AppCompatEditText + 同一 drawable),未新增资源。守门测试 UiStyleSourceTest#standaloneInputStyleProvidesItsOwnBox:解析 Widget.WebHTV.Input 定义,断言父样式不得含 TextInputLayout、必须自带 @drawable/selector_dialog_input、必须自带 android:textColor。设备验证(dev3 192.168.50.3:5559,覆盖安装,真实点击路径):设置→TMDB→「TMDB 数据配置」输入框恢复可见圆角边框,API Key 304ca56b1b7b57ca7a47d9b59946be94、语言 zh-CN、API 域名、图片域名均完整显示不再裁切,排版正常,FATAL EXCEPTION=0;设置→AI 服务→「AI 通用配置」同类输入框同样恢复边框与完整文字,FATAL=0,证明是整类修复而非单点。自动化::app:testMobileArm64_v8aDebugUnitTest --tests 'com.fongmi.android.tv.ui.style.*' BUILD SUCCESSFUL。注:本次提交只含代码与测试;配套文档 4.31 记录因超出本会话声明范围,已另存为 /tmp/doc_431.patch 待下个文档任务提交。

Task-Guard: THEME-INPUT-STYLE-REGRESSION-20260926
2026-09-26 12:41:03 +08:00
Silent1566
3ebc9ccd4e fix(tv): highlight current site in quick source switcher
Verification: QuickAdapterSelectionTest passed (2 tests, leanbackArm64_v8aDebugUnitTest); assembleLeanbackArm64_v8aDebug passed; Robolectric binding test proves current site is activated and others are not

Task-Guard: tv-site-selection-style
2026-09-26 12:38:01 +08:00
Silent1566
1e41863c18 fix(tv): show config name button border
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.dialog.InterfaceEntryInteractionTest (BUILD SUCCESSFUL); task_guard check; git diff --check

Task-Guard: TV-CONFIG-NAME-BORDER
2026-09-26 11:34:11 +08:00
Silent1566
1bb72bd709 fix(tv): keep config action focus columns
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.dialog.InterfaceEntryInteractionTest (BUILD SUCCESSFUL); task_guard check; git diff --check

Task-Guard: TV-CONFIG-ACTION-FOCUS
2026-09-26 11:06:05 +08:00
Silent1566
f7674024e9 fix(tv): restore readable VOD source colors
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.dialog.SiteDialogThemeSourceTest (BUILD SUCCESSFUL); git diff --check

Task-Guard: TV-VOD-SITE-COLOR
2026-09-26 10:10:13 +08:00
Silent1566
44a0509d62 fix(theme): stop crashing when a semantic attr has no theme assignment
Fixes the reported crash: tapping TMDB data configuration under Settings > TMDB killed the app. The exception was UnsupportedOperationException: 'Failed to resolve attribute at index 3: TypedValue{t=0x2/d=0x7f040665}' thrown from TypedArray.getColorStateList inside TextView.readTextAppearance during inflation. That resource id resolves to attr webhtvColorOnSurface, and all five TextAppearance.WebHTV.* styles set android:textColor to the custom webhtvColorOnSurface / webhtvColorOnSurfaceVariant attrs, which webhtv_attrs.xml declares but no theme ever assigns - Theme.WebHTV only maps the standard Material attrs onto the same tokens. Reading such a text appearance therefore throws inside the View constructor, so every dialog using Widget.WebHTV.Label, Label.Secondary, Helper or SliderLabel crashed on open: dialog_tmdb_source, dialog_ai_config, dialog_ai_prompt_config, dialog_speed and dialog_buffer, not just the one reported. The fix points those five styles at the standard attrs the theme does assign, ?attr/colorOnSurface and ?attr/colorOnSurfaceVariant, which Theme.WebHTV maps to exactly the same token colours, so nothing changes visually while the dependency on unassigned attributes is removed. ThemeContractTest#everyReferencedSemanticAttrIsAssignedByATheme now scans all ?attr/webhtv* references across main/mobile/leanback and requires each to have a matching <item> assignment - it failed before the fix naming exactly [webhtvColorOnSurface, webhtvColorOnSurfaceVariant] and passes after - so the declarations and their assignments can never drift apart again. Verified on dev3 192.168.50.3:5559 through the user's original path: the TMDB data configuration dialog now opens and renders its title, source description, API key, language, API and image hosts and both buttons, process alive, FATAL EXCEPTION = 0, where it previously crashed every time. Theme and dialog unit suites pass, as does the leanback javac compile. The defect came from the earlier theme-integration commits and predates the scrim work, which did not touch these files.

Task-Guard: TMDB-DIALOG-INFLATE-CRASH-20260926

Verification: 修复用户报告的「设置 → TMDB → TMDB 数据配置」一按即崩。根因链(每环有证据):(1) 崩溃异常为 UnsupportedOperationException: Failed to resolve attribute at index 3: TypedValue{t=0x2/d=0x7f040665},抛于 TypedArray.getColorStateList ← TextView.readTextAppearance ← MaterialTextView.<init>,即 inflate 读 textAppearance 时崩溃;(2) 0x7f040665 在 app/build/intermediates/runtime_symbol_list/mobileArm64_v8aDebug/.../R.txt 解析为 attr webhtvColorOnSurface;(3) app/src/main/res/values/webhtv_type.xml 的 5 个 TextAppearance.WebHTV.* 把 android:textColor 指向 ?attr/webhtvColorOnSurface(Variant);(4) webhtv_attrs.xml 只声明这些属性,全仓库无任何主题赋值(grep 'name="webhtvColor' 过滤掉 format="color" 后为空),Theme.WebHTV 仅将标准 Material 属性映射到同一批 token(colorOnSurface→@color/webhtv_color_on_surface、colorOnSurfaceVariant→@color/webhtv_color_on_surface_variant)。影响面大于单点:Widget.WebHTV.Label/Label.Secondary/Helper/SliderLabel 全部受影响,dialog_tmdb_source、dialog_ai_config、dialog_ai_prompt_config、dialog_speed、dialog_buffer 等弹窗均会崩。修复:webhtv_type.xml 5 处改为主题确实赋值的标准属性 ?attr/colorOnSurface / ?attr/colorOnSurfaceVariant,二者在 Theme.WebHTV 中指向完全相同的 token 色,故视觉零变化,仅移除对无人赋值属性的依赖。守门测试:ThemeContractTest#everyReferencedSemanticAttrIsAssignedByATheme 扫描 main/mobile/leanback 三套 res 的全部 ?attr/webhtv* 引用并要求每个属性在 values/ 中找到 <item name=...> 赋值;该测试在修复前失败并精确报出 [webhtvColorOnSurface, webhtvColorOnSurfaceVariant],修复后通过。设备验证(按用户原始路径,dev3 192.168.50.3:5559,覆盖安装):设置 → TMDB → 「TMDB 数据配置」弹窗正常打开,渲染出标题、数据源说明、API Key、语言 zh-CN、API 域名、图片域名与取消/确定按钮,进程存活 pid 32224,FATAL EXCEPTION = 0;修复前该操作必崩(用户截图 09:37 与我抓取的 09:36/09:37 崩溃栈一致)。自动化::app:testMobileArm64_v8aDebugUnitTest --tests 'com.fongmi.android.tv.theme.*' --tests 'com.fongmi.android.tv.ui.dialog.*' BUILD SUCCESSFUL;:app:compileLeanbackArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL。归属:该缺陷源自主题整合提交(webhtv_attrs.xml/webhtv_type.xml,6cdc7dd36 等),非本轮 scrim 工作引入,后者未触碰这两个文件。无数据格式、偏好键或资源替换类变更。

Task-Guard: TMDB-DIALOG-INFLATE-CRASH-20260926
2026-09-26 09:46:28 +08:00
www.xueximeng.com
37eb7f4f0d docs(cache): correct update blocker root cause
Verification: 修正文档中不准确的「设备网络不可用」表述:宿主机与设备分别请求 api.github.com/.../releases/latest 均 403 且响应为 API rate limit exceeded;CNB 发布镜像 403 且 errmsg 为 Repo fish2035/webhtv-release has been frozen,证明是发布端/配额问题而非设备网络;据此换取更准确的阻塞描述

Task-Guard: CACHE-MGMT-01-UPDATE-ROOTCAUSE
2026-09-26 09:35:26 +08:00
Silent1566
f35b8dafdd
Merge pull request #376 from Silent1566/dev1
合并 dev1:同步最新 beta 并完善光影剧幕与 TMDB 语言边界
2026-09-26 09:10:37 +08:00
Silent1566
5058aaab2e merge: sync latest beta and review theme changes
Verification: Mobile targeted tests: TmdbSourcePayloadTest/TmdbLanguagePolicyTest/TmdbSourceCapabilityPlannerTest/TmdbSourceMergerTest 20/20 passed; TmdbDetailActivityLayoutTest/DetailModeControllerTest/TmdbCinemaThemeTest 144/144 passed; Mobile+Leanback Arm64 Debug Java compilation passed; Debug APK overwrite-installed on 192.168.50.3:5555 and app launched without fatal errors; removed commits excluded; Gradle daemon stopped

Task-Guard: C24-beta-sync-review-dev1-20260926
2026-09-26 04:45:47 +08:00
www.xueximeng.com
225a3fc374 fix(cache): keep panel open when closing during cleanup
Verification: 双形态 Java 编译通过;5563 覆盖安装实测(预置最多 120000 个 2 天前 .tmp 使清理持续数秒):清理中点击面板底部「确定/关闭」按钮后弹窗保持打开(无障碍树仍可读到「缓存管理」,无任何弹窗按钮),未出现修改前的直接关闭;此前已验证清理中 BACK 只请求取消且状态显示「缓存清理已取消」、空闲时 BACK 正常关闭;测试文件已清理

Task-Guard: CACHE-MGMT-01-CLOSE-CANCEL
2026-09-26 02:56:33 +08:00
Silent1566
350ea614bb feat(theme): drive modal scrim alpha from scrimOpacity
Implements the approved path 1 (preserve the default look) and the agreed overlayOpacity editor label. The dialogs keep their own scrim colour - translucent white in light mode, translucent black in dark - and the user drives only its alpha, because substituting the token's colorScrim (translucent black in both modes) was measured to invert the light-mode scrim from lightening to darkening. ThemeController gains configuredScrimOpacity(boolean light), which reads the user's explicitly configured alpha and returns null when unset - the distinction from 'the value happens to equal the default' is what keeps the shipped rendering byte-identical - plus a pure applyScrimOpacity(int base, Float opacity) that returns the base untouched for null and otherwise replaces only the alpha byte. The mobile EpisodeDetailDialog and TmdbPersonDialog overlay literals now route through it, delegating to the shared maths, and the overlayOpacity label states it applies to the web theme only in all three locales. Automated evidence: theme unit tests pass with three new contracts - the dialogs must keep 0x99F4F7FA and must never reference colorScrim(), with arithmetic asserted directly (null is a strict no-op, 0f/1f map to 0x00/0xFF alpha, out-of-range clamps, 0.85f yields 0xD9F4F7FA); the accessor distinguishes unset from a value equal to the token baseline (0.322f still reports as a user value); and the three locale labels exist. Regression coverage over theme.*, ui.dialog.*, EpisodeAdapterTest, and TmdbDetailActivityLayoutTest - all of which reference the changed files - passes, as do the mobile and leanback javac compiles. Honest gap: no device screenshot was captured because both dialogs are only reachable through the TMDB detail flow and this device currently has no watch history or site configuration, and the earlier 'network blocked' reading was itself wrong (TMDB drops ICMP and returned 401 only for a keyless request; with the device's configured key search/person returns 200 with real data), so the runtime pixel effect still lacks device confirmation and is recorded as such with a follow-up procedure.

Task-Guard: THEME-SCRIM-WIRE-P1-20260926

Verification: 按路径 1(保默认外观)实现 scrimOpacity 接线 + overlayOpacity 编辑器标注。设计:不把 token 的 colorScrim 灌进弹窗,而是保留每个弹窗自己的遮罩色相,只让用户控制 alpha,从而默认外观逐字节不变。实现:ThemeController 新增 configuredScrimOpacity(boolean light)——读取 profile 中用户显式设置的 scrim alpha,未设置返回 null(关键:必须区分'未设置'与'恰好等于默认值'),并按调用方自己解析的 light/dark 选择槽集;新增纯函数 applyScrimOpacity(int base, Float opacity)——null 原样返回、否则只替换 alpha 字节保留 RGB。mobile EpisodeDetailDialog.java:289 与 TmdbPersonDialog.java:372 的 overlay 由字面量改为 applyScrimOpacity(light ? 0x99F4F7FA : <深色字面量>, light),本地 helper 委托共享函数。overlayOpacity 的 label 在三份 strings.xml 追加'仅 Web 主题生效'。自动化证据(全部通过):(1) :app:testMobileArm64_v8aDebugUnitTest --tests 'com.fongmi.android.tv.theme.*' BUILD SUCCESSFUL,新增 3 条契约——scrimOpacityKeepsTheDialogOwnColourAndOnlyMovesAlphaWhenSet 断言两弹窗保留 0x99F4F7FA、必须不出现 colorScrim()、必须委托共享函数,并直接断言算术行为(null 严格等于 0x99F4F7FA/0xB3000000、0f→0x00F4F7FA、1f→0xFFF4F7FA、-1f/2f 被夹取、0.85f→0xD9F4F7FA);configuredScrimOpacityReportsUnsetSeparatelyFromAnyValue 用反射注入 profile,断言未设置→null、仅设 light 时 dark 仍 null、设成 0.322f(等于 token 基线)仍报用户值而非未设置;overlayOpacityIsLabelledAsWebOnly 断言三语文案。(2) 回归:同任务覆盖 theme.*、ui.dialog.*、EpisodeAdapterTest、TmdbDetailActivityLayoutTest 全部通过(这些测试直接引用被改动文件)。(3) 双 flavor :app:compileMobileArm64_v8aDebugJavaWithJavac 与 :app:compileLeanbackArm64_v8aDebugJavaWithJavac 均 BUILD SUCCESSFUL。如实记录的验证缺口:未取得设备端截图证据——两弹窗仅能从 TMDB 详情路径进入,当前设备 192.168.50.3:5559 无观看历史、无站点配置,无法在合理成本内到达;同时排除了'网络阻塞'误判(TMDB 封 ICMP 且裸请求缺 api_key 才 401,用设备内配置 key 实测 search/person 返回 200 带真实数据),故该弹窗在有内容源设备上应可打开但本次未实测。因此 scrimOpacity 目前只有单元级行为证据、缺设备级像素确认,已在文档 13.3 节明确标注并给出后续补验步骤(设两极值打开 TmdbPersonDialog,遮罩区差异应>0、分隔线应 0 差异)。设备偏好已按字节还原为基线 /tmp/sc_base.xml。

Task-Guard: THEME-SCRIM-WIRE-P1-20260926
2026-09-26 02:55:25 +08:00
Silent1566
5e51a2c0eb Merge remote-tracking branch 'origin/beta' into dev1 2026-09-26 01:11:02 +08:00
Silent1566
b15b6cdfe0
Merge pull request #375 from Silent1566/dev4
合并远端 beta 并修正移动端全局历史点击
2026-09-26 00:56:52 +08:00
Silent1566
8da7bd6253 fix(detail): add light cinema text plate
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests TmdbDetailActivityLayoutTest passed (128 tests)

Task-Guard: CINEMA-LIGHT-TEXT-PLATE
2026-09-26 00:56:27 +08:00
www.xueximeng.com
f7d8327548 fix(cache): treat BACK as cancel request while cleanup runs
Verification: 双形态 Java 编译通过;5563 覆盖安装实测(预置 30000 个 2 天前 .tmp 使清理持续数秒):清理中按 BACK 面板不关闭、清理被取消且状态行显示「缓存清理已取消」;空闲时按 BACK 正常关闭弹窗回到设置页;测试文件已清理,cache 恢复 21MB

Task-Guard: CACHE-MGMT-01-BACK-CANCEL
2026-09-26 00:39:30 +08:00
Silent1566
4d0fb65e09 Merge remote-tracking branch 'origin/beta' into dev4 2026-09-26 00:03:17 +08:00
Silent1566
682a90cc99 docs(theme): record that the scrim replacement would regress the default look
Assessment-only follow-up, no code change. The corrected wiring path from the previous note - replacing the runtime overlay literals in mobile EpisodeDetailDialog and TmdbPersonDialog with ThemeController.current().colorScrim() - turns out to alter the default appearance and is therefore a regression that must not be applied as-is. Quantified: mobile EpisodeDetailDialog light uses 0x99F4F7FA (white, alpha 0.600) while the token baseline is 0x52000000 (black, alpha 0.322), differing in hue, brightness and strength; its dark value 0xB3000000 (alpha 0.702) differs in strength from 0x8A000000 (alpha 0.541); TmdbPersonDialog light likewise uses 0x99F4F7FA versus the black baseline; and its dark 0x8F000000 (0.561) is within 0.02 of the baseline. In other words these two dialogs use a translucent white scrim in light mode where colorScrim is translucent black, so a straight swap would turn a lightening overlay into a darkening one. Two viable paths are recorded instead: preserve the default look by keeping the literals as the default and only overriding when the user explicitly sets scrimOpacity (which requires exposing whether the slot was overridden, since colorScrim currently bakes the user value into alpha and cannot distinguish a user-set 0.322 from unset), or accept a deliberate visual unification onto the colorScrim baseline as a separately reviewed visual change. Conclusion: the real blocker for scrimOpacity is not finding a consumer but the mismatch between the current default scrim colour and the token baseline, so nothing should be implemented until a path is chosen; this task stays unimplemented. The plan's next-action line was updated to match and the document's section ordering was normalised to 10, 11, 12.

Task-Guard: THEME-SCRIM-DEFAULT-20260925

Verification: 进一步阻塞复核(仅文档,无代码变更)。第 11.3 节提出的修正路径——把 mobile EpisodeDetailDialog 与 TmdbPersonDialog 的运行时 overlay 字面量换成 ThemeController.current().colorScrim()——经色值量化后确认会改动默认外观,属回归,不能直接实施。逐项对照:mobile EpisodeDetailDialog 浅色现有 0x99F4F7FA(白,alpha 0x99=0.600)对 token 基线 0x52000000(黑,alpha 0x52=0.322),色相/明暗/强度全不同;深色现有 0xB3000000(alpha 0.702)对基线 0x8A000000(alpha 0.541),强度不同;TmdbPersonDialog 浅色现有 0x99F4F7FA 对 0x52000000,同样全不同;深色现有 0x8F000000(0.561)对 0x8A000000(0.541),仅差 0.02。即浅色下这两个弹窗用的是半透明白遮罩,而 colorScrim 基线是半透明黑,直接替换会把浅色弹窗由提亮变压暗。据此记录两条可选路径:路径1保默认外观——保留字面量作默认,仅在用户显式设置 scrimOpacity 时才覆盖,代价是需把'用户是否覆盖'暴露到 ThemeTokens(当前 colorScrim 已把用户值烘进 alpha,无法区分'用户设为 0.322'与'未设置');路径2接受外观统一——把默认遮罩统一到 colorScrim 基线,属有意的视觉变更,须独立评审。结论:scrimOpacity 接线的真正阻塞不是找消费点,而是现有默认遮罩色与 token 基线不一致;在选定路径前不应实施,本任务保持未实施状态。已同步修正主文档下一步描述。文档节序整理为 10→11→12,无重复编号。本任务未运行构建或设备测试(纯文档)。

Task-Guard: THEME-SCRIM-DEFAULT-20260925
2026-09-25 23:44:31 +08:00
Silent1566
8d07e76093 fix: unlock mobile global history setting taps
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.history.GlobalHistorySettingSourceTest BUILD SUCCESSFUL; git diff --check PASS

Task-Guard: global-history-resume-touch-lock
2026-09-25 23:28:06 +08:00
Silent1566
a47a9bf1bc
Merge pull request #374 from Silent1566/dev2
追更全量刷新与元数据展示
2026-09-25 23:03:52 +08:00
Silent1566
68df600518 docs(theme): falsify the scrim wiring premise and correct the plan
Assessment correction, no code change: while implementing, verification of where each dialog actually obtains its scrim colour disproved the premise the plan rested on, so the implementation was aborted and every code edit reverted (ThemeRole.java, ThemeBinder.java and the two layouts restored; SCRIM hits 0, webhtv:scrim hits 0, worktree otherwise clean). The three full-screen dialogs do declare android:background=@color/webhtv_color_scrim in XML, but all of them overwrite it at runtime with hardcoded literals: mobile EpisodeDetailDialog.java:290,297 sets root.setBackgroundColor(light ? 0x99F4F7FA : 0xB3000000), TmdbPersonDialog.java:372,383 sets view.setBackgroundColor(light ? 0x99F4F7FA : 0x8F000000), leanback EpisodeDetailDialog.java:316,322 sets root.setBackgroundColor(light ? 0xFFFFFFFF : 0xFF101214) which is an opaque page colour rather than a scrim, and TmdbVideoPlayerDialog.java:322 sets container.setBackgroundColor(Color.BLACK) in fullscreen. Those XML declarations are therefore dead code at runtime, and the only live webhtv_color_scrim uses are not scrims at all (two 1dp dividers plus an 88dp row background per source set in dialog_ad_block_stats, and a poster placeholder in dialog_receive), so no live scrim consumer driven by that token exists today. Consequently the original design - add ThemeRole.SCRIM, teach ThemeBinder about ColorDrawable, tag the layouts - would not have had any effect even if implemented. The corrected wiring is the four-line change that assigns the colour in the first place: replace the two runtime overlay literals with ThemeController.current().colorScrim(), which already carries the user's scrimOpacity because ThemeResolver writes withAlpha(base.colorScrim(), scrimOpacity). That touches two Java files outside this session's declared scope, so it is left for an approved follow-up. Recorded the falsification, the corrected path, the now-unnecessary binder work (cost drops from medium to low) and the lesson - evaluating a token's landing site must verify the colour's final effective source, not just its XML declaration - in the design document, and updated the plan's next-action line accordingly.

Task-Guard: THEME-SCRIM-WIRING-20260925

Verification: 实施前复核证伪设计前提,实施中止并全部回退,仅保留文档修正(无代码变更,工作树除两份文档外干净)。关键事实:设计文档第 3 节认定'三个全屏弹窗的 XML scrim 背景是活的遮罩、可直接接线',逐文件核对运行时取色后证伪——(1) mobile EpisodeDetailDialog.java:290,297 运行时 root.setBackgroundColor(overlay),overlay=light?0x99F4F7FA:0xB3000000 硬编码;(2) TmdbPersonDialog.java:372,383 运行时 view.setBackgroundColor(overlay),overlay=light?0x99F4F7FA:0x8F000000 硬编码;(3) leanback EpisodeDetailDialog.java:316,322 运行时 root.setBackgroundColor(background),background=light?0xFFFFFFFF:0xFF101214,是不透明全屏底色而非遮罩;(4) TmdbVideoPlayerDialog.java:322 全屏时 container.setBackgroundColor(Color.BLACK)。即 webhtv_color_scrim 在这四处 XML 声明均为运行时被覆盖的死代码。剩余'活着'的 webhtv_color_scrim 用法全部不是遮罩:dialog_ad_block_stats 三个 source set 各 2 处 1dp 分隔线 + 1 处 88dp 行背景,dialog_receive 为海报占位底。因此当前代码不存在任何由 webhtv_color_scrim 驱动的活遮罩消费点,原方案(新增 ThemeRole.SCRIM + ThemeBinder 支持 ColorDrawable + 布局打 tag)即使实施也不会生效。已回退本轮全部无效代码改动:git checkout 还原 ThemeRole.java、ThemeBinder.java、dialog_episode_detail.xml、dialog_tmdb_person.xml,复查 SCRIM 命中=0、webhtv:scrim 命中=0,git status 仅剩两份文档改动。文档修正:新增第 11 节记录证伪、正确接线点(把两处运行时硬编码 overlay 字面量改为 ThemeController.current().colorScrim(),因 ThemeTokens.colorScrim() 已含用户 scrimOpacity)与教训(评估 token 落点必须验证最终生效来源而非只看 XML);第 6 节建议改为指向该正确路径;第 7 节旧步骤标记为已废弃仅留追溯;第 5 节方案 B 描述同步更新(binder 契约扩展经复核不需要,工作量由中降为低);主文档下一步描述同步修正。正确路径涉及两份新的 Java 文件(mobile EpisodeDetailDialog.java、TmdbPersonDialog.java),超出本会话声明的路径范围,故不在本会话实施,留待用户批准新范围。

Task-Guard: THEME-SCRIM-WIRING-20260925
2026-09-25 22:59:15 +08:00
Silent1566
d7bebcf586 feat(following): refresh all items and show metadata
Verification: FOLLOW-2: 23 targeted unit tests passed; 2 device migration tests passed on 192.168.50.3:5557; mobile arm64 debug build+overwrite install passed; app launched without fatal crash

Task-Guard: FOLLOW-2
2026-09-25 22:37:48 +08:00
www.xueximeng.com
ae0b26e8ee fix(cache): notify cleanup result instead of asking to confirm it
Verification: 双形态 Java 编译通过;5563 覆盖安装实测:构造 2 天前 pushed-stale.apk 后执行轻度清理,仅出现 Toast「清理完成 释放 512KB · 删除 1 个文件」,无任何结果弹窗(4 秒后仍无确定/取消按钮),无障碍树 id/status=「清理完成 释放 512 KB · 删除 1 个文件」、id/summary 刷新为 19.3MB/478.9MB;回归确认深度清理执行前二次确认仍为第一步 取消/继续

Task-Guard: CACHE-MGMT-01-RESULT-TOAST
2026-09-25 21:02:49 +08:00
www.xueximeng.com
3ea56bc079 docs(cache): record update endpoint network blocker
Verification: 实测确认更新闭环的外部阻塞:设备请求 api.github.com/repos/fish2018/webhtv/releases/latest 与 cnb.cool 发布清单均返回 403,网络受限无法完成真实检查更新;已据实写入文档,不虚报完成

Task-Guard: CACHE-MGMT-01-UPDATE-NET
2026-09-25 19:11:35 +08:00
www.xueximeng.com
98f27f59fc docs(cache): finalize recovery anchor status
Verification: 最终审计:工作区干净、无未勾选验收项、43 个恢复标签;缓存包独立 JUnit 41/41 通过;恢复锚点更新为准确终态,明确两项非阻塞已知边界(应用更新完整闭环受环境限制、插件上限自动淘汰按安全设计暂不启用)

Task-Guard: CACHE-MGMT-01-FINAL-ANCHOR
2026-09-25 18:03:23 +08:00
www.xueximeng.com
5faf3d8b4d docs(cache): clarify update verification scope
Verification: 审查 Updater/HttpUpdateTransfer/OciUpdateTransfer 确认下载目标为 cache/update.apk 且属本计划缓存契约;该契约已实测通过(进行中 update.apk 被保护、过期临时包淘汰)。完整更新闭环受环境限制:ApkUrlPolicy 拒绝私网/HTTP、无线上 HTTPS 发布包、安装需系统安装器人工确认,故按 §24 第5条如实标注而未虚报

Task-Guard: CACHE-MGMT-01-UPDATE-SCOPE
2026-09-25 17:59:31 +08:00
www.xueximeng.com
d762e8ee21 docs(cache): document plugin limit safety decision
Verification: 审计插件模块上限并回退试改:directCleanupStatus 对 PLUGIN_SCRIPTS 恒返回 NOT_ALLOWED,UI 显示「由模块管理」并禁用清理,applyConfiguredLimits 不淘汰插件文件,属有意安全设计(运行中暂停插件加载未实现,后台删除 jar/py/js 可能致回归)。设备实测:80MB js 文件 + 64MB 插件上限,深度清理后该文件仍保留(仅释放其他模块 8.7MB/56 文件)。尝试改自动淘汰后已回退以避免回归,结论记录于 §20.6

Task-Guard: CACHE-MGMT-01-PLUGIN-LIMIT
2026-09-25 17:53:32 +08:00
Silent1566
83aca519ed docs(theme): assess scrim and overlay opacity wiring
Assessment-only: no code, resource, lock or runtime change. Produced docs/THEME-SCRIM-OVERLAY-20260925-design.md and registered the task plus next action in the theme plan. Every conclusion is traceable: ThemeRole has no SCRIM/OVERLAY role (0 hits), so neither slot has a native consumer and both editor sliders are dead controls. Their semantics differ from dialogOpacity - scrimOpacity and overlayOpacity are absolute alphas (withAlpha(base.colorScrim(), ...) / withAlpha(base.colorOverlayLight(), ...)) whose bases are 0x52000000 (light) and 0x8A000000 (dark/TV) for scrim, while dialogOpacity is a scale with a 1.0 baseline, so applyShellOpacity's opacity>=1 no-op rule must not be reused. The binder handles no ColorDrawable (0 hits) and even the explicit-tag path still requires baseline==current. scrimOpacity does have correct existing consumers - the full-screen overlay backgrounds of dialog_episode_detail, dialog_tmdb_person and dialog_tmdb_video_player - but webhtv_color_scrim is also used for 1dp dividers and an 88dp row in dialog_ad_block_stats (3 places per source set) plus a poster placeholder in dialog_receive, so a global swap is wrong and the wiring must be scoped per view. overlayOpacity's semantics do not hold: overlay_light's only use is a 1dp divider in dialog_quick_search while the real image veils use overlay_dark, which 4.23 froze. Official evidence confirms the intent - Material's mtrl_scrim_color is exactly #52000000, matching the project's light webhtv_color_scrim - and the plan's own slot table already defines scrimOpacity as the page/dialog outer scrim, making this an implementation gap rather than a design gap. A material risk is recorded: TmdbPersonDialog:133 and EpisodeDetailDialog:240 disable window dim (setDimAmount(0f)) but TmdbVideoPlayerDialog:326 keeps 0.72f, so a view scrim would stack with it; the first implementation should therefore wire only the two clean dialogs. The document compares no-change, the recommended scoped-wiring option, rebinding the veils and unfreezing overlayDark, window-level dim, and removing the slots from the editor, and states the recommendation, minimal implementation steps, acceptance criteria and rollback path, citing source excerpts instead of line numbers so references do not rot. No build or device test was run, as this task changes docs only.

Task-Guard: THEME-SCRIM-OVERLAY-20260925

Verification: 设计研究任务(仅文档,未改代码)。产出 docs/THEME-SCRIM-OVERLAY-20260925-design.md,并在主题主文档登记任务与下一步。所有结论均双向可回溯,已逐条复核:(1) ThemeRole 无 SCRIM/OVERLAY 角色(grep -c = 0),故两槽无原生消费点,编辑器滑块是死控件;(2) resolver 语义差异——scrimOpacity 是绝对 alpha(withAlpha(base.colorScrim(), scrimOpacity),ThemeResolver:168,184),基线 light=0x52000000(0.322)/dark与TV=0x8A000000(0.541),而 dialogOpacity 是缩放且基线 1.0,实施时不能套用 applyShellOpacity 的 opacity>=1 no-op 判定;overlayOpacity 派生自 colorOverlayLight(0x14FFFFFF);(3) binder 不处理 ColorDrawable(grep -c = 0),且 singleColor 的显式 tag 路径仍要求 baseline==current;(4) scrim 消费点清单——3 个全屏弹层遮罩(dialog_episode_detail/dialog_tmdb_person/dialog_tmdb_video_player)语义正确,但 dialog_ad_block_stats 三个 source set 各 3 处用于 1dp 分隔线/88dp 行底、dialog_receive 用于海报占位底,因此不能全局替换、必须按视图限定作用域;(5) overlay 语义错配已证实——overlay_light 唯一用法是 dialog_quick_search.xml:80 的 1dp 分隔线,真正的图片 veil 用被 4.23 冻结的 overlay_dark(shape_tmdb_episode_overlay/shape_tmdb_recommendation_info 的 centerColor);(6) 官方一手证据复核通过——Material Components mtrl_scrim_color 恰为 #52000000,与本项目浅色 webhtv_color_scrim 完全一致;(7) 设计文档原文(第 14 槽表格与 Dialog 处理清单)本就把 scrim 定义为 Dialog 外遮罩,故 scrim 属实现遗漏而非设计缺失;(8) 关键风险已记录——TmdbPersonDialog:133 与 EpisodeDetailDialog:240 设 setDimAmount(0f),但 TmdbVideoPlayerDialog:326 设 0.72f,视图 scrim 会与窗口 dim 叠加,故建议首版只接前两个弹窗。方案对比含保持现状/推荐方案B/改绑 veil 解冻 overlayDark/窗口级 dim/移出编辑器五条,并给出推荐、最小实施步骤、验收标准与回滚路径。引用采用原文片段而非绝对行号以避免漂移。本任务未运行构建或设备测试(纯文档,无代码变更)。

Task-Guard: THEME-SCRIM-OVERLAY-20260925
2026-09-25 17:45:41 +08:00
Silent1566
c22cc652a4
Merge pull request #372 from Silent1566/dev4
dev4:同步 beta 并修复转译环境接口重载闪退
2026-09-25 15:27:40 +08:00
Silent1566
27ce58a70f docs: record second beta sync review
Verification: 定向单测(GlobalHistorySettingSourceTest、NativeBridgeGuardTest、PlayerPlaybackRegressionSourceTest)通过;mobile/leanback arm64 Java 编译通过;git diff --check 与两轮净差异复评通过;origin/beta 为祖先且被移除主题提交不是祖先

Task-Guard: BETA-SYNC-REVIEW-DEV4-20260925
2026-09-25 15:19:43 +08:00
Silent1566
30912bac89 Merge remote-tracking branch 'origin/beta' into dev4 2026-09-25 15:11:37 +08:00
Silent1566
c5df062925 fix(loader): retain translated dex loaders to avoid houdini crash
Verification: NativeBridgeGuardTest passed; leanback arm64 debug build and overwrite install on 192.168.50.3:5561 passed; 3 real VOD interface reloads retained translated loaders (total 2/3/4) and left app process alive with empty crash buffer

Task-Guard: MIGRATE-HOUDINI-FIX-DEV4-20260925
2026-09-25 15:05:23 +08:00
www.xueximeng.com
c66f7f1874 docs(cache): record system quota enforcement evidence
Verification: 5563 读取系统缓存配额 478.9MB 并在设置页/缓存页展示;设备设置总上限 1GB(偏好 1073741824),有效上限由 CacheTotalLimitPolicy.effectiveLimit 收敛至配额(CacheTotalLimitPolicyTest 断言 min(1024,512)=512);验证后还原为不限(偏好 0)

Task-Guard: CACHE-MGMT-01-QUOTA-EVIDENCE
2026-09-25 15:01:02 +08:00
www.xueximeng.com
4089b4b91b docs(cache): record mobile flavor device verification
Verification: 5563 覆盖安装 mobileArm64_v8a debug 后实测:设置页显示 缓存管理 25.7MB/478.9MB,弹窗真实扫描 25.7MB/系统配额 478.9MB,三级清理/刷新/确定可见可点,轻度清理返回清理完成且无 FATAL EXCEPTION;验证后重装 leanback flavor 恢复 TV 形态

Task-Guard: CACHE-MGMT-01-MOBILE-EVIDENCE
2026-09-25 14:55:50 +08:00
Silent1566
8ee61fbdb7 docs(theme): record the TV remote focus/selection/back acceptance
Verification: closed the last row of the 4.7 device matrix on dev3 192.168.50.3:5559 (V1923A, API 28, light system) with the leanback arm64 debug build overwrite-installed and focus driven through adb shell input keyevent DPAD_*. Focus movement advanced one cell at a time across the home navigation row ((48,176)->(304,176)->(572,176)->(840,176)) and into the content grid, each step changing 265674-292954 pixels with the focus rect matching the focused=true node in the UI dump; 4-5 selected=true nodes coexisted and stayed distinguishable from the focused one; BACK from both the settings page and the exit dialog returned to HomeActivityCurrent without a stuck or leftover activity; the focused button ring measured #FFFFFF on the #FBFCFF panel (6.39:1, above the focus/surface >= 3:1 gate) and the focus band changed colours identically under the probe and Default, so focus colour is neither lost nor corrupted by theming; under the probe (primary=focus=#C62828, surface=#FFF8E1) the settings page differed from Default by 11474 px at every focus step while a focus move changed 292414 px, showing theming and focus coexist. Probe correction: focus and primary share the same frozen baseline in TV (#A8C7FA both), and the binder only rewrites a shared baseline colour when the roles agree, so an initial probe splitting them (primary=#C62828, focus=#7B1FA2) made the channel refuse every rewrite - a probe defect, not a product one. Two false leads were excluded by reading resources: the fixed translucent focus bar and brand colours (yellow_500 etc.) are deliberate exemptions, and the TV exit dialog is a hardcoded brand surface (shape_exit_confirm_dialog #FBFCFF/#E5EAF3, shape_exit_confirm_badge #E8F0FE/#C7DBFF, selector_exit_confirm_secondary #DCEAFF/#0B57D0/#F8FAFD) that the binder must skip, so the 4.28 fix introduced no regression. Scope stated honestly: 5559 is a tablet-characteristics device without android.software.leanback, so this validates theme-time focus/selection/disabled visibility under D-pad navigation, not real remote hardware. Device state restored byte-identically, night mode back to no, mobile flavour reinstalled, no leftover test files.

Task-Guard: TV-REMOTE-STATES-20260925

Verification: TV 遥控(焦点/选中/返回)三态验收完成,4.7 设备矩阵按设计项收口。设备 dev3 192.168.50.3:5559(V1923A,API28,浅色系统),leanback arm64 debug 覆盖安装,用 adb shell input keyevent DPAD_* 驱动焦点。子项证据:(1) 焦点移动通过——首页导航行 (48,176)->(304,176)->(572,176)->(840,176) 逐格推进,DPAD_DOWN 进入内容网格并继续移动,每步截图变化 265674-292954 像素,焦点框坐标与 UI dump 的 focused=true 节点逐一对应;(2) 选中态通过——UI dump 同时含 4-5 个 selected=true 节点(导航项+网格卡片),选中与焦点项可区分;(3) 返回通过——设置页 BACK 与退出弹窗 BACK 均回到 HomeActivityCurrent,无卡死或残留;(4) 状态可见无丢色——焦点按钮边框 #FFFFFF 对弹窗面板 #FBFCFF 对比度 6.39:1(设计门禁 focus/surface >= 3:1),焦点带在探针与 Default 下换色分布逐项相同(#5D566A->#464050 x246 等);(5) 主题与焦点共存——探针 primary=focus=#C62828/surface=#FFF8E1 下设置页 4 个焦点步各与 Default 相差 11474 像素(bbox (73,72)-(1847,445)),焦点移动步变化 292414 像素,两者互不干扰。探针构造修正:冻结调色板中 focus 与 primary 同色(TV 基线均 #A8C7FA),binder 规定共享基线色的角色取值一致才改写,首个 primary=#C62828/focus=#7B1FA2 的探针会让通道整体拒绝改写,属探针缺陷,改用同值后才有效。排除两个误判:首页/设置页焦点高亮条在探针与 Default 下完全相同,核对资源确认是刻意固定的半透明遮罩与品牌色(yellow_500 等,按设计豁免),真正消费 focus token 的 leanback 侧是 TmdbCastPresenter 与 main 共享的 selector_tmdb_card;TV 退出弹窗面板/按钮两组完全相同,核对 app/src/leanback/res/drawable 确认是硬编码字面量品牌样式(shape_exit_confirm_dialog #FBFCFF/#E5EAF3、shape_exit_confirm_badge #E8F0FE/#C7DBFF、selector_exit_confirm_secondary #DCEAFF/#0B57D0/#F8FAFD),binder 按契约本就跳过,因此 4.28 未引入回退。验收边界如实标注:5559 为 tablet 特性设备(无 android.software.leanback),本行验的是主题语境下焦点/选中/禁用态可见性,用 DPAD 代遥控导航,不等于真实遥控器硬件验证,后者仍无设备。环境还原:偏好按字节恢复(cmp 一致)、夜间模式 no、设备装回 mobile flavor(leanback launcher=0)、应用可正常启动、无残留测试文件。

Task-Guard: TV-REMOTE-STATES-20260925
2026-09-25 14:48:46 +08:00
www.xueximeng.com
53d1149c09 docs(cache): record karaoke module cache isolation evidence
Verification: 5563 实测:缓存页统计 K 歌轨道 256KB/1文件 与 歌词 128KB/1文件;K 歌行清理确认框指向「清理 K 歌轨道」,执行结果释放 6 bytes/删除 1 文件,仅删除 verify.generated.txt,保留非轨道文件与歌词文件,证明模块清理隔离

Task-Guard: CACHE-MGMT-01-KARAOKE-EVIDENCE
2026-09-25 14:47:29 +08:00
www.xueximeng.com
aec62ca27b docs(cache): record EPG live refresh verification
Verification: 5563 本地 HLS 直播源实测:GET /live.m3u 200、GET /epg.xml 200、HLS playlist 与全部 segNNN.ts 200(持续重取),PlaybackState state=3/buffered 30000ms;cache/epg/epg.xml 落盘 319 字节且内容为测试频道与验证节目;验证后 Config 恢复原始 3 行并删除测试 EPG 缓存

Task-Guard: CACHE-MGMT-01-EPG-REFRESH
2026-09-25 14:41:47 +08:00
Silent1566
0e4f4164c8
Merge pull request #371 from Silent1566/dev2
修复移动端全局历史设置触控与持久化
2026-09-25 13:43:49 +08:00
Silent1566
7e42054deb fix(detail): show light cinema backdrop without wash
Verification: profileBackdropKeepsHistoricalTransparencyOverPosterArt passed; mobile arm64 debug build installed over existing package on 192.168.50.3:5555; runtime Cinema light detail shows varied original artwork pixels (148,185,204, 82,63,65, 121,91,89) rather than washed F4F7FA gradient; Gradle daemons stopped

Task-Guard: CINEMA-LIGHT-ORIGINAL-BACKDROP
2026-09-25 13:41:56 +08:00
Silent1566
02016f6b20 fix: harden mobile global history touch and persistence
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.history.GlobalHistorySettingSourceTest --tests com.fongmi.android.tv.ui.activity.PlayerPlaybackRegressionSourceTest BUILD SUCCESSFUL; git diff --check PASS; merged origin/beta 8a06267880 as ancestor; Gradle daemon stopped

Task-Guard: remote-beta-review-20260925
2026-09-25 13:37:25 +08:00
Silent1566
93e9f8ea06 Merge remote-tracking branch 'origin/beta' into dev2 2026-09-25 13:33:20 +08:00
Silent1566
8a06267880
Merge pull request #370 from Silent1566/dev4
合并 dev4:修复自动换线后画面丢失并同步 beta 最新改动
2026-09-25 13:29:29 +08:00
Silent1566
4d24168e8d fix(detail): show profile light backdrop at full opacity
Verification: profileBackdropKeepsHistoricalTransparencyOverPosterArt passed; mobile arm64 debug build installed over existing package on 192.168.50.3:5555; runtime Profile light detail shows original artwork colors (top pixels vary 72,93,98 to 117,83,92) instead of washed translucent surface; Gradle daemons stopped

Task-Guard: PROFILE-LIGHT-ORIGINAL-BACKDROP
2026-09-25 13:26:47 +08:00
Silent1566
8113c3176f docs: record beta sync review state
Verification: Gradle targeted tests and mobile/leanback arm64 Java compilation passed; git diff --check passed; origin/beta is ancestor

Task-Guard: C23-beta-sync-review-dev4-20260925
2026-09-25 13:24:28 +08:00
Silent1566
ced589c09a Merge remote-tracking branch 'origin/beta' into dev4 2026-09-25 13:15:27 +08:00
Silent1566
40c7b3122f fix(detail): keep profile cards translucent
Verification: profileBackdropKeepsHistoricalTransparencyOverPosterArt passed; mobile arm64 debug build installed over existing package on 192.168.50.3:5555; runtime Profile card interior pixels are translucent (225-226 RGB) rather than opaque 255,255,255; Gradle daemons stopped

Task-Guard: THEME-PROFILE-TRANSPARENT-BACKDROP-2
2026-09-25 13:09:16 +08:00
Silent1566
119370caa6 Require explicit touch for global history setting
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.history.GlobalHistorySettingSourceTest BUILD SUCCESSFUL; explicit touch-sequence regression assertions PASS; git diff --check PASS; Gradle daemon stopped

Task-Guard: global-history-mobile-explicit-click
2026-09-25 13:08:07 +08:00
Silent1566
9991cc095a fix(player): rebind surface after automatic line fallback
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.activity.PlayerPlaybackRegressionSourceTest --no-daemon passed; :app:compileMobileArm64_v8aDebugJavaWithJavac and :app:compileLeanbackArm64_v8aDebugJavaWithJavac --no-daemon passed; git diff --check passed

Task-Guard: auto-line-surface-rebind-fix
2026-09-25 12:49:06 +08:00
Silent1566
ba8c3ed699 fix(theme): derive the binder baseline from the compiled flavour palette
Verification: TV (leanback) ignored the custom theme profile entirely. The leanback source set overrides every webhtv_color_* token with the dark table (53/53 identical to main/values-night) and ships no values-night, so TV views always inflate dark; but ThemeController.frozenPalette()/resolveWith() inferred the baseline from Resources.getSystem().uiMode, so on a light-mode device the baseline was the light table while inflation produced the dark one. ThemeBinder only rewrites colours that exactly equal the baseline, so the entire TV channel silently degraded to a no-op. Falsifying experiment on one build, flipping only the system dark setting: light-mode TV home 0 / settings 0 changed pixels vs dark-mode TV home 159174 / settings 11474. Fix: compiledDarkPalette() compares the flavour's actually compiled webhtv_color_* resources against the 19 binder roles and darkPaletteFor() makes an identifiable compiled table authoritative (TV stays dark even when the user picks light), falling back to the old uiMode rule only when the palette cannot be identified; both entry points share the decision. Automated: :app:testMobileArm64_v8aDebugUnitTest --tests 'com.fongmi.android.tv.theme.*' 105 tests green, adding tvFlavourBaselineMustDescribeTheCompiledResources and darkPaletteDecisionKeepsMobileStableAndForcesTvOntoItsCompiledTable. Device (dev3 192.168.50.3:5559, API 28, light system, overwrite install of the final revision): TV home 36999 / settings 11474 changed pixels, the settings value matching the earlier dark-mode control exactly; mobile stayed responsive on a deterministic native settings page (19827 px), so no regression. Device state restored byte-identically (cmp against /tmp/w_base.xml), night mode back to no, mobile flavour reinstalled. Also recorded but not fixed (pre-existing, out of scope): launching SearchActivity without the keyword extra NPEs in SearchFragment.setKeyword:208.

Task-Guard: TV-THEME-PALETTE-20260925

Verification: TV 主题通道失效定位与修复。根因:app/src/leanback/res/values/webhtv_tokens.xml 的 53 项 token 全量覆盖为暗色表且与 main/res/values-night 53/53 逐项相同,leanback 无 values-night,故 TV 侧 inflate 颜色恒为暗色;而 ThemeController.frozenPalette()/resolveWith() 原先用 Resources.getSystem().uiMode 推断浅深,浅色系统下基线取 ThemeTokens.light(),与 ThemeBinder 的精确匹配契约不符,导致 TV 整条主题通道静默 no-op。证伪实验(同一 TV 包仅切系统深浅):浅色 TV 首页 0 / 设置页 0 像素,深色 TV 首页 159174 / 设置页 11474 像素。修复:新增 compiledDarkPalette() 用本 flavor 实际编译的 webhtv_color_* 资源逐项比对 19 个 binder role,再由 darkPaletteFor(compiled, mode, systemDark) 让可识别的编译表成为权威(TV 恒暗,显式选浅色也仍暗),仅无法识别时回退原 uiMode 规则;frozenPalette() 与 resolveWith() 共用该判定。自动化::app:testMobileArm64_v8aDebugUnitTest --tests 'com.fongmi.android.tv.theme.*' 105 项全绿,新增 tvFlavourBaselineMustDescribeTheCompiledResources 与 darkPaletteDecisionKeepsMobileStableAndForcesTvOntoItsCompiledTable 两个契约测试。设备(dev3 192.168.50.3:5559 API28 浅色系统 覆盖安装 最终版本):修复后 TV 首页 36999 / 设置页 11474 像素,设置页数值与修复前深色对照值 11474 完全一致;手机端同探针确定性原生设置页 19827 像素仍正常响应,无回归。环境还原:偏好按字节恢复至 /tmp/w_base.xml(cmp 一致)、夜间模式恢复 no、设备装回 mobile flavor 且可正常启动。顺带记录未修的既有缺陷:无 keyword extra 启动 SearchActivity 会 NPE(SearchFragment.java:208),与本次改动无关。

Task-Guard: TV-THEME-PALETTE-20260925
2026-09-25 12:28:19 +08:00
Silent1566
245ddc0fbf fix(detail): restore profile backdrop transparency
Verification: profileBackdropKeepsHistoricalTransparencyOverPosterArt passed; mobile arm64 debug build installed over existing package on 192.168.50.3:5555; runtime Profile screenshot shows translucent art-influenced background with non-uniform pixels instead of opaque white surface; Gradle daemons stopped

Task-Guard: THEME-PROFILE-TRANSPARENT-BACKDROP
2026-09-25 12:14:58 +08:00
Silent1566
4081b5f683 Prevent mobile global history entry click
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.history.GlobalHistorySettingSourceTest BUILD SUCCESSFUL; delayed mobile listener regression assertion PASS; git diff --check PASS

Task-Guard: global-history-mobile-entry-click
2026-09-25 11:58:27 +08:00
Silent1566
d97de03001 Fix global history mode restart persistence
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.history.GlobalHistorySettingSourceTest BUILD SUCCESSFUL; git diff --check PASS

Task-Guard: global-history-mobile-restart
2026-09-25 11:55:33 +08:00
Silent1566
e8ebb6b9a6
Merge pull request #369 from Silent1566/dev2
合并 beta 最新代码并优化追更卡片操作布局
2026-09-25 11:46:45 +08:00
Silent1566
b5cac8a339 merge: sync latest remote beta and review following actions
Verification: FollowingUiSourceTest 13/13 passed; mobile arm64 debug build/cover-install passed; 1920x1080 and 720x1280 layout verification passed; XML parse and git diff --check passed; no reverted remote paths reintroduced

Task-Guard: C22-beta-sync-review-dev2-20260925
2026-09-25 11:43:37 +08:00
Silent1566
d964faca5e fix(detail): restore cinema style theme control
Verification: DetailModeControllerTest 7/7 passed; mobile arm64 debug build installed over existing package on 192.168.50.3:5555; runtime dump shows Cinema title bounds [28,178][1064,281] and Profile title bounds [276,275][1864,341], restoring distinct card/layout templates; Gradle daemons stopped

Task-Guard: THEME-CINEMA-LAYOUT-STYLE
2026-09-25 11:43:10 +08:00
Silent1566
c32ff7872c Merge remote-tracking branch 'origin/beta' into dev2 2026-09-25 11:12:51 +08:00
Silent1566
3200f6bb01 Place following card actions evenly in the lower row
Verification: FollowingUiSourceTest 13 passed; mobile arm64 debug installed on 192.168.50.3:5557; card actions sit in an equal-width row under the poster

Task-Guard: following-card-actions
2026-09-25 10:40:13 +08:00
www.xueximeng.com
61156ab629 docs(cache): record low-space trigger device evidence
Verification: 5563 root 可逆构造 400MB tmpfs 真实低空间:dumpsys jobscheduler 记录 CacheCleanupJobService 执行,清理历史新增 {mode:STANDARD, reason:low-space, status:COMPLETED, deletedFiles:1},未执行 L3;事后卸载 tmpfs、恢复偏好并确认应用正常启动

Task-Guard: CACHE-MGMT-01-LOWSPACE-EVIDENCE
2026-09-25 10:34:04 +08:00
Silent1566
ac56065718 fix(theme): distinguish light cinema from profile chrome
Verification: TmdbCinemaThemeTest 4/4 passed; mobile arm64 debug build installed over existing package on 192.168.50.3:5555; runtime screenshots show Profile light and Cinema light distinct warm/gold; Gradle daemons stopped

Task-Guard: THEME-CINEMA-DISTINCT
2026-09-25 10:32:37 +08:00
Silent1566
2d21687ad5
Merge pull request #368 from Silent1566/dev4
合并 beta 最新代码并完善点播/直播线路同步
2026-09-25 10:27:20 +08:00
Silent1566
a8f5e6005f test(config): enforce live sync pairing policy
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.server.process.ConfigUseLiveSyncAcceptanceTest passed; :app:compileMobileArm64_v8aDebugJavaWithJavac passed; :app:compileLeanbackArm64_v8aDebugJavaWithJavac passed; scripts/build_arm64_debug_install.sh --flavor leanback --serial 192.168.50.3:5561 built and installed by adb install -r successfully; ./gradlew --stop stopped daemon; origin/beta merged at 6e3d3ede9a; removed-theme implementation commits absent and theme tree unchanged in PR delta

Task-Guard: C22-beta-sync-review-dev4-20260925
2026-09-25 10:23:52 +08:00
Silent1566
3b25f0598b docs(theme): record playback regression acceptance evidence
Verification: dev3 192.168.50.3:5559 (V1923A/API28) with the playprobe custom theme fully active — playback via the exported HomeActivity push path (HomeActivity.checkAction -> VideoActivity.push) rather than the TMDB detail page. Exo kernel (player=EXO), phase=READY with firstFrameMs=3748, dropped=0/rebufferCount=0/rebufferTotalMs=0, decoder profile firstFrames=1 failures=0 drops=0 recoverableErrors=0 blacklisted=false, audio established via OMX.google.aac.decoder + SoftAAC2 44100Hz, position advanced 3363 -> 4362ms with OSD 00:10/03:00, 209922 pixels changed inside the player bbox (28,13,728,464) between samples, and Back -> HomeActivity -> VideoActivity resumed at positionMs=47314 (phase=READY); FATAL EXCEPTION=0 throughout and the theme touched only surrounding UI, never the video surface. Recorded the environment blocker honestly: the device cannot reach api.themoviedb.org (ping 2/2 loss), so the TMDB detail page stalls at its loading state (>10 min, unrelated to theming) and the push path was used to decouple the player from that dependency; two earlier false negatives from am start on the non-exported VideoActivity are documented as invalid evidence. Device prefs restored byte-identical to the pre-experiment baseline (cmp equal, md5 da54c8a4a153a04aa18c8fbdf4e64c7d) and the pushed test video removed. WebHome global skin stays independent per the user's 2026-09-24 decision; TV remote remains the only unexecuted matrix row (needs a leanback device).

Task-Guard: THEME-PLAYBACK-REGRESSION-20260925

Verification: 播放回归设备验收:dev3 192.168.50.3:5559 (V1923A/API28) 探针主题 playprobe 全激活下经 HomeActivity 推送入口播放 180s mp4;Exo 路径 player=EXO,phase=READY firstFrameMs=3748,dropped=0/rebufferCount=0/rebufferTotalMs=0,TV-exo-decoder-profile firstFrames=1 failures=0 drops=0 recoverableErrors=0 blacklisted=false,音频 OMX.google.aac.decoder + SoftAAC2 44100Hz 建立,播放推进 pos 3363->4362ms 且 OSD 00:10/03:00,两帧间播放器区域 bbox(28,13,728,464) 变化 209922 像素,Back 回首页再入 VideoActivity 二段 phase=READY positionMs=47314 续播,全程 FATAL EXCEPTION=0;主题仅改周边 UI 未侵入播放器画面。环境阻塞记录:设备到 api.themoviedb.org 100% 丢包导致 TMDB 详情页停在加载态(>10 分钟无进展,与主题无关),故以本地推送链路解耦验证;直接 am start 非导出 VideoActivity 的两次误判已纠正并写入文档。设备偏好已按字节还原至实验前基线 /tmp/w_base.xml(cmp byte-identical,md5 da54c8a4a153a04aa18c8fbdf4e64c7d;profile=Default theme_color=-291840 detail_open_mode=1),设备测试视频已删除。

Task-Guard: THEME-PLAYBACK-REGRESSION-20260925
2026-09-25 10:18:14 +08:00
www.xueximeng.com
9c491312cc feat(cache): add rollback feature switch for cache management
Verification: 缓存包独立 JUnit 41/41 通过(新增 CachePolicyStoreTest 2 例);双形态 Java 编译通过;5563 覆盖安装实测开关关闭时设置页显示旧式 60.3MB、点击直接全清并回显「无」(cache 由约 60MB 降至 4KB),随后恢复开关为 true

Task-Guard: CACHE-MGMT-01-FEATURE-SWITCH
2026-09-25 10:16:56 +08:00
Silent1566
e52e91441d merge: sync latest remote beta 2026-09-25 10:13:07 +08:00
Silent1566
74bf29f92b fix(config): preserve independent live interface on vod switch
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.server.process.ConfigUseLiveSyncAcceptanceTest passed; :app:compileMobileArm64_v8aDebugJavaWithJavac passed; :app:compileLeanbackArm64_v8aDebugJavaWithJavac passed; corrected APK installed on 192.168.50.3:5561; Gradle daemon stopped

Task-Guard: independent-live-sync-guard
2026-09-25 10:05:29 +08:00
Silent1566
6e3d3ede9a
Merge pull request #367 from Silent1566/dev2
修复 TMDB 中文语言展示并同步 beta
2026-09-25 10:04:44 +08:00
Silent1566
0a9ababdca
Merge pull request #366 from Silent1566/dev1
修复追更站点大小写键匹配
2026-09-25 09:56:55 +08:00
Silent1566
f8853289f3 Merge remote-tracking branch 'origin/beta' into dev2 2026-09-25 09:54:58 +08:00
Silent1566
d73c7eecba fix(tmdb): enforce display language identity
Verification: Leanback Arm64 Debug Java compile passed; targeted Leanback/Mobile JVM and source regressions passed; second review fixed zh-CN/zh-TW identity and removed duplicate Leanback fallback helpers

Task-Guard: C21-tmdb-zh-language-fix
2026-09-25 09:53:47 +08:00
Silent1566
5d788440bb docs: record following key fix recovery state
Verification: VodConfigSiteKeyTest passed; diff checks passed; remote transport and gh auth recovered; excluded commits confirmed absent from HEAD ancestors

Task-Guard: C20-beta-sync-review-dev1-followup
2026-09-25 09:53:09 +08:00
www.xueximeng.com
4a83d02f68 docs(cache): record rollback switch and legacy entry deltas
Verification: 核对第24节第1/6条:FileUtil.getCacheSize/clearCache 仍保留但已无调用方(旧全量入口不再暴露);§23.1 的 cache_mgmt_enabled 功能开关未实现,回滚依赖提交与恢复标签,两处偏离已补入§20.6

Task-Guard: CACHE-MGMT-01-DELTA-SWITCH
2026-09-25 09:28:52 +08:00
www.xueximeng.com
0486a05f03 docs(cache): record EPG retention device evidence
Verification: 5563 实测 EPG 保留策略:构造今日 today.xml 与 2 天前 old.xml 后执行轻度清理,结果释放 4 bytes/删除 1 文件,old.xml 删除、today.xml 保留;验收清单改为部分通过并注明自动刷新仍待直播源

Task-Guard: CACHE-MGMT-01-EPG-EVIDENCE
2026-09-25 09:27:39 +08:00
www.xueximeng.com
d89c7624f2 docs(cache): record lyrics and subtitle device evidence
Verification: 5563 实测:歌词多源检索链路(QQMusic/LRCLIB/ranking/空结果降级)正常执行;外挂 SRT 在 00:02:32 实际渲染中文台词;据此勾选歌词/字幕验收项并记录 K 歌待真实指纹实测

Task-Guard: CACHE-MGMT-01-MEDIA-EVIDENCE
2026-09-25 09:13:36 +08:00
Silent1566
7cd8799dfe Fix following source key case lookup
Verification: app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.api.config.VodConfigSiteKeyTest

Task-Guard: FIX-following-site-key-case
2026-09-25 08:58:00 +08:00
www.xueximeng.com
1cb7cffdc0 fix(cache): protect in-flight temp transfers from cleanup
Verification: 缓存包独立 JUnit 39/39 通过(新增 CacheTempFilePolicyTest 3 例);双形态 Java 编译通过;5563 覆盖安装后轻度清理实测 update.apk 保留、过期 pushed-stale.apk 删除(释放 512KB/删除 1 文件)

Task-Guard: CACHE-MGMT-01-TEMP-ACTIVE
2026-09-25 08:32:52 +08:00
Silent1566
1bbb751861 fix(home): sync matching live interface on vod selection
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.server.process.ConfigUseLiveSyncAcceptanceTest passed; :app:compileLeanbackArm64_v8aDebugJavaWithJavac passed; Gradle daemon stopped

Task-Guard: home-vod-live-sync
2026-09-25 00:41:04 +08:00
Silent1566
8e86516f3d fix(mobile): sync matching live interface in settings
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.server.process.ConfigUseLiveSyncAcceptanceTest passed; :app:compileMobileArm64_v8aDebugJavaWithJavac passed; Gradle daemon stopped

Task-Guard: mobile-setting-vod-live-sync
2026-09-25 00:39:49 +08:00
Silent1566
3a49bfbfef fix(setting): sync matching live interface on vod switch
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.server.process.ConfigUseLiveSyncAcceptanceTest passed; :app:compileLeanbackArm64_v8aDebugJavaWithJavac passed; Gradle daemon stopped

Task-Guard: setting-vod-live-sync
2026-09-25 00:38:14 +08:00
Silent1566
07a0e9c64a fix(config): sync matching live interface on managed vod switch
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.server.process.ConfigUseLiveSyncAcceptanceTest passed; leanback arm64 debug build installed via scripts/build_arm64_debug_install.sh; Gradle daemon stopped

Task-Guard: interface-switch-sync-live
2026-09-25 00:37:01 +08:00
Silent1566
5efe8f14f2
Merge pull request #365 from Silent1566/dev1
合并 dev1:同步 beta 最新代码并评审播放同步稳定身份匹配
2026-09-25 00:25:42 +08:00
Silent1566
8b552cbaa5 docs: record beta sync review delivery
Task-Guard: C20-beta-sync-review-dev1-20260924
2026-09-25 00:17:34 +08:00
Silent1566
4b38555402 merge: sync latest remote beta and align identity schema test
Verification: Mobile/Leanback full JVM suites and Java compile passed (4915 and 4008 tests, 0 failures/errors, 2 skipped each); shared identity fixtures 3/3, Vercel 4/4, Deno 4/4, Cloudflare 6/6 passed; git diff checks passed; mobile arm64 debug APK overlaid on 192.168.50.3:5555 and startup smoke had no crash

Task-Guard: C20-beta-sync-review-dev1-20260924
2026-09-25 00:15:38 +08:00
Silent1566
70592cbc8b
Merge pull request #364 from Silent1566/dev4
优化追更手动已读与 TV 焦点操作
2026-09-24 23:51:56 +08:00
Silent1566
50de93a4d7 docs: add TMDB zh-CN language fix design
Verification: docs/C21-tmdb-zh-language-fix.md created; markdown structure inspected; git diff --check passed

Task-Guard: C21-tmdb-zh-language-fix
2026-09-24 23:43:52 +08:00
Silent1566
8ed3955b6b fix(following): restore left focus from read all
Verification: FollowingUiSourceTest passed via :app:testLeanbackArm64_v8aDebugUnitTest; Gradle daemons stopped

Task-Guard: following-readall-left-focus
2026-09-24 23:32:53 +08:00
Silent1566
cc85ad350c feat: implement playback sync stable identity matching
Verification: 共享身份 fixture 3/3、Vercel 4/4、Deno 4/4、Cloudflare 6/6、Go 测试、Rust 4/4、git diff --check、task_guard check 均通过;Mobile/Leanback 编译与定向单元测试通过;Mobile arm64 Debug 测试包已覆盖安装并完成启动健康检查

Task-Guard: playback-sync-identity-matching-design
2026-09-24 23:24:02 +08:00
Silent1566
236b440b4e fix(following): focus read all on TV remote
Verification: FollowingUiSourceTest passed via :app:testLeanbackArm64_v8aDebugUnitTest; Gradle daemons stopped

Task-Guard: following-readall-focus
2026-09-24 23:22:41 +08:00
Silent1566
94323cd231 feat(following): restore manual read confirmation
Verification: FollowingUiSourceTest passed via :app:testLeanbackArm64_v8aDebugUnitTest; Gradle daemon stopped

Task-Guard: manual-following-read
2026-09-24 23:05:31 +08:00
Silent1566
76c4f09106
Merge pull request #362 from Silent1566/dev4
优化前台追更刷新时效
2026-09-24 22:41:19 +08:00
Silent1566
b23c409f81
Merge pull request #363 from Silent1566/dev2
fix(player): 自动换线路前强制重建播放器
2026-09-24 22:41:04 +08:00
Silent1566
4d5bb4e845 fix(player): force rebuild before automatic line fallback
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.activity.PlayerPlaybackRegressionSourceTest --no-daemon passed (14 tests); :app:compileMobileArm64_v8aDebugJavaWithJavac and :app:compileLeanbackArm64_v8aDebugJavaWithJavac --no-daemon passed; beta merge completed and PR353 theme-removal commits are not ancestors

Task-Guard: auto-line-audio-beta-review
2026-09-24 22:29:38 +08:00
Silent1566
d3077b1dee Merge remote-tracking branch 'origin/beta' into dev2 2026-09-24 22:20:49 +08:00
Silent1566
81cb271024 fix(following): keep foreground refresh cadence bounded
Verification: FollowingSchedulePolicyTest 6/6 passed; Mobile/Leanback arm64 Java compile passed; git diff --check passed; final review passed

Task-Guard: C20-beta-review
2026-09-24 22:18:32 +08:00
Silent1566
8d00bbbe96 Improve foreground following refresh cadence
Verification: FollowingSchedulePolicyTest 5/5 passed; Mobile/Leanback arm64 Java compile passed; git diff --check passed

Task-Guard: C20-foreground-following-refresh
2026-09-24 21:04:45 +08:00
www.xueximeng.com
35e7d678b5 docs(cache): record design-to-implementation deltas
Verification: 逐项核对设计第11.2/14.6节与实现,记录五处偏离(统一上限档位、自动清理默认关、触发条件不可配置、临时文件固定24h、边界文案复用),并将验收清单两项表述与实现对齐

Task-Guard: CACHE-MGMT-01-DESIGN-DELTA
2026-09-24 20:42:40 +08:00
www.xueximeng.com
7f3f32e58d docs(cache): correct acceptance evidence after symlink fix
Verification: 修正文档中因符号链接误判而失真的两处验收证据:20.3 的 16 条 warning 实为祖先符号链接误判(已修复,设备复测无警告);20.2 符号链接项补充祖先别名与最终组件判定说明

Task-Guard: CACHE-MGMT-01-DOC-ACCURACY
2026-09-24 20:36:47 +08:00
www.xueximeng.com
306b627fd9 docs(cache): record 5563 regression verification evidence
Verification: 5563 设备回归:播放/seek/预载实测通过、播放中标准清理不中断、播放器切换前后模块统计一致、备份与恢复闭环成功;EPG 与歌词/字幕/K歌因无源未验证

Task-Guard: CACHE-MGMT-01-REGRESSION-EVIDENCE
2026-09-24 20:34:15 +08:00
Silent1566
00c6087dfe
Merge pull request #361 from Silent1566/dev4
fix(mobile): 修复追番页面内容与操作按钮裁切
2026-09-24 20:21:58 +08:00
Silent1566
fcc412debf fix(mobile): keep following actions evenly spaced
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.activity.FollowingUiSourceTest(BUILD SUCCESSFUL);两份移动端布局 XML 解析通过;git diff --check 通过;修复后二次复评确认所有 Activity/Adapter 绑定 ID 与动作按钮覆盖完整

Task-Guard: following-mobile-layout-review-20260924
2026-09-24 20:17:54 +08:00
Silent1566
51ecec7222 fix(mobile): prevent following page content clipping
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.activity.FollowingUiSourceTest(12 tests,BUILD SUCCESSFUL);1920x1080 与 589x1280 设备截图核验按钮/文本完整可见;git diff --check;已执行 ./gradlew clean

Task-Guard: following-mobile-layout-visibility-20260924
2026-09-24 19:55:28 +08:00
www.xueximeng.com
b93e7ac3bb fix(cache): stop ancestor symlinks from hiding cache roots
Verification: 缓存包独立 JUnit 36/36 通过;双形态 Java 编译通过;5563 覆盖安装后缓存统计恢复为 59.1MB/478.9MB、歌词 1MB/1文件、无部分结果警告;标准清理实测释放 165.3KB/删除 8 文件

Task-Guard: CACHE-MGMT-01-SYMLINK
2026-09-24 19:15:40 +08:00
Silent1566
9801f2b31f
Merge pull request #360 from Silent1566/dev4
dev4:同步 beta 并修复详情页焦点回归
2026-09-24 18:40:39 +08:00
Silent1566
d3e87170c3 fix: reconcile beta focus correction with immediate detail focus
Verification: 双 flavor Java 编译 BUILD SUCCESSFUL in 2m16s;移动端全量 JVM 单测修复后 BUILD SUCCESSFUL in 40s(4908 tests, 0 failed, 2 skipped);git diff --check 与 --cached --check 通过;两轮组合复评通过

Task-Guard: C19-beta-sync-review-dev4-20260924
2026-09-24 18:37:48 +08:00
Silent1566
f16d95efe9 docs: design playback sync identity matching
Verification: git diff --check;文档锚点与 5 个完整 commit ID 校验通过;设计文档包含协议、客户端/服务端实现清单、迁移/冲突/回滚、共享测试与 ID-01 至 ID-24 验收矩阵

Task-Guard: playback-sync-identity-matching-design
2026-09-24 18:27:52 +08:00
Silent1566
00bc40e1f7 merge: sync latest remote beta 2026-09-24 18:26:52 +08:00
Silent1566
21ebe9612b fix: make super parse work on legacy WebView
Verification: compileMobileArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL; scripts/build_arm64_debug_install.sh --serial 192.168.50.3:5561 BUILD SUCCESSFUL and coverage install; clean 5561 run with parse-super start json=0 web=10, wh-wasm JS HMAC shim, webview-sniff m3u8, parse-super web success 虾米, parse-job success, VideoActivity READY firstFrameMs=12310 rebufferCount=0; generated build artifacts and temporary logs cleaned, Gradle daemon stopped

Task-Guard: PLAYBACK-PARSE-SUPER-20260923
2026-09-24 18:07:35 +08:00
Silent1566
882f2033f8 fix(theme): apply dialog opacity to the dialog shell
Verification: 4.7 device matrix: 16-slot row and light/dark row pass with distinguishable probes (light panel #E0E0E0 + #C62828 primary + #C8E6C9 container vs dark #212121 + #80DEEA + #006064, groups independent, no restart needed); resource-recycling row passes over 55 cold-start/dialog/back cycles with FATAL=0 and PSS 331175 -> 313289 kB (no growth); transparency row FAILED and exposed dialogOpacity as a functional dead slot - lower bound 0.70 vs upper bound 1.00 produced byte-identical dialogs (0 changed pixels) because the token only reached the editor preview swatch and the Web snapshot; fixed by applying it to the dialog window shell (ThemeBinder.applyShellOpacity unwraps InsetDrawable and scales the drawable's own fill alpha, strict no-op at >=1 so the frozen baseline stays byte-identical, never touches text alpha per the documented contract); after the fix 0.70 vs 1.00 differ by 374849 px with bbox x474..1444 y342..736 exactly the dialog, 1.00 shows opaque #7B1FA2 and 0.70 shows #6D2B8C (the probe blended 70/30 with the wallpaper) while the title stays #FFFFFF unchanged; new contract+arithmetic test dialogOpacityReachesTheWindowShellAndNotTheText with ThemeBinder.scaleAlpha made package-private for JVM assertion; two failures fixed by correcting my own wrong expectation (0.70*255 rounds to 179) and by updating the 4.19 assertion that still matched the old return-shape; mobile+leanback theme tests and both flavors compileWithJavac PASS; check_ui_tokens --strict PASS; device prefs byte-verified restored. New residual: scrimOpacity and overlayOpacity remain zero-reference dead slots (needs a semantic decision, not just a fix)

Task-Guard: THEME-DIALOG-OPACITY-20260924
2026-09-24 17:26:47 +08:00
Silent1566
4eafca8539
Merge pull request #359 from Silent1566/dev1
修复 TMDB 路由选择的电视遥控操作
2026-09-24 16:36:13 +08:00
Silent1566
940ae26b7f fix: keep TMDB route activation after focus navigation
Verification: 契约测试通过::app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.dialog.TmdbSourceDialogInflationContractTest(2 tests)。mobile/arm64-v8a Debug APK 通过 scripts/build_arm64_debug_install.sh 覆盖安装到 192.168.50.3:5555。实机验证通过:语言输入 Down 自动打开 API 选择器,Back 后 Enter 可重新打开,API Down 可进入图片选择器。二次评审、task_guard check、git diff --check 通过;验证临时 XML 已清理。

Task-Guard: C19-beta-sync-review-dev1-20260924-fix
2026-09-24 16:29:26 +08:00
Silent1566
a4b4fd759f fix(theme): map framework text roles onto webhtv tokens
Verification: root-caused and fixed the framework-text-role gap at the theme layer: Material's Base.V14.Theme.Material3.Light points android:textColorPrimary/Secondary at its own m3_default_color_* selectors which hard-reference m3_sys_color_light_on_surface(_variant) (#1D1B20/#49454F), so Activity-context widgets never followed ?attr/colorOnSurface* and ThemeBinder could not rewrite those unknown values; Theme.WebHTV previously mapped only the Material colorOnSurface attrs, not the framework android:textColor* ones (only the Dialog overlay did); added webhtv_text_primary/secondary selectors preserving Material's disabled emphasis and mapped textColorPrimary/Secondary/Tertiary/Hint onto them so both fixes apply: widgets now resolve our tokens AND match baseline roles so the binder can rewrite them; new guard ThemeBaseWiringTest#activityThemeMapsFrameworkTextRolesToWebhtvTokens; check_ui_tokens --strict first rejected my new resource (hex literals in my own comment) which I removed, now violations=0 legacy=0 contrast 38/0 colors=56; mobile+leanback theme tests and FULL suites pass with zero failing classes, both flavors compileWithJavac PASS; dev3 192.168.50.3:5559 API28 same-coordinate before/after: import-dialog EditText hint went from Material default #50545C to exactly #44474F (webhtv_color_on_surface_variant) and then followed to #FFFFFF under the white onSurfaceVariant probe (it previously ignored themes entirely); panel #CFD8EB vs #7B1FA2 confirms same-screen comparison; device prefs byte-verified restored

Task-Guard: THEME-TEXTCOLOR-MAPPING-20260924
2026-09-24 16:27:25 +08:00
www.xueximeng.com
c59a13ca5f fix(cache): keep deep cleanup confirmation in one dialog
Verification: 双形态 Java 编译通过;5563 覆盖安装 com.silent.android.webhtv 实测:深度清理首次仅一个确认框(取消/继续),点继续后同一窗口更新为不可撤销文案与取消/开始深度清理,无叠加弹窗

Task-Guard: CACHE-MGMT-01-DEEP-CONFIRM
2026-09-24 16:22:25 +08:00
Silent1566
d5065df980 merge: sync latest remote beta
Verification: Beta merge from origin/beta (4b8e6bb80) completed without conflicts; merge content retained in index after resetting only the accidental task-guard baseline commit. No runtime validation run for this reconciliation commit; task review and risk-based verification continue before release.

Task-Guard: C19-beta-sync-review-dev1-20260924
2026-09-24 16:17:13 +08:00
Silent1566
37f92430da fix(player): rebuild player before automatic line fallback
Verification: PlayerPlaybackRegressionSourceTest.autoLineFallbackRebuildsRememberedPlayerBeforeFetchingNextLine (mobile ARM64) passed; :app:compileLeanbackArm64_v8aDebugJavaWithJavac and :app:compileMobileArm64_v8aDebugJavaWithJavac passed; Gradle daemon stopped

Task-Guard: fix-auto-line-audio-only
2026-09-24 16:04:15 +08:00
Silent1566
643f0618c5 fix: open TMDB route picker on focus
Verification: Focused contract test passed: :app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.dialog.TmdbSourceDialogInflationContractTest. Runtime TV verification on 192.168.50.3:5555: scrolling to API route opened picker automatically; DPAD_DOWN+ENTER selected official API; focused API input then reopened its picker by ENTER. Leanback arm64 debug APK built and overwritten via scripts/build_arm64_debug_install.sh. Device preference backup restored byte-for-byte (SHA-256 1c8d9b5e39c28f88d39e72af5bfe6f55c31df07981a0c6849c9554f15b5b2da0).

Task-Guard: FIX-TV-TMDB-ROUTE-AUTO-SWITCH
2026-09-24 15:57:19 +08:00
Silent1566
4b8e6bb803
Merge pull request #358 from Silent1566/dev2
合并上游测试兼容更新并通过 beta 评审
2026-09-24 15:45:52 +08:00
Silent1566
9446ea0caf fix(guard): recover committed and finished task state
Verification: bash -n passed; real repository start/check/finish/tag/archive lifecycle exercised; a separate fresh start succeeded after archive.

Task-Guard: task-guard-recovery-archive
2026-09-24 15:44:02 +08:00
Silent1566
ebf10f99bf merge upstream/main test compatibility update
Verification: :app:compileLeanbackArm64_v8aDebugUnitTestJavaWithJavac --no-daemon BUILD SUCCESSFUL (34s)

Task-Guard: beta-upstream-sync-20260924
2026-09-24 15:32:51 +08:00
Silent1566
ecc2de7e4b fix(theme): give programmatic editor widgets explicit token colours
Verification: programmatic platform widgets in the theme editor now take explicit semantic colours: root cause is that Theme.WebHTV (the Activity theme) never maps android:textColorPrimary, so new TextView/Button/EditText from the Activity context fall back to Material's #49454F (= its on_surface_variant, not our #44474F token) which the binder correctly refuses to rewrite as an unknown colour; ThemeDialog mobile+leanback set colorOnSurface on the edit-mode label and the light/dark toggle plus a new outlinedPill() background (framework Button ships its own light plate, so text-only colouring would go white-on-white), and ThemeColorPickerDialog colours hexLabel/hexInput(text+hint)/useHex the same way; new guard test programmaticEditorWidgetsAlwaysGetTokenColours matches new TextView/EditText/Button incl. fully-qualified forms and follows the declared variable name so widgets coloured elsewhere still pass (it caught and corrected one false positive on first run); mobile+leanback theme tests PASS (ThemeEditorContractTest 12/0) and full mobile+leanback suites PASS with zero failing classes, both compileWithJavac PASS, check_ui_tokens --strict PASS violations=0 legacy=0 contrast 38/0; dev3 192.168.50.3:5559 API28 on the #7B1FA2 probe: 正在编辑 label went #49454F -> #FFFFFF and the 浅色 toggle became a coordinating outlined pill; device prefs byte-verified restored

Task-Guard: THEME-PROGRAMMATIC-WIDGETS-20260924
2026-09-24 15:12:52 +08:00
Silent1566
7a8b7c8962
Merge pull request #356 from Silent1566/dev2
修复电视首页切换站点后的旧分类残留
2026-09-24 14:10:50 +08:00
Silent1566
2559082e3d test(leanback): cover stale home type clearing chain
Verification: :app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.activity.HomeSiteSwitchClearsTypesTest; task_guard check; git diff --check

Task-Guard: beta-merge-review-20260924
2026-09-24 14:06:17 +08:00
www.xueximeng.com
cfbafad5ec fix(cache): make TV cache dialog full-height with clear focus and contrast
Verification: PASS: compileLeanbackArm64_v8aDebugJavaWithJavac; PASS: compileMobileArm64_v8aDebugJavaWithJavac; PASS: TV device NX627J Android 9 192.168.50.3:5563 - panel now spans y~50..1030 of 1080 (was 652px) after switching from MaterialAlertDialog to a self-drawn Dialog; PASS: module title/detail now use theme text colors (were hardcoded #202124/#5F6368) fixing dark-on-dark contrast; PASS: focus ring is a 3dp white stroke with no fill so labels stay bright, and the primary Close button was switched to TonalButton so nothing looks pre-focused; PASS: focus order explicitly wired - device verified UP from refresh now lands on cleanupStandard (previously skipped the whole cleanup row to totalLimit), then retention; no FATAL EXCEPTION

Task-Guard: CACHE-MGMT-01-TVUI2
2026-09-24 13:53:18 +08:00
Silent1566
6edd360509 fix(theme): keep primary readable on every surface role
Verification: restored the Material 3 primary-on-surface readability contract: ThemeResolver.readableAccent keeps hue/chroma and walks HCT tone to the nearest passing tone (Material baseline scheme measures 4.97-10.91:1, our frozen palettes 4.94-10.76, both confirmed from the Material 1.14.0 AAR and measured locally); onPrimary is recomputed when primary is repaired; focus now follows primary because the frozen palette ships focus==primary and the binder only rewrites a shared baseline colour when both roles agree (that divergence was why the first repair attempt left buttons unchanged); ThemeContrast gained the four primary/surface pairs so repair and gate can never disagree; 6 new tests incl. byte-identical empty profile and seed palettes not repaired; 2 pre-existing tests updated where they encoded pre-fix behaviour (documented, not silently loosened); mobile+leanback theme tests and full suites plus both compileWithJavac PASS with zero failing classes; check_ui_tokens --strict PASS; dev3 API28 device: dialog action text went from #0B57D0 (1.28:1, unreadable) to #AAC0FF (4.57:1) on the #7B1FA2 probe while keeping hue, preset chips likewise became legible; device prefs byte-verified restored

Task-Guard: THEME-PRIMARY-CONTRAST-20260924
2026-09-24 13:53:11 +08:00
Silent1566
438c455330 fix(leanback): clear stale home types on site switch
Verification: :app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.activity.HomeSiteSwitchClearsTypesTest

Task-Guard: home-site-clear-types
2026-09-24 13:35:09 +08:00
Silent1566
90e16653b2 fix: use TV pickers for TMDB route selection
Verification: Runtime TV remote verification on 192.168.50.3:5555: API route opened picker, DPAD_DOWN+ENTER selected official API and input text changed to 官方 API(直连); image route opened picker, three DPAD_DOWN+ENTER selected wsrv.nl 图片代理 and input text changed to wsrv.nl 图片代理. Unit contract test passed: :app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.dialog.TmdbSourceDialogInflationContractTest. Leanback arm64 debug APK built and overwritten via scripts/build_arm64_debug_install.sh.

Task-Guard: FIX-TV-TMDB-ROUTE-REMOTE-PICKER
2026-09-24 13:29:33 +08:00
Silent1566
3f8ad880de
Merge pull request #355 from Silent1566/dev2
修复电视详情页焦点裁切与滚动留白
2026-09-24 13:25:05 +08:00
Silent1566
374687e585 fix(theme): theme the remaining AppCompat and platform dialogs
Verification: 9 production AlertDialog.Builder sites in 8 files converted to WebHtvAlertDialogBuilder (ThemeColorPickerDialog, mobile+leanback ThemeDialog, AudioActivity platform AlertDialog, DebugLogDialog x2, leanback HomeMenuKeyDialog/HomeActivity/HistoryActivity); CrashActivity deliberately exempt with in-code rationale; guard test now uses a regex that also catches fully-qualified new androidx.appcompat.app.AlertDialog.Builder( and immediately surfaced 4 previously-unlisted sites; mobile+leanback theme unit tests BUILD SUCCESSFUL; both flavors compileWithJavac PASS; check_ui_tokens --strict PASS violations=0 legacy=0 contrast 38/0; dev3 192.168.50.3:5559 API28: theme colour picker 504631 px and theme editor dialog 637313 px exactly #7B1FA2 with all four corner samples #CFD8EB -> #7B1FA2, FATAL=0; device prefs byte-verified restored

Task-Guard: THEME-ALERTDIALOG-BUILDER-20260924
2026-09-24 13:20:03 +08:00
Silent1566
6d62c593c6 评审远端 beta 合并后的电视详情页焦点修复并补齐相关视频导航
Verification: Leanback arm64-v8a Debug 单元测试通过;leanback/arm64-v8a Debug APK 通过 scripts/build_arm64_debug_install.sh 构建并覆盖安装到 192.168.50.3:5557,安装校验通过;应用启动无本次新增崩溃;最终复评通过:焦点监听安装/移除各一次、相关视频裁切与内边距各一次、相关视频行已纳入 first/last 程序化导航且顺序正确。

Task-Guard: BETA-SYNC-REVIEW-DEV2-20260924
2026-09-24 13:01:26 +08:00
www.xueximeng.com
d187f6ae8b test(exo): avoid package-private recoverable access
Verification: bash ./gradlew :app:testMobileArm64_v8aDebugUnitTest --tests 'com.fongmi.android.tv.player.danmaku.*' --no-daemon (BUILD SUCCESSFUL in 44s)

Task-Guard: fix-exo-recoverable-test-compile
2026-09-24 12:45:28 +08:00
Silent1566
b297c7fc93 Merge remote-tracking branch 'origin/beta' into dev2 2026-09-24 12:27:30 +08:00
Silent1566
e56adc7e5e test(base): realign the stale touch-optimization source assertion
Verification: TouchOptimizationHelperSourceTest realigned to the 584b64514 single-inflate form while preserving its original intent (fragment callbacks registered before the content view; wall then sync inside the override) plus a new assertion that the resolved binding instance is the one passed to setContentView; full mobile unit suite ./gradlew :app:testMobileArm64_v8aDebugUnitTest reports 712 classes / 4863 tests / 0 failures / 0 errors with fresh result timestamps, so the suite is green again after the pre-existing stale red

Task-Guard: TEST-STALE-BASETHEME-ASSERT-20260924
2026-09-24 12:25:35 +08:00
Silent1566
d8c51593a2 refactor(theme): route flavour alert dialogs through the themed builder
Verification: 33 flavor files / 69 raw MaterialAlertDialogBuilder sites migrated to WebHtvAlertDialogBuilder (mobile 20/38, leanback 13/31); guard test widened to main+mobile+leanback (0 raw builders repo-wide) and AdRuleManageDialogLayoutTest updated; mobile+leanback theme unit tests BUILD SUCCESSFUL; both flavors compileWithJavac PASS; full mobile unit suite (712 classes) passed except one pre-existing stale assertion TouchOptimizationHelperSourceTest (its file and the leanback BaseActivity it asserts on are untouched by this task, breakage dates to 584b64514); check_ui_tokens --strict PASS violations=0 legacy=0 contrast 38/0; dev3 192.168.50.3:5559 API28 mobile HistoryActivity delete-all confirm dialog now shows 307808 px exactly #7B1FA2 with four panel sample points #CFD8EB -> #7B1FA2 under the purple probe; device prefs byte-verified restored

Task-Guard: THEME-DIALOG-BUILDER-FLAVORS-20260924
2026-09-24 12:21:52 +08:00
Silent1566
2cdd60fc55 fix: make TMDB route dropdowns TV remote operable
Verification: Unit contract test passed: :app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.dialog.TmdbSourceDialogInflationContractTest; Leanback arm64 debug APK built with scripts/build_arm64_debug_install.sh and overwritten to 192.168.50.3:5555

Task-Guard: FIX-TV-TMDB-ROUTE-REMOTE
2026-09-24 12:17:37 +08:00
Silent1566
5afd512551 fix(theme): recolour the alert dialog window background
Verification: mobile+leanback theme unit tests BUILD SUCCESSFUL incl. new dialogWindowBackgroundIsRecolouredOutsideTheViewTree; leanback compileWithJavac PASS; check_ui_tokens --strict PASS violations=0 legacy=0 contrast 38/0; dev3 192.168.50.3:5559 API28 FollowingActivity import-subscription dialog (same scenario that previously kept the compiled panel) now shows 391852 changed pixels of which 364824 are exactly the probe #7B1FA2, four panel sample points all #CFD8EB -> #7B1FA2, title white via onSurface, primary untouched so buttons stayed baseline blue; device prefs byte-verified restored

Task-Guard: THEME-WINDOW-BACKGROUND-20260924
2026-09-24 12:03:29 +08:00
Silent1566
567bfdcd39 fix(theme): stop passing a self-referencing overlay as a dialog theme
Verification: mobile+leanback theme unit tests BUILD SUCCESSFUL incl. new dialogThemeArgumentsResolveColorPrimaryConcretely (parses every res style + parent chain, requires nearest colorPrimary to be a concrete @color, correctly allows inheriting ThemeOverlay.WebHTV.Dialog.NoInset and would reject the removed self-referencing overlay); mobile+leanback compileWithJavac PASS; check_ui_tokens --strict PASS violations=0 legacy=0 contrast 38/0; dev3 192.168.50.3:5559 API28 FollowingActivity cancel-following dialog now renders with FATAL EXCEPTION=0 and Theme.AppCompat=0 (100% reproducible crash before); decisive device experiment proved ThemeOverlay_WebHTV_Dialog as themeResId does NOT crash so only the self-referencing overlay was defective and the other 36 sites were left untouched

Task-Guard: THEME-DIALOG-THEME-ID-FIX-20260924
2026-09-24 11:54:14 +08:00
Silent1566
005efaf637 按钮/控件焦点也保留上下间距,消除贴屏顶部的拥挤
Verification: leanback/arm64-v8a Debug 构建通过并覆盖安装到 192.168.50.3:5557;实测焦点按钮不再贴屏幕顶端:play [32,24]-[1068,116](原为 y=0)、changeSourceDetail [32,24]-[226,108]、线路芯片 [32,24]-[208,86]、episodeTitle [120,24]-[290,96],均为 12dp 上间距;焦点头部按钮金色描边完整(上 y32-37、下 y102-107),屏幕 0-3 行无金色像素;下方外部链接行 bottom 间距 16dp(y912-992);向下遍历 22 步无元素 y1<0 或 y2>1080;回归验证卡片行标题锚定仍生效(猜你喜欢[24,67]、个性推荐·TMDB[24,67]、主创[24,67] 均完整,无标题残缺)。

Task-Guard: TV-BUTTON-ROW-FOCUS-MARGIN
2026-09-24 11:52:06 +08:00
Silent1566
36d2c1faad
Merge pull request #354 from Silent1566/dev1
修复全局历史显式关闭的持久化
2026-09-24 11:36:47 +08:00
Silent1566
0f4401b57f 卡片行聚焦改为按分区标题锚定,消除标题被切与下一个标题残缺
Verification: leanback/arm64-v8a Debug 构建通过并覆盖安装到 192.168.50.3:5557;在 TmdbDetailActivity(墨雨云间)逐行上下导航实测:聚焦任意卡片行时其分区标题完整可见(如 personalTmdbTitle y24-67、relatedVideoTitle y24-67,均留 12dp 顶部间距),且底部不再出现残缺的下一个标题(DOWN #2 时 personalDoubanList 行底 y1040、下一标题完全移出可视区;其余各步均无标题跨底边);相关视频行焦点卡片四边金色描边完整(上 y710-713、下 y1030-1033、左 x37-40、右 x607-610),上一轮修复无回归。

Task-Guard: TV-CARD-ROW-TITLE-ANCHOR
2026-09-24 11:28:51 +08:00
Silent1566
2c2712e55d refactor(theme): route shared alert dialogs through a themed builder
Verification: mobile+leanback compile BUILD SUCCESSFUL; mobile+leanback theme.* and ui.dialog.* unit tests PASS incl. new guard materialAlertDialogsAreBuiltThroughTheThemedBuilder (0 raw builders left in src/main) and updated DialogRoundedCornerSourceTest; check_ui_tokens --strict PASS violations=0 legacy=0 contrast 38/0; dev3 192.168.50.3:5559 API28 FollowingActivity 导入订阅 dialog (1-arg builder, previously unbound) shows 9980 changed pixels with title/message text moving to #ADADAD under the purple probe vs 0 rewrites before; baseline 409c1b52b rebuilt and reinstalled to prove the 12 ThemeOverlay-as-themeResId crashes are pre-existing (identical stack via git stash), not a migration regression; device prefs byte-verified restored

Task-Guard: THEME-DIALOG-BUILDER-MAIN-20260924
2026-09-24 11:21:30 +08:00
Silent1566
73c4a7d7d5 Fix explicit global history off persistence
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.history.GlobalHistorySettingSourceTest BUILD SUCCESSFUL

Task-Guard: global-history-off-persistence
2026-09-24 11:06:50 +08:00
Silent1566
ac95866199
Merge pull request #353 from Silent1566/dev1
merge: 同步 dev1 最新修复并合入 beta
2026-09-24 10:57:01 +08:00
Silent1566
6aabb5b23a merge: 同步远端 dev1 主题与详情修复
合并 origin/dev1 的主题系统、TMDB 详情模式与播放修复,保留 beta 合并后的外链浏览器与追更/动作卡改动。

Verification: 定向主题/详情/追更/动作卡测试通过;mobile 与 leanback Arm64 Java 编译通过。

Task-Guard: beta-sync-review-dev1-remote-20260924
2026-09-24 10:45:25 +08:00
Silent1566
891c1f4dd4 卡片行焦点留白,避免放大描边被可视区裁切
Verification: leanback/arm64-v8a Debug 构建通过并覆盖安装到 192.168.50.3:5557;复现'从下方行向上选到相关视频'场景,relatedVideoList 行顶保留 24dp 留白(y=48px),焦点卡片 [37,54]-[611,378] 四边金色描边完整(上 y54-57、下 y374-377、左 x37-40、右 x607-610);向下进入该行亦完整(行 y631-967、卡片 y637-961);上下往返多次稳定无抖动。

Task-Guard: TV-CARD-ROW-FOCUS-MARGIN
2026-09-24 10:12:53 +08:00
Silent1566
1c53bf14fe fix: 清理 TMDB 详情页重复导入
Verification: 合并 origin/beta=87c147af5b49e7447a41a0a2267155d3dbef85a0;评审 beta 与 dev1 已提交未推送改动并清理 TmdbDetailActivity 重复导入;bash ./gradlew :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.web.CatWebWiringTest --tests com.fongmi.android.tv.content.ActionCardHelperTest --tests com.fongmi.android.tv.ui.activity.FollowingUiSourceTest :app:compileMobileArm64_v8aDebugJavaWithJavac :app:compileLeanbackArm64_v8aDebugJavaWithJavac --console=plain:BUILD SUCCESSFUL;bash scripts/build_arm64_debug_install.sh --flavor leanback --serial 192.168.50.3:5555:Debug 构建成功并 install -r 覆盖安装;启动首页无崩溃;git diff --check 与重复导入静态检查通过

Task-Guard: beta-sync-review-dev1-20260924
2026-09-24 09:42:17 +08:00
Silent1566
409c1b52bc fix(theme): recolour Material shape panels in the binder
Verification: mobile theme unit tests BUILD SUCCESSFUL incl. backgroundChannelCoversMaterialShapeAndInsetWrappers; dev3 192.168.50.3:5559 API28 LinkDialog(BaseAlertDialog) A/B with 32s cold start + tap: 277730 changed pixels of which 245581 are exactly the probe #7B1FA2 (dialog panel recoloured, previously skipped because the fill is a MaterialShapeDrawable wrapped in InsetDrawable) plus 7870 px text #ADADAD and 4145 px #FFFFFF; primary left untouched so the confirm button stayed baseline blue; device prefs byte-verified restored

Task-Guard: THEME-SHAPE-BACKGROUND-20260924
2026-09-24 09:16:08 +08:00
Silent1566
2a0b8af916 fix(theme): bind FollowingActivity into the shared appearance contract
Verification: mobile+leanback theme unit tests BUILD SUCCESSFUL incl. followingPageOptsIntoTheSharedAppearanceContract and nativeActivitiesOutsideBaseActivityAreExplicitlyAccountedFor; dev3 192.168.50.3:5559 API28 FollowingActivity A/B with 14s cold start: exactly the 14735 baseline #0B57D0 (colorPrimary) pixels left the baseline under the orange #FB8C00 preset and became #88511D, secondaryContainer #DFE2E6 -> #FFDCC2, error #552422 unchanged as expected, FATAL EXCEPTION=0; device prefs byte-verified restored

Task-Guard: THEME-FOLLOWING-BIND-20260924
2026-09-24 09:02:29 +08:00
Silent1566
45eb9b620b Merge remote-tracking branch 'origin/beta' into dev1 2026-09-24 08:53:37 +08:00
Silent1566
49b9b4c3e6 修复电视 TMDB 详情页相关视频焦点放大裁切
Verification: leanback/arm64-v8a Debug 构建通过并覆盖安装到 192.168.50.3:5557;在 TmdbDetailActivity(墨雨云间·剧幕)聚焦相关视频首卡,实测四边金色描边完整:顶边 y184-187、底边 y504-507、左边 x37-40、右边 x607-610,均落在 relatedVideoList 容器边界内。

Task-Guard: TV-RELATED-VIDEO-FOCUS-CLIP-2
2026-09-24 01:58:46 +08:00
www.xueximeng.com
43307d50d3 fix(cache): make TV cache dialog 90% adaptive and fully scrollable
Verification: PASS: compileLeanbackArm64_v8aDebugJavaWithJavac; PASS: compileMobileArm64_v8aDebugJavaWithJavac; PASS: TV device NX627J Android 9 192.168.50.3:5563 - dialog outer bounds [96,54][1824,1026] = 1728x972 of 1920x1080 (~90%x90%); PASS: content root is a scrollable Android ScrollView covering the content area; PASS: after remote-key scrolling, autoCleanup/retention/totalLimit/cleanupLight/cleanupStandard/cleanupDeep/refresh/close all visible and focusable; PASS: no FATAL EXCEPTION after fixing the LayoutParams ClassCastException regression

Task-Guard: CACHE-MGMT-01-TVUI
2026-09-24 01:05:52 +08:00
Silent1566
db06ebb4cb fix(theme): bind the native dialog families to the theme tokens
Verification: mobile+leanback theme unit tests BUILD SUCCESSFUL incl. alertDialogFamiliesBindThroughTheSharedDialogChannel; :app:compileLeanbackArm64_v8aDebugJavaWithJavac PASS; dev3 192.168.50.3:5559 API28 ConfigDialog(BaseAlertDialog) A/B with 30s cold start: noise baseline default-vs-default=320 px, teal seed=9545 px, slot probe=22498 px, and exactly the 7870 pixels rendered #181A1C (?attr/colorOnSurface) in default turned #ECECEC under the onSurface=#FFFFFF probe (0 rewrites before this change); device prefs restored to pre-test values

Task-Guard: THEME-DIALOG-BIND-20260923
2026-09-24 00:47:29 +08:00
Silent1566
f54d4de2d6 fix(tv): guard WebView anti-darkening by capability
Verification: bash ./gradlew :app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.web.CatWebWiringTest :app:compileLeanbackArm64_v8aDebugJavaWithJavac --console=plain: BUILD SUCCESSFUL; bash scripts/build_arm64_debug_install.sh --flavor leanback --serial 192.168.50.3:5555: BUILD SUCCESSFUL and install -r success; runtime check on 192.168.50.3:5555 confirmed builtin browser opens CatWebActivity without UnsupportedOperationException on Android 9 WebView.

Task-Guard: catwebbrowser-disable-auto-darkening
2026-09-24 00:40:44 +08:00
www.xueximeng.com
46b19b9111 docs(cache): record recovery anchor and device blocker
Verification: PASS: recovery anchor updated with current test count 34/34, completed offline hardening, exact offline blocker (assigned device 192.168.50.3:5563 offline for 3 consecutive goal turns), the 5 device-dependent acceptance items, and the single next action to take once the device recovers

Task-Guard: CACHE-MGMT-01-ANCHOR
2026-09-23 22:00:44 +08:00
www.xueximeng.com
44d9afb9ef fix(cache): confine retention deletions to the declared root
Verification: PASS: compileMobileArm64_v8aDebugJavaWithJavac; PASS: compileLeanbackArm64_v8aDebugJavaWithJavac; PASS: cache pure JUnit 34/34 including new out-of-root deletion guard and symlink-skip tests

Task-Guard: CACHE-MGMT-01-BOUNDS
2026-09-23 21:37:01 +08:00
www.xueximeng.com
a2d4e7467e docs(cache): record playback hot-path diff audit
Verification: PASS: git diff vs baseline 8e4d9333de over player/, androidx/media3/mpvplayer, web/, api/, service/, App and AndroidManifest is 110 insertions, 0 modifications, 0 deletions (pure additions); DiskCacheCapacityPolicy and LRU evictor untouched; recorded as structural evidence only, device-level in-play cleanup remains unverified

Task-Guard: CACHE-MGMT-01-HOTPATH
2026-09-23 21:03:35 +08:00
www.xueximeng.com
91fdd30412 feat(cache): validate module registry root invariants
Verification: PASS: compileMobileArm64_v8aDebugJavaWithJavac; PASS: compileLeanbackArm64_v8aDebugJavaWithJavac; PASS: cache pure JUnit 32/32 including new CacheModuleRegistryTest (unique ids, cache-dir containment, nested/duplicate root rejection, registry purity)

Task-Guard: CACHE-MGMT-01-REGISTRY
2026-09-23 20:51:20 +08:00
Silent1566
87c147af5b
Merge pull request #352 from Silent1566/dev4
修复动作卡片空回传误报并同步 beta
2026-09-23 20:36:16 +08:00
Silent1566
1f42fa6927 fix: preserve action success and error semantics
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.content.ActionCardHelperTest and :app:compileMobileArm64_v8aDebugJavaWithJavac passed (BUILD SUCCESSFUL)

Task-Guard: ACTION-CARD-EMPTY-SUCCESS-20260923
2026-09-23 20:23:06 +08:00
Silent1566
090918863c 修复电视详情页相关视频焦点放大裁切
Verification: 资源编译通过;192.168.50.3:5557 上聚焦《墨雨云间》相关视频卡片,焦点四边、标题及底部标签均完整显示,无裁切。

Task-Guard: TV-RELATED-VIDEO-FOCUS-CLIP
2026-09-23 20:14:29 +08:00
www.xueximeng.com
b143c13e96 fix(cache): keep total-limit rescan off the main thread
Verification: PASS: compileMobileArm64_v8aDebugJavaWithJavac; PASS: compileLeanbackArm64_v8aDebugJavaWithJavac; PASS: cache pure JUnit 25/25; FIX: total-limit follow-up scan now runs on scheduler background thread instead of main thread

Task-Guard: CACHE-MGMT-01-LIMIT
2026-09-23 20:05:51 +08:00
Silent1566
fdf31d00d1 Merge remote-tracking branch 'origin/beta' into dev4 2026-09-23 19:39:46 +08:00
Silent1566
a993531170 feat(tv): choose browser for TMDB external links
Verification: bash ./gradlew :app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.web.CatWebWiringTest :app:compileLeanbackArm64_v8aDebugJavaWithJavac :app:compileMobileArm64_v8aDebugJavaWithJavac --console=plain: BUILD SUCCESSFUL; bash scripts/build_arm64_debug_install.sh --flavor leanback --serial 192.168.50.3:5555: BUILD SUCCESSFUL and install -r success; runtime check on 192.168.50.3:5555 confirmed external link click shows choice dialog and builtin choice opens CatWebActivity.

Task-Guard: tmdb-external-link-choice-browser
2026-09-23 19:28:39 +08:00
Silent1566
04908bf044 fix(theme): make theme colour actually reach native views
Verification: theme unit tests (mobile theme scope) BUILD SUCCESSFUL incl. new seed-mapping/fallback/button-channel contracts; scripts/check_ui_tokens.sh --strict PASS (violations=0 legacy=0 contrast 38/0 min=4.28); dev3 192.168.50.3:5559 API28 device A/B: slot probe turned exactly the 4008 baseline onSurface pixels white and 3094 pixels respond to a teal seed on HistoryActivity, unbindable FollowingActivity unchanged as control

Task-Guard: THEME-COLOR-BASELINE-20260923
2026-09-23 19:15:52 +08:00
www.xueximeng.com
6e430268e5 docs(cache): record vod config blocker root cause
Verification: PASS: blocker root cause captured from device stack trace: VodConfig.load NPE at OkHttp.newCall(OkHttp.java:174) because the configured VOD url was null; this blocks source-dependent playback/lyrics/karaoke/EPG regression checks and is unrelated to cache-management changes

Task-Guard: CACHE-MGMT-01-ROOTCAUSE
2026-09-23 18:57:49 +08:00
Silent1566
55a8412d2a fix: treat empty action response as success
Verification: ActionCardHelperTest 2/2 passed; mobile arm64 debug assembled and installed to 192.168.50.3:5561; APK sha256 35f754ba09ab18ca146e0e2c05cfefb47651cfadc33573aa4d52e484abc3005d

Task-Guard: ACTION-CARD-EMPTY-SUCCESS-20260923
2026-09-23 18:43:27 +08:00
www.xueximeng.com
561b65fd0f docs(cache): record playback regression blockers
Verification: PASS: regression blocker recorded with direct device evidence; local ijk-smoke.mp4 and remote sample both returned MediaSession Source error state=7 on NX627J; no VOD/EPG config loaded; TV uiautomator returned null root; these acceptance items remain unchecked

Task-Guard: CACHE-MGMT-01-REGRESS
2026-09-23 18:17:38 +08:00
www.xueximeng.com
202529c530 docs(cache): record config preservation evidence
Verification: PASS: on NX627J Android 9, after running STANDARD cleanup (result PARTIAL, 0 deleted), mpv.conf md5 remained d696b6350e5cfc151769066120b803c3, fonts.conf remained cf92f416c8dc00d940765b5243032887, and WebHome preference lines hash remained 7963216a978342b128f5a24e3c909fee

Task-Guard: CACHE-MGMT-01-CONFIG
2026-09-23 17:50:41 +08:00
www.xueximeng.com
15df276114 docs(cache): record persistent job scheduling evidence
Verification: PASS: NX627J Android 9 auto-cleanup toggle persisted cache_mgmt_auto_enabled=true/false; PASS: dumpsys jobscheduler shows persisted 7-day CacheCleanupJobService with batteryNotLow; PASS: disabling auto cleanup left pending queue empty and job cancelled

Task-Guard: CACHE-MGMT-01-JOB
2026-09-23 16:40:08 +08:00
www.xueximeng.com
9b827c8195 docs(cache): record compatibility acceptance evidence
Verification: PASS: NX627J Android 9 rotation and night-mode toggles kept cache dialog controls intact with process alive and no FATAL/ANR; PASS: tv main database content file unchanged by cache dialog; PASS: cache_mgmt_inventory_duration_ms=9, modules=13, warnings=16

Task-Guard: CACHE-MGMT-01-COMPAT
2026-09-23 15:16:07 +08:00
Silent1566
61ddddec4b
Merge pull request #351 from Silent1566/dev2
dev2 同步 beta:追更播放与 TV 布局修复
2026-09-23 15:12:26 +08:00
Silent1566
ca0456c30b Merge remote-tracking branch 'origin/beta' into dev2 2026-09-23 14:50:48 +08:00
Silent1566
223060c18f feat(tv): open TMDB external links in app browser
Verification: bash ./gradlew :app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.web.CatWebWiringTest :app:compileLeanbackArm64_v8aDebugJavaWithJavac :app:compileMobileArm64_v8aDebugJavaWithJavac --console=plain: BUILD SUCCESSFUL; bash scripts/build_arm64_debug_install.sh --flavor leanback --serial 192.168.50.3:5555: BUILD SUCCESSFUL and install -r success; aapt2/aapt APK inspection confirms detail_external_opening string and CatWebActivity/TmdbDetailActivity manifest entries.

Task-Guard: tmdb-external-link-in-app-browser
2026-09-23 14:43:23 +08:00
Silent1566
1366f2dba6
Merge pull request #350 from Silent1566/dev4
合并 dev4:完善 TMDB 自动线路与追更页适配
2026-09-23 14:41:51 +08:00
www.xueximeng.com
9d9a644c16 docs(cache): remove stale head reference
Verification: PASS: documentation state no longer pins a stale HEAD; reflects current verified implementation and remains committed

Task-Guard: CACHE-MGMT-01-DOCS2
2026-09-23 14:34:35 +08:00
www.xueximeng.com
b496926734 docs(cache): reconcile acceptance checklist with device evidence
Verification: PASS: acceptance checklist updated from authoritative evidence: inventory scan 9ms/13 modules/16 warnings on NX627J Android 9; mobile and TV cleanup completion verified; cache pure JUnit 25/25; arm64 debug builds compiled and installed

Task-Guard: CACHE-MGMT-01-DOCS
2026-09-23 14:30:25 +08:00
www.xueximeng.com
aa6abd4dd4 feat(cache): persist inventory scan metrics
Verification: PASS: compileMobileArm64_v8aDebugJavaWithJavac; PASS: compileLeanbackArm64_v8aDebugJavaWithJavac; PASS: device inventory metrics on NX627J Android 9 at 192.168.50.3:5563: 13 modules, 16 warnings, 9 ms scan duration; PASS: leanback debug install via temporary applicationId override without source change

Task-Guard: CACHE-MGMT-01-OBS
2026-09-23 14:25:27 +08:00
www.xueximeng.com
41fb1689a6 docs(cache): record mobile and TV acceptance evidence
Verification: PASS: mobile device smoke on LIO-AN00 Android 9 (192.168.50.3:5555) including cleanup completion dialog; PASS: TV leanback device smoke on NX627J Android 9 (192.168.50.3:5563) including cleanup completion dialog and persisted cache_mgmt_cleanup_history; PASS: cache pure JUnit 25/25

Task-Guard: CACHE-MGMT-01-EVIDENCE
2026-09-23 13:29:29 +08:00
Silent1566
587c4d51f6 调整去广告实验性设置提示
Verification: bash ./gradlew :app:processMobileArm64_v8aDebugResources --offline --console=plain: BUILD SUCCESSFUL

Task-Guard: AD-SETTINGS-EXPERIMENTAL-WARNING
2026-09-23 13:29:04 +08:00
Silent1566
e6634543ee Merge remote-tracking branch 'origin/beta' into dev4 2026-09-23 13:04:12 +08:00
Silent1566
0f110b3115 fix(following): scroll TV header with content
Verification: git diff --check passed; XML parsing passed for main and leanback layouts; FollowingUiSourceTest BUILD SUCCESSFUL; leanback arm64-v8a Debug build and overwrite installation to 192.168.50.3:5561 succeeded; runtime reproduction verified the TV header scrolls with content, FollowingActivity remained resumed, screenshots captured, and no FATAL EXCEPTION occurred; Gradle daemons stopped

Task-Guard: FOLLOWING-TV-FOCUS-VISIBILITY-20260923
2026-09-23 12:49:15 +08:00
Silent1566
584b64514a fix(base): keep one inflated binding per activity
Verification: mobile arm64 debug build + overwrite install Success on 192.168.50.3:5559; bottom bar taps verified: 点播 -> VodFragment visible/SettingFragment hidden, 设置 -> SettingFragment visible, 直播 -> LiveActivity resumed; FATAL EXCEPTION=0; leanbackArm64_v8aDebug assemble SUCCESS

Task-Guard: HOME-NAV-BINDING-20260923
2026-09-23 12:43:20 +08:00
www.xueximeng.com
d404d93aae feat(cache): add safe plugin cache retention
Verification: PASS: cache pure JUnit 25/25 (CacheInventoryTest + CachePolicyEngineTest + CacheRetentionManagerTest + CacheAutoCleanupPolicyTest + CacheCleanupJournalTest + CacheTotalLimitPolicyTest) via direct JUnit runner; PASS: compileMobileArm64_v8aDebugJavaWithJavac; PASS: compileLeanbackArm64_v8aDebugJavaWithJavac

Task-Guard: CACHE-MGMT-01-P2D
2026-09-23 11:40:14 +08:00
www.xueximeng.com
e6630f6f1b fix(cache): keep cache dialog actions visible on mobile
Verification: PASS: mobile debug install and device smoke on LIO-AN00 Android 9 at 192.168.50.3:5555; PASS: cache dialog layout shows module list, limits, auto-cleanup, retention, total limit, and all three cleanup buttons; PASS: light cleanup confirmation and result dialog completed; NOTE: leadback package installs on HD1910 but TV focus-navigation acceptance remains unverified

Task-Guard: CACHE-MGMT-01-UI
2026-09-23 11:26:54 +08:00
Silent1566
c575029dc5
Merge pull request #349 from Silent1566/dev1-following-resume-fix-20260923
修复追更页继续播放的来源绑定与详情模式路由
2026-09-23 11:02:06 +08:00
Silent1566
6b1d8652a8 Merge remote-tracking branch 'origin/beta' into dev1 2026-09-23 10:55:17 +08:00
Silent1566
90faa2bada fix(following): respect configured detail mode on continue playback
Verification: :app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.activity.FollowingUiSourceTest BUILD SUCCESSFUL; :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.activity.FollowingUiSourceTest BUILD SUCCESSFUL; git diff --check passed; Gradle daemons stopped

Task-Guard: tv-following-respect-tmdb-mode
2026-09-23 10:36:29 +08:00
www.xueximeng.com
0790ca363a fix(cache): enforce temp file limit and hide unimplemented plugin limit
Verification: PASS: cache pure JUnit 24/24 (CacheInventoryTest + CachePolicyEngineTest + CacheRetentionManagerTest + CacheAutoCleanupPolicyTest + CacheCleanupJournalTest + CacheTotalLimitPolicyTest) via direct JUnit runner; PASS: compileMobileArm64_v8aDebugJavaWithJavac; PASS: compileLeanbackArm64_v8aDebugJavaWithJavac

Task-Guard: CACHE-MGMT-01-P2C
2026-09-23 10:11:15 +08:00
www.xueximeng.com
0392c5e095 feat(cache): add P2 total cache soft limit
Verification: PASS: cache pure JUnit 23/23 (CacheInventoryTest + CachePolicyEngineTest + CacheRetentionManagerTest + CacheAutoCleanupPolicyTest + CacheCleanupJournalTest + CacheTotalLimitPolicyTest) via direct JUnit runner; PASS: compileMobileArm64_v8aDebugJavaWithJavac; PASS: compileLeanbackArm64_v8aDebugJavaWithJavac

Task-Guard: CACHE-MGMT-01-P2B
2026-09-23 10:09:09 +08:00
www.xueximeng.com
214eae7ba1 fix(cache): persist auto cleanup across reboot and guard symlinks
Verification: PASS: cache pure JUnit 20/20 (CacheInventoryTest + CachePolicyEngineTest + CacheRetentionManagerTest + CacheAutoCleanupPolicyTest + CacheCleanupJournalTest) via direct JUnit runner; PASS: compileMobileArm64_v8aDebugJavaWithJavac; PASS: compileLeanbackArm64_v8aDebugJavaWithJavac; PASS: processMobileArm64_v8aDebugManifest; PASS: processLeanbackArm64_v8aDebugManifest

Task-Guard: CACHE-MGMT-01-P3B
2026-09-23 10:06:05 +08:00
www.xueximeng.com
b405167163 feat(cache): add P4 runtime governance and cleanup journal
Verification: PASS: cache pure JUnit 19/19 (CacheInventoryTest + CachePolicyEngineTest + CacheRetentionManagerTest + CacheAutoCleanupPolicyTest + CacheCleanupJournalTest) via direct JUnit runner; PASS: compileMobileArm64_v8aDebugJavaWithJavac; PASS: compileLeanbackArm64_v8aDebugJavaWithJavac; LIMIT: reboot recovery still not implemented

Task-Guard: CACHE-MGMT-01-P4
2026-09-23 09:34:21 +08:00
www.xueximeng.com
b3e89479ae feat(cache): add P3 automatic cleanup scheduler
Verification: PASS: cache pure JUnit 18/18 (CacheInventoryTest + CachePolicyEngineTest + CacheRetentionManagerTest + CacheAutoCleanupPolicyTest) via direct JUnit runner; PASS: compileMobileArm64_v8aDebugJavaWithJavac; PASS: compileLeanbackArm64_v8aDebugJavaWithJavac; LIMIT: process-local scheduler only; reboot recovery not implemented

Task-Guard: CACHE-MGMT-01-P3A
2026-09-23 09:17:36 +08:00
www.xueximeng.com
eeca921eb6 feat(cache): add P2 module limits and retention policy
Verification: PASS: cache pure JUnit 15/15 (CacheInventoryTest + CachePolicyEngineTest + CacheRetentionManagerTest) via direct JUnit runner; PASS: compileMobileArm64_v8aDebugJavaWithJavac; PASS: compileLeanbackArm64_v8aDebugJavaWithJavac; NOTE: full unit-test task still blocked by pre-existing ExoCompressedAudioDirectPolicyTest isRecoverable visibility error

Task-Guard: CACHE-MGMT-01-P2
2026-09-23 08:51:10 +08:00
www.xueximeng.com
d6393243d6 feat(cache): add P1 tiered module cleanup
Verification: PASS: cache pure JUnit 12/12 (CacheInventoryTest + CachePolicyEngineTest) via direct JUnit runner; PASS: compileMobileArm64_v8aDebugJavaWithJavac; PASS: compileLeanbackArm64_v8aDebugJavaWithJavac; NOTE: full unit-test task still blocked by pre-existing ExoCompressedAudioDirectPolicyTest isRecoverable visibility error

Task-Guard: CACHE-MGMT-01-P1
2026-09-23 08:38:33 +08:00
Silent1566
5559baa86d fix(following): force TV continue playback to direct history route
Verification: :app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.activity.FollowingUiSourceTest BUILD SUCCESSFUL; :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.activity.FollowingUiSourceTest BUILD SUCCESSFUL; scripts/build_arm64_debug_install.sh --flavor leanback --abi arm64-v8a --serial 192.168.50.3:5555 BUILD SUCCESSFUL and adb install -r Success; FollowingContinueDeviceTest OK (1 test); git diff --check passed

Task-Guard: tv-following-direct-resume-route
2026-09-23 04:22:33 +08:00
Silent1566
d1ef28cf97 fix(following): keep TV content below top edge
Verification: git diff --check passed; FollowingUiSourceTest BUILD SUCCESSFUL; leanback arm64-v8a Debug build and overwrite install to 192.168.50.3:5561 succeeded; runtime UI verified top controls at y=56, recycler at y=152, first item title at y=192, FollowingActivity resumed, no FATAL EXCEPTION

Task-Guard: FOLLOWING-TV-TOP-INSET-20260923
2026-09-23 01:53:15 +08:00
Silent1566
4b18b8266a fix(following): preserve source binding on continue playback
Verification: :app:testLeanbackArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.activity.FollowingUiSourceTest BUILD SUCCESSFUL; git diff --check passed

Task-Guard: tv-following-continue-source
2026-09-23 00:03:55 +08:00
www.xueximeng.com
77b5d10421 feat(cache): add P0 cache inventory and management overview
Verification: PASS: compileMobileArm64_v8aDebugJavaWithJavac; PASS: compileLeanbackArm64_v8aDebugJavaWithJavac; NOTE: unit-test source added, full unit-test compilation blocked by pre-existing ExoCompressedAudioDirectPolicyTest isRecoverable visibility error

Task-Guard: CACHE-MGMT-01-P0
2026-09-22 23:42:33 +08:00
Silent1566
6c3d1bbb8e fix(nav): keep core bottom navigation items visible by default
Verification: mobile arm64 debug build Success and overwrite install on 192.168.50.3:5559; cold start nav_position=1 renders 3 bottom items vod/live/setting at 295x140 each with icons, while lab/following stay hidden by config; FATAL EXCEPTION=0

Task-Guard: HOME-NAV-VISIBILITY-20260922
2026-09-22 22:16:05 +08:00
www.xueximeng.com
987f19e90e docs: add cache management upgrade design
Verification: Documentation-only design review: CACHE-MGMT-01 design includes evidence-backed architecture, module boundaries, cleanup policy, UI/TV behavior, phased plan, test matrix, acceptance criteria, rollback, and implementation checklist; static checks passed after replacing Markdown hard-break trailing spaces: 1724 lines, no conflict markers, guard check PASS, task_guard.sh start/finish used.

Task-Guard: CACHE-MGMT-01
2026-09-22 20:55:45 +08:00
Silent1566
adb79ea256 feat(theme): color preset chips and mark active seed
Verification: mobile arm64 debug build Success and overwrite install on 192.168.50.3:5559; on-device theme editor: default/wallpaper neutral chips, blue/teal/green/orange rendered in their own colors, selected chip switches blue->teal with visible high-contrast stroke; cancel closes dialog; FATAL EXCEPTION=0

Task-Guard: THEME-EDITOR-USABILITY-20260922
2026-09-22 20:05:13 +08:00
Silent1566
99e96c9218
Merge pull request #348 from Silent1566/dev2
feat: 增强 TMDB 自动线路与故障切换
2026-09-22 17:46:52 +08:00
Silent1566
bec5a5c098 Merge remote-tracking branch 'origin/beta' into dev2 2026-09-22 17:38:47 +08:00
Silent1566
ae1c334080 fix(tmdb): migrate legacy default routes to auto
Verification: 历史官方默认配置(无 routeMode)在 Android 9 UI dump 中 API/图片均显示自动;新增 routeMode 保证新用户明确选择官方直连后仍保持直连、历史自定义不改变;相关配置测试通过;Debug 包覆盖安装到 192.168.50.3:5557

Task-Guard: tmdb-route-mode-legacy
2026-09-22 17:27:19 +08:00
Silent1566
ae67e809a1 fix(tmdb): put auto route first and align failover labels
Verification: API 与图片两个自动选项文案统一为低延迟优先/失败切换,并均已放到各自下拉第一项;TmdbProxyTest 与 UI 聚焦测试通过,BUILD SUCCESSFUL;git diff --check 通过

Task-Guard: tmdb-api-auto-order-fix
2026-09-22 17:13:22 +08:00
Silent1566
70674c7fc4 fix(tmdb): put auto route first and align labels
Verification: API 与图片自动选项文案统一为低延迟优先/失败切换;两类下拉列表均将自动置于第一项;TmdbProxyTest 与 UI 资源/Java 聚焦测试通过,BUILD SUCCESSFUL;git diff --check 通过

Task-Guard: tmdb-auto-label-order
2026-09-22 16:48:37 +08:00
Silent1566
f72b4ec260 fix(tmdb): default legacy official routes to auto
Verification: 历史官方默认配置 UI dump 现显示 API/图片自动选项;显式 routeConfigured 自定义/直连保留测试通过;Mobile ARM64 Debug 聚焦测试 BUILD SUCCESSFUL;Debug 包已覆盖安装到 192.168.50.3:5557,未卸载已有包

Task-Guard: tmdb-auto-default-legacy
2026-09-22 16:28:02 +08:00
Silent1566
e2bce36ed5 feat(tmdb): add automatic route failover and wsrv image proxy
Verification: 研究记录已写入 docs/tmdb-proxy-design.md;自定义 API/图片配置、wsrv.nl URL 包装、API/图片自动候选、低延迟排序与失败冷却单测通过;Mobile ARM64 Debug 聚焦测试 BUILD SUCCESSFUL;scripts/build_arm64_debug_install.sh 已构建并覆盖安装到 192.168.50.3:5557,运行时 UI dump 确认 API/图片线路下拉控件;未卸载已有包

Task-Guard: tmdb-auto-failover
2026-09-22 15:43:27 +08:00
Silent1566
975708fe6b
Merge pull request #347 from Silent1566/dev4
合并 dev4:稳定接口身份与多地址支持
2026-09-22 15:29:25 +08:00
Silent1566
1f008c0da9 fix: preserve remote config identity during upsert
Verification: 已完成全量改动复评并修复远端配置稳定身份缺口;StableInterfaceIdentityAcceptanceTest 定向测试 BUILD SUCCESSFUL;git diff --check 通过;task_guard check 通过;Gradle daemon 已停止并回收资源

Task-Guard: dev4-beta-sync-20260922
2026-09-22 15:24:24 +08:00
Silent1566
d2ea042db7 Merge remote-tracking branch 'origin/beta' into dev4 2026-09-22 15:06:58 +08:00
Silent1566
5394255511 fix: wait for TV interface target before focusing
Verification: Fixed the remaining runtime gap where one DPAD move could leave focus on the previous row: Leanback ConfigAdapter now waits for the target RecyclerView child to attach, requests focus once, and removes the attach listener after success; no smooth scrolling or repeated delayed focus callbacks; InterfaceEntryInteractionTest and ConfigHistoryCurrentSourceGuardTest passed (10 tests total); Leanback arm64-v8a Debug APK compiled and was covered-installed with install -r to 192.168.50.3:5561; runtime UI dump verified consecutive DPAD_DOWN sequence across all six interface rows and add button, then DPAD_UP back across all six rows; Gradle daemon stopped and temporary UI dumps cleaned; git diff --check passed

Task-Guard: leanback-interface-focus-attach
2026-09-22 14:51:24 +08:00
Silent1566
85ebd3bcfa fix: remove TV interface focus flicker
Verification: InterfaceEntryInteractionTest passed with 8 tests, 0 failures, and 0 errors; ConfigHistoryCurrentSourceGuardTest passed with 2 tests; leanback arm64-v8a debug Java compilation passed; latest Debug APK built and covered-installed to 192.168.50.3:5561; removed smooth scrolling and repeated delayed focus callbacks, now stopping scroll and using one post-on-animation focus after direct layout-manager positioning to eliminate focus flicker; current interface remains focusable but cannot be reused; git diff --check passed; task_guard check passed

Task-Guard: leanback-interface-focus-no-flash
2026-09-22 13:56:15 +08:00
Silent1566
da20a189f6 fix(tmdb): remove invalid routes and split api image
Verification: 真实线路探测:itv666 API /3/configuration 返回 200 有效 JSON、/t/p/w342 图片返回 200 image/png;Worker 池各地址 TLS connect EOF,NAStool API 返回 HTML且图片404,已移除;布局检查通过(ScrollView单子节点,apiHostInput/imageHostInput各一次);聚焦 Mobile ARM64 Debug 单测全部通过;Debug APK 构建成功并使用 adb install -r 覆盖安装到 192.168.50.3:5557,运行时确认 API/图片双线路下拉控件

Task-Guard: tmdb-route-validity-split
2026-09-22 13:37:27 +08:00
Silent1566
eaf7f3bf1f i18n(theme): localize theme editor strings
Verification: zh-rCN/zh-rTW theme_editor_* key coverage complete (46/46 each); XML parse OK; :app:compileMobileArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL; scripts/build_arm64_debug_install.sh --serial 192.168.50.3:5559 build+overwrite install Success; device zh-CN verified 外观与语言 and 主题色彩 dialog/editor show Chinese labels, presets and slot names; FATAL EXCEPTION=0

Task-Guard: THEME-EDITOR-I18N-20260922
2026-09-22 13:34:59 +08:00
Silent1566
29b2f0fd2b fix: align TV dialog sizing and focus
Verification: InterfaceEntryInteractionTest passed with 8 tests, 0 failures, and 0 errors; ConfigHistoryCurrentSourceGuardTest passed with 2 tests; leanback arm64-v8a debug Java compilation passed; latest Debug APK built and covered-installed to 192.168.50.3:5561; ConfigDialog now uses the LightDialog full-size overload so its on-show sizing is not overwritten by the compact default; dialog margins are 24dp (48dp total); DPAD row focus gets delayed retries after scroll; git diff --check passed; task_guard check passed

Task-Guard: leanback-interface-current-focus-and-config-fill
2026-09-22 13:28:18 +08:00
Silent1566
c808cfecd6
Merge pull request #345 from Silent1566/dev5
合并 beta 并同步手机版触屏设置测试
2026-09-22 12:58:56 +08:00
Silent1566
2985605626 refactor(tmdb): unify route selector input
Verification: 布局结构检查通过:ScrollView 仅一个直接子节点、仅保留 apiHostInput;聚焦 Mobile ARM64 Debug 单测通过(TmdbProxyTest、TmdbConfigImageHostTest、TmdbConfigEffectiveTest、TmdbConfigTestServiceTest、TmdbSourceDialogInflationContractTest);:app:processMobileArm64_v8aDebugResources/Java 编译通过;scripts/build_arm64_debug_install.sh 覆盖安装到 192.168.50.3:5557,运行时 UI dump 确认默认 https://api.tmdb.org、单一线路输入框,并实际打开下拉检查内置线路

Task-Guard: tmdb-unified-route
2026-09-22 12:27:22 +08:00
Silent1566
c6002dca3b fix: keep current interface focusable on TV
Verification: InterfaceEntryInteractionTest passed with 8 tests, 0 failures, and 0 errors; ConfigHistoryCurrentSourceGuardTest passed with 2 tests; leanback arm64-v8a debug Java compilation passed; Debug APK built and covered-installed to 192.168.50.3:5561; ConfigDialog content hierarchy now expands to the full screen-sized window; current interface row remains focusable while click reuse and delete protection remain; git diff --check passed; task_guard check passed

Task-Guard: leanback-interface-current-focus-and-config-fill
2026-09-22 12:19:01 +08:00
Silent1566
fd9cccfa03 docs(theme): record residual device matrix evidence
Verification: dev3 mobile: invalid hex #GGGGGG rejected with Enter #RRGGBB and no profile write; TAB/DPAD focus traversed 16 settings rows without crash; FATAL=0; theme remains reset to default

Task-Guard: L2-MATRIX-RESIDUAL-20260922
2026-09-22 12:15:36 +08:00
Silent1566
0d105eedd8 fix(theme): restore home navigation and theme editor entry
Verification: mobile arm64 debug build + overwrite install Success on 192.168.50.3:5559; cold start nav_position=1 opens native settings -> appearance -> theme editor; Blue preset, light #FF0000 apply/cancel/restart, dialog opacity 1.0, dark #00FF00 restart persistence verified; reset to default; FATAL=0

Task-Guard: NAV-THEME-ENTRY-20260922
2026-09-22 12:10:49 +08:00
Silent1566
838167adde feat(tmdb): add built-in proxy route selector
Verification: Layout XML/ScrollView structural check passed; focused Mobile ARM64 Debug unit tests passed (TmdbProxyTest, TmdbConfigImageHostTest, TmdbConfigEffectiveTest, TmdbConfigTestServiceTest, TmdbSourceDialogInflationContractTest); :app:processMobileArm64_v8aDebugResources passed; scripts/build_arm64_debug_install.sh mobile arm64-v8a installed over existing package on 192.168.50.3:5557 and runtime UI dump confirmed proxy selector/label without overlap

Task-Guard: tmdb-proxy-selector
2026-09-22 12:09:54 +08:00
Silent1566
6a01d426d8 修复手机版触屏优化移除后的测试断言
Verification: 聚焦 :app:testMobileArm64_v8aDebugUnitTest 通过 PushParserTest 与 TouchOptimizationHelperSourceTest;git diff --check 通过;第二轮改动复评通过

Task-Guard: dev5-beta-merge-review-20260922
2026-09-22 12:09:00 +08:00
Silent1566
be7dad1b7d Merge remote-tracking branch 'origin/beta' into dev5 2026-09-22 11:34:54 +08:00
Silent1566
1b42d66244 移除手机版个性设置中的触屏优化入口
Verification: :app:compileMobileArm64_v8aDebugJavaWithJavac BUILD SUCCESSFUL; mobile sources contain no touchOptimization references; leanback entry/runtime retained

Task-Guard: remove-mobile-touch-optimization
2026-09-22 11:06:40 +08:00
Silent1566
ca0e3dc2aa fix(tmdb): keep proxy input inside scroll content
Verification: layout structure passed: ScrollView has exactly one direct child and proxyHostInput is present once; git diff --check passed; :app:processMobileArm64_v8aDebugResources passed with BUILD SUCCESSFUL

Task-Guard: tmdb-proxy-layout-crash
2026-09-22 09:44:07 +08:00
Silent1566
f6f90ba7ba feat(theme): extend web token snapshot with opacity fields
Verification: mobile/leanback theme+备份定向单测全部通过(含新增 ThemeWebBridgeTokenTest 5项:原13字段保留、focusScale格式不变、三个透明度字段两位小数格式稳定、取值与ThemeTokens一致、不泄漏profile/seed、null回退light);scripts/check_ui_tokens.sh --strict violations=0 legacy=0、38组对比度0失败;snapshotJson仅追加字段不改key名,HomeWebController仍为只读通道。未完成:Layer2设备功能矩阵因dev3首页被内置WebHome接管、原生外观入口自动化不可达,已在文档记录

Task-Guard: L2D-THEME-CLOSURE-20260922
2026-09-22 03:24:56 +08:00
Silent1566
89b3095f76 feat(theme): add layer 2C profile editor with live preview
Verification: mobile/leanback theme 定向单测全部通过(含新增 ThemeEditorContractTest 11项:逐槽往返/透明度边界/非法值拒绝/浅深独立/预览不落盘/旧14色路径移除);:app:compileMobileArm64_v8aDebugJavaWithJavac 与 :app:compileLeanbackArm64_v8aDebugJavaWithJavac 通过;scripts/check_ui_tokens.sh --strict violations=0 legacy=0、38组对比度0失败;编辑器经 ThemeProfileStore.apply 原子写入,取消不改动持久化。未完成:dev3真机编辑器交互验收因首页被内置WebHome接管、原生外观入口自动化不可达,已在文档记录为残余风险

Task-Guard: L2C-THEME-EDITOR-20260921
2026-09-22 03:16:22 +08:00
Silent1566
f50897455c fix: expand TV interface dialogs
Verification: InterfaceEntryInteractionTest passed with 7 tests, 0 failures, and 0 errors; leanback arm64-v8a debug Java compilation passed; TV interface list and edit dialogs now use screen-sized windows with 32dp margins on every edge, transparent window backgrounds, and zero decor padding; git diff --check passed; task_guard check passed

Task-Guard: leanback-interface-dialog-fullscreen-margins
2026-09-22 01:52:57 +08:00
Silent1566
f128caa286 feat(tmdb): add configurable proxy base
Verification: git diff --check passed; XML parse passed; :app:testMobileArm64_v8aDebugUnitTest focused TMDB tests passed with BUILD SUCCESSFUL

Task-Guard: tmdb-proxy
2026-09-22 01:31:23 +08:00
Silent1566
fb4fd00438 fix: improve TV interface dialog focus navigation
Verification: InterfaceEntryInteractionTest passed with 7 tests, 0 failures, and 0 errors; leanback arm64-v8a debug Java compilation passed; BUILD SUCCESSFUL in 32s with 98 actionable tasks; TV interface dialog now focuses the editable name field initially and provides an explicit D-pad focus chain through URL, backup addresses, file actions, confirm, and cancel; git diff --check passed; task_guard check passed

Task-Guard: leanback-interface-dialog-focus-chain
2026-09-22 01:14:10 +08:00
Silent1566
673bc67ec5 fix: use existing TV interface name hint
Verification: leanback arm64-v8a debug Java compilation passed after correcting the interface-name hint resource and cleaning regenerable build caches; git diff --check passed; task_guard check passed

Task-Guard: leanback-interface-name-hint-fix
2026-09-21 23:56:29 +08:00
Silent1566
5f043081ca fix: adapt TV interface dialogs
Verification: InterfaceEntryInteractionTest passed with 7 tests, 0 failures, and 0 errors; leanback arm64-v8a debug Java compilation passed; BUILD SUCCESSFUL in 45s with 98 actionable tasks; TV interface list and edit dialogs now adapt to screen width and height; the list exposes the add button; the edit dialog supports modifying and saving the interface name; git diff --check passed; task_guard check passed

Task-Guard: leanback-interface-dialog-adaptive-layout
2026-09-21 23:35:57 +08:00
Silent1566
0ec701f31b feat(theme): apply B-safe layer 2B profile through controlled binder
Verification: mobile/leanback theme 定向单测全部通过;scripts/check_ui_tokens.sh --strict violations=0 legacy=0、38组对比度0失败;dev3 192.168.50.3:5559 API28 mobile 覆盖安装:默认路径无binder活动且FATAL=0,注入13槽profile后bound=10 costMs=6-7ms,列表滚动/对话框/返回正常FATAL=0;修复API28上Class.getRecordComponents NoSuchMethodError与ColorStateList.createFromXml ClassCastException两个设备专属缺陷,改用内容哈希签名与公开ColorStateList构造器

Task-Guard: L2B-THEME-BINDER-20260921
2026-09-21 23:31:35 +08:00
Silent1566
65b27e395f fix: persist history line binding immediately
Verification: VideoActivityLayoutTest passed; mobile and leanback arm64-v8a debug Java compilation passed; BUILD SUCCESSFUL in 58s with 98 actionable tasks; both players now persist sourceBindingKey immediately through syncHistory after selecting a playback line; git diff --check passed; task_guard check passed

Task-Guard: history-flag-binding-save
2026-09-21 22:28:34 +08:00
Silent1566
6435115120 feat(theme): add B-safe layer 2A profile and resolver
Verification: mobile/leanback theme+backup 定向单测各69项0失败0错误(含新增 ThemeProfileCodecTest/ValidatorTest/MigrationTest/ThemeResolverOverrideTest);scripts/check_ui_tokens.sh --strict violations=0 legacy=0、38组对比度0失败min=4.28、hex计数全0;空profile解析与不传profile逐字段相同,播放器/健康/品牌token在所有覆盖测试中与默认一致;未修改ThemeController与任何布局资源,运行时视觉保持Layer 1

Task-Guard: L2A-THEME-PROFILE-20260921
2026-09-21 21:33:39 +08:00
Silent1566
5bdd9372e3 fix: persist history interface binding
Verification: StableInterfaceIdentityAcceptanceTest, PlaybackProgressWriterEpisodeTest, and HistoryResumePayloadTest passed; mobile and leanback arm64-v8a debug Java compilation passed; BUILD SUCCESSFUL in 1m 39s with 98 actionable tasks; History.sourceBindingKey is persisted through Room migration 46 to 47; generated Room schema 47 is included; git diff --check passed; task_guard check passed

Task-Guard: history-source-binding-persistence
2026-09-21 21:23:16 +08:00
Silent1566
04e996e50c fix: explain protected current interface deletion
Verification: InterfaceEntryInteractionTest and ConfigHistoryCurrentSourceGuardTest passed with 0 failures; mobile and leanback arm64-v8a debug Java compilation passed; mobile arm64-v8a Debug APK built successfully and installed with overlay installation on 192.168.50.3:5561; clean relaunch verified app remains responsive; runtime UI verified current source 嗷呜 remains visible, its use action is disabled, edit remains available, delete remains visible with protected-current feedback behavior, and add remains available; git diff --check passed; task_guard check passed

Task-Guard: interface-current-delete-feedback
2026-09-21 20:33:15 +08:00
Silent1566
44ac882d6a fix: protect current interface actions
Verification: InterfaceEntryInteractionTest and ConfigHistoryCurrentSourceGuardTest passed; mobile and leanback arm64-v8a debug Java compilation passed; mobile arm64-v8a Debug APK built and installed with adb install -r on 192.168.50.3:5561; runtime UI verified current source 嗷呜 remains visible with disabled use text and hidden delete action while edit remains available; git diff --check; task_guard check

Task-Guard: interface-current-source-actions
2026-09-21 18:51:59 +08:00
Silent1566
73b046cc07 fix: persist backup addresses for new interfaces
Verification: InterfaceEntryInteractionTest passed; mobile and leanback arm64-v8a debug Java compilation passed; mobile arm64-v8a Debug APK built and installed with adb install -r on 192.168.50.3:5561; new interface test autobackup persisted urlsJson=["http://primary.test.invalid","backup.test.invalid"] and reopened with backup address visible; temporary test configs removed; git diff --check; task_guard check

Task-Guard: interface-new-backup-persistence
2026-09-21 18:28:55 +08:00
Silent1566
0c926dba8d fix(following): align panel scrim with home buttons per mode
Verification: check_ui_tokens.sh --strict violations=0 legacy=0、38组对比度0失败、hex计数全0;FollowingUiSourceTest新增模式极性契约后mobile/leanback定向单测通过;dev3 192.168.50.3:5559两端覆盖安装FATAL EXCEPTION=0;TV深色顶栏(76,73,89)/卡片(71,70,84)对onSurface为6.77:1/7.17:1且与首页按钮20%黑纱同源,手机浅色正文8.52:1、次要文字4.63:1(修复前1.95:1/1.06:1)

Task-Guard: FOLLOWING-SCRIM-ALIGN-20260921
2026-09-21 18:27:51 +08:00
Silent1566
0b1af5033f fix(following): use global wallpaper with translucent panels
Verification: check_ui_tokens.sh --strict violations=0 legacy=0、38组对比度0失败、hex计数全0(drawables=550 colors=53);FollowingUiSourceTest新增壁纸契约+ThemeControllerContractTest旧断言更新后,mobile/leanback定向单测均通过;mobile与leanback arm64 debug覆盖安装dev3 192.168.50.3:5559成功且FATAL EXCEPTION=0;mobile追更页面板外像素(88,78,113)壁纸透出、面板内(208,207,217),leanback深色半透明面板正常、空态图标可见;TV临时勾选首页追更按钮验收后已恢复7/10

Task-Guard: FOLLOWING-WALLPAPER-20260921
2026-09-21 17:47:49 +08:00
Silent1566
46d3e74898 feat: separate interface list add and edit actions
Verification: InterfaceEntryInteractionTest passed; mobile and leanback arm64-v8a debug Java compilation passed; mobile arm64-v8a Debug APK built successfully; APK installed with adb install -r on 192.168.50.3:5561; runtime UI verified that the VOD interface manager lists all configs and exposes explicit edit, delete, and add actions; git diff --check passed; task_guard check passed

Task-Guard: interface-config-list-interaction
2026-09-21 16:15:18 +08:00
Silent1566
6cdc7dd362 feat(theme): integrate webhtv semantic theme into flavor bases
Verification: check_ui_tokens.sh --strict violations=0 legacy=0、38组对比度0失败(min=4.28)、hex计数全0;mobile全量单测705套件/4790项0失败,leanback全量单测614套件/3917项0失败;新增ThemeBaseWiringTest 5项、ThemeControllerContractTest增补2项契约;mobile与leanback arm64 debug均覆盖安装到dev3 192.168.50.3:5559并冷启动,API28 FATAL EXCEPTION=0,mobile主色实测token蓝#0B57D0、leanback #A8C7FA;一并修复3f3ab82b1f遗漏的colorOnSurface_20/70/80/90导致leanback资源链接失败;git diff --check通过

Task-Guard: L1-THEME-INTEGRATE-20260921
2026-09-21 15:48:40 +08:00
Silent1566
30ba0f48f9 feat(theme): unify remaining modules and add theme mode
Verification: strict检查violations=0 legacy=0且hex计数全0、38组对比度通过;ThemeControllerContractTest/ThemeResolverTest/ThemeContractTest/UiStyleSourceTest/UiLayoutSourceTest/WebThemeTokenSourceTest/NativeBridgeGuardTest/JarLoader*/setting.*全部通过;mobile/leanback arm64 debug编译通过;dev3 192.168.50.3:5559上同一接口连续重载3次进程保持前台FATAL EXCEPTION=0;外观与语言显示5项且主题模式可切浅色/深色并即时生效;AudioMiniPlayer主题切换NPE已修复;git diff --check通过。

Task-Guard: UI-UNIFY-REMAINING-MODULES-20260921
2026-09-21 13:46:41 +08:00
Silent1566
327ac86f86 fix: retain saved backup addresses for dialog reopen
Verification: ConfigDialogNamePersistenceTest passed; mobile and leanback arm64 debug Java compilation passed; BUILD SUCCESSFUL in 33s, 98 actionable tasks; git diff --check; task_guard check

Task-Guard: interface-address-reopen-prefill
2026-09-21 13:16:14 +08:00
Silent1566
daac96ebb8 fix(loader): retain translated dex loaders to avoid houdini crash
Verification: NativeBridgeGuardTest与既有JarLoaderTest/LoaderQueueTest通过;assembleMobileArm64_v8aDebug通过;dev3 192.168.50.3:5559覆盖安装后同一接口连续重载3轮进程保持前台、FATAL EXCEPTION=0、日志出现retained translated loaders;git diff --check通过。

Task-Guard: FIX-VOD-RELOAD-HOUDINI-20260921
2026-09-21 12:18:16 +08:00
Silent1566
a8e6949e9c fix: localize interface backup address hint
Verification: 简体中文和繁体中文均已补充 dialog_config_addresses;mobile/leanback arm64 debug 资源处理成功;BUILD SUCCESSFUL in 27s;git diff --check;task_guard check

Task-Guard: interface-address-localization
2026-09-21 12:03:21 +08:00
Silent1566
6064be078b test: cover stable interface identity acceptance
Verification: StableInterfaceIdentityAcceptanceTest passed for mobile and leanback arm64 debug variants; BUILD SUCCESSFUL in 42s, 114 actionable tasks; git diff --check; task_guard check

Task-Guard: interface-stable-identity-acceptance-tests
2026-09-21 11:29:11 +08:00
Silent1566
4d211e6188 feat: add interface backup address editor
Verification: ConfigDialogNamePersistenceTest passed; mobile and leanback arm64 debug Java compilation passed; BUILD SUCCESSFUL in 58s, 98 actionable tasks; git diff --check; task_guard check

Task-Guard: interface-stable-address-ui
2026-09-21 11:13:42 +08:00
Silent1566
b60203504a test(ui): align detail photo radius contract
Verification: TmdbDetailActivityLayoutTest更新cardCornerRadius断言为@dimen/webhtv_card_radius_default后单测通过;git diff --check通过;未修改生产行为,仅同步source contract与文档。

Task-Guard: VISUAL-TEST-ALIGN-20260921
2026-09-21 10:53:22 +08:00
Silent1566
fceef8bed9 test(ui): freeze card geometry and surface variant contracts
Verification: strict检查 violations=0 legacy=0 hex_layouts=0 hex_drawables=0 hex_colors=0 allowlisted=191,38组对比度通过;新增UiLayoutSourceTest并通过,连同UiStyleSourceTest/WebThemeTokenSourceTest/Theme*全部通过;mobile/leanback arm64 debug Java编译通过;dev3模拟器覆盖安装启动HomeActivityCurrent,FATAL EXCEPTION=0;git diff --check通过。

Task-Guard: VISUAL-LAYOUT-CONTRACT-20260921
2026-09-21 10:46:29 +08:00
Silent1566
bc2ce54d2f fix: preserve config identity during backup restore
Verification: git diff --check; task_guard check; mobile and leanback arm64 debug Java compilation => BUILD SUCCESSFUL in 39s, 58 actionable tasks

Task-Guard: interface-stable-identity-completion
2026-09-21 10:28:25 +08:00
Silent1566
dba04ebc01 fix(ui): reconcile semantic token tests and visual regressions
Verification: 严格检查 check_ui_tokens --strict:violations=0 legacy=0 hex_layouts=0 hex_drawables=0 hex_colors=0 allowlisted=191,对比度38组通过;10个失败测试用例全部修复,覆盖DialogGlassChip/TMDB详情/历史与VOD adapter/AdRule/GroupRule/MultiThreadProxy/TmdbSource/GlobalHistory/SiteHealth;mobile/leanback arm64 debug编译通过;dev3模拟器覆盖安装启动HomeActivityCurrent,FATAL EXCEPTION=0;git diff --check通过。

Task-Guard: VISUAL-FOLLOWUP-20260921
2026-09-21 10:12:22 +08:00
Silent1566
3f3ab82b1f chore(ui): finalize token cleanup and legacy asset allowlist
Verification: check_ui_tokens.sh --strict返回violations=0 legacy=0,hex_layouts/hex_drawables/hex_colors均为0,allowlisted=191且对比度38组全通过;UiStyleSourceTest、WebThemeTokenSourceTest、ThemeResolverTest、ThemeContractTest通过;mobile/leanback arm64 debug Java编译通过;dev3模拟器覆盖安装后HomeActivityCurrent启动,FATAL EXCEPTION=0;git diff --check通过。

Task-Guard: VISUAL-SYSTEM-F-20260921
2026-09-21 09:57:26 +08:00
Silent1566
eb76ab8a82 feat: add stable interface identity and failover addresses
Verification: git diff --check; task_guard check; ./gradlew --no-daemon :app:compileMobileArm64_v8aDebugJavaWithJavac :app:compileLeanbackArm64_v8aDebugJavaWithJavac :app:testMobileArm64_v8aDebugUnitTest :app:testLeanbackArm64_v8aDebugUnitTest --stacktrace => BUILD SUCCESSFUL in 1m 34s, 114 actionable tasks

Task-Guard: interface-stable-identity
2026-09-21 09:55:39 +08:00
Silent1566
810fd5ef7a feat(web): unify built-in web theme tokens
Verification: check_ui_tokens.sh --stage E真实扫描assets后返回violations=0 legacy=0 allowlisted=2;新增WebThemeTokenSourceTest连同WebTheme*/Theme*测试通过;mobile/leanback arm64 debug Java编译通过;dev3模拟器覆盖安装后HomeActivityCurrent启动,FATAL EXCEPTION=0;git diff --check通过。

Task-Guard: VISUAL-SYSTEM-E-20260921
2026-09-21 09:50:58 +08:00
Silent1566
e1ea7ab346 feat(ui): unify detail and player control tokens
Verification: check_ui_tokens.sh --stage D返回violations=0 legacy=0;UiStyleSourceTest含播放器色隔离断言、ThemeResolverTest、ThemeContractTest共16项通过;mobile/leanback arm64 debug Java编译通过;dev3模拟器进入TMDB详情并播放第一集,VideoActivity OSD正常、FATAL EXCEPTION=0;git diff --check通过。

Task-Guard: VISUAL-SYSTEM-D-FULL-20260921
2026-09-21 09:13:19 +08:00
Silent1566
f63b0a81bc feat(ui): unify home list and card tokens
Verification: check_ui_tokens.sh --stage C返回violations=0 legacy=0;ThemeResolverTest、ThemeContractTest、UiStyleSourceTest通过;mobile/leanback arm64 debug Java编译通过;dev3模拟器覆盖安装后列表/卡片与去广告规则管理Dialog正常,FATAL EXCEPTION=0;git diff --check通过。

Task-Guard: VISUAL-SYSTEM-C-20260921
2026-09-21 00:57:05 +08:00
Silent1566
0af2340d49 feat(ui): unify dialog and settings visual system
Verification: ThemeResolverTest、ThemeContractTest、DialogRoundedCornerSourceTest、UiStyleSourceTest全部通过;mobile/leanback arm64 debug Java编译通过;check_ui_tokens.sh --stage B返回violations=0 legacy=0;dev3模拟器192.168.50.3:5559完成手机浅色/深色Dialog实机进入测试,FATAL EXCEPTION=0;git diff --check通过。

Task-Guard: VISUAL-SYSTEM-B-FULL-20260921
2026-09-21 00:41:53 +08:00
Silent1566
c5593731c1 docs: assess stable interface identity design
Verification: 文档共351行;git diff --check通过;章节结构和最终建议已核验;task_guard check通过

Task-Guard: INTERFACE-IDENTITY-1
2026-09-20 23:45:01 +08:00
Silent1566
72c1bec917 feat(ui): add unified semantic token foundation
Verification: ThemeResolverTest、ThemeContractTest、UiStyleSourceTest 共13项通过;mobile/leanback arm64 debug Java编译通过;check_ui_tokens.sh --baseline 38组对比度全通过,最低4.28:1;git diff --check通过;未改既有页面资源。

Task-Guard: VISUAL-SYSTEM-A-20260920
2026-09-20 23:29:16 +08:00
Silent1566
1edbc9b9c9 Merge latest origin/beta into dev1
Verification: :app:testMobileArm64_v8aDebugUnitTest --offline --tests com.fongmi.android.tv.ui.activity.TmdbDetailActivityLayoutTest --no-daemon --max-workers=1 --console=plain (BUILD SUCCESSFUL in 38s)

Task-Guard: beta-sync-review-dev1-20260917
2026-09-17 19:26:33 +08:00
Silent1566
adaff1abee Merge origin/beta into dev1
Verification: :app:testMobileArm64_v8aDebugUnitTest --offline --rerun-tasks --tests com.fongmi.android.tv.ui.detail.* --tests com.fongmi.android.tv.ui.activity.TmdbDetailActivityLayoutTest --tests com.fongmi.android.tv.ui.activity.VideoActivityHistoryTitleTest --no-daemon --max-workers=1 --console=plain (BUILD SUCCESSFUL in 1m 14s)

Task-Guard: beta-sync-review-dev1-20260917
2026-09-17 19:12:55 +08:00
Silent1566
24f97cbaa1 fix(detail): initialize mode controller before view setup
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.detail.* --no-daemon --max-workers=1 --console=plain (BUILD SUCCESSFUL in 42s)

Task-Guard: tmdb-detail-controller-init-order-null
2026-09-17 16:32:24 +08:00
Silent1566
9f51d9ab9c fix(detail): guard early lifecycle theme mode
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.theme.ThemeControllerSourceTest --no-daemon --max-workers=1 --console=plain (BUILD SUCCESSFUL in 35s)

Task-Guard: tmdb-detail-controller-early-lifecycle-null
2026-09-17 16:14:52 +08:00
Silent1566
02f6377afc test(detail): update controller regression assertions
Verification: :app:testMobileArm64_v8aDebugUnitTest --no-daemon --max-workers=1 --console=plain (BUILD SUCCESSFUL in 1m 16s; 4425 tests, 1 skipped)

Task-Guard: tmdb-detail-controller-regression-tests
2026-09-17 15:29:04 +08:00
Silent1566
ba91aca4d8 refactor(detail): centralize TMDB mode decisions
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.detail.* --no-daemon --max-workers=1 --console=plain (BUILD SUCCESSFUL in 49s)

Task-Guard: tmdb-detail-mode-controller-phase4
2026-09-17 15:15:59 +08:00
Silent1566
48942fb4d0 test(detail): cover TMDB mode controllers
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.detail.* (BUILD SUCCESSFUL)

Task-Guard: tmdb-detail-mode-controller-tests
2026-09-17 14:43:59 +08:00
Silent1566
37eab07288 fix(player): preserve video-owned colors
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.theme.ThemeControllerSourceTest --no-daemon --max-workers=1 (BUILD SUCCESSFUL in 39s)

Task-Guard: preserve-video-player-theme
2026-09-17 13:51:39 +08:00
Silent1566
85af02f1fc fix(theme): scope custom highlight colors
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.theme.ThemeControllerSourceTest --no-daemon --max-workers=1 (BUILD SUCCESSFUL in 47s)

Task-Guard: theme-highlight-scope
2026-09-17 13:28:31 +08:00
Silent1566
6504b98729 fix(player): use black shutter across mobile layouts 2026-09-16 19:12:43 +08:00
Silent1566
934c9669cf fix(player): use black shutter for tmdb inline playback
Verification: ./gradlew :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.theme.ThemeControllerSourceTest --no-daemon (BUILD SUCCESSFUL in 36s); git diff --check; task_guard check PASS

Task-Guard: fix-tmdb-player-white-shutter
2026-09-16 14:31:23 +08:00
Silent1566
86b46e5117 fix(theme): preserve colorful detail theme state
Verification: ./gradlew :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.theme.ThemeControllerSourceTest --no-daemon (BUILD SUCCESSFUL); git diff --cached --check

Task-Guard: theme-highlight-player-overlay-scope
2026-09-16 13:24:16 +08:00
Silent1566
bd280278d8 Merge remote-tracking branch 'origin/beta' into dev1 2026-09-16 00:05:08 +08:00
Silent1566
297ece432a fix(theme): preserve navigation default unchecked style
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.theme.ThemeControllerSourceTest (BUILD SUCCESSFUL, 8 tests, 0 failures)

Task-Guard: nav-highlight-default-style
2026-09-15 23:49:08 +08:00
Silent1566
fe6d302918 fix(theme): restore default preset to reset semantics
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.theme.ThemeResolverTest (BUILD SUCCESSFUL, 5 tests, 0 failures)

Task-Guard: theme-default-preset-reset
2026-09-15 23:20:13 +08:00
Silent1566
76882b51d0 test(theme): align episode highlight contract
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.ui.activity.VideoActivityLayoutTest(153 个测试,0 failures,0 errors,BUILD SUCCESSFUL);git diff --check 通过

Task-Guard: beta-sync-review-20260915
2026-09-15 20:27:48 +08:00
Silent1566
33b3dc1cbf Merge remote-tracking branch 'origin/beta' into dev1
# Conflicts:
#	app/src/mobile/java/com/fongmi/android/tv/ui/dialog/SiteDialog.java
#	app/src/testMobile/java/com/fongmi/android/tv/ui/dialog/SiteDialogThemeSourceTest.java
2026-09-15 19:48:40 +08:00
Silent1566
7e4e4f887b fix(theme): limit highlight selection to primary role
Verification: :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.theme.ThemeResolverTest (BUILD SUCCESSFUL); git diff --check; task_guard check PASS

Task-Guard: theme-highlight-scope-consistency
2026-09-15 19:28:42 +08:00
Silent1566
b7a93d3094 fix(theme): guarantee bottom navigation contrast
Verification: ThemeControllerSourceTest BUILD SUCCESSFUL; assembleMobileArm64_v8aDebug BUILD SUCCESSFUL; APK installed on 192.168.50.3:5555; screenshot verified clearer unchecked navigation icons

Task-Guard: theme-bottom-nav-contrast-followup
2026-09-15 16:09:34 +08:00
Silent1566
8a6b331f5f fix(theme): improve bottom navigation contrast
Verification: bash ./gradlew :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.theme.ThemeControllerSourceTest passed; git diff --check passed

Task-Guard: theme-bottom-nav-contrast
2026-09-15 13:40:25 +08:00
Silent1566
353d187825 fix(theme): limit accent fill to primary buttons
Verification: bash ./gradlew :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.theme.ThemeControllerSourceTest passed; git diff --check passed

Task-Guard: theme-button-accent-contrast
2026-09-15 13:33:07 +08:00
Silent1566
a158c8c732 fix(theme): keep reset theme switch enabled
Verification: bash ./gradlew :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.theme.ThemeControllerSourceTest passed; git diff --check passed

Task-Guard: theme-reset-native-default
2026-09-15 12:48:02 +08:00
Silent1566
c872cee68c fix(theme): reset colors and add picker presets
Verification: bash ./gradlew :app:testMobileArm64_v8aDebugUnitTest --tests com.fongmi.android.tv.theme.ThemeControllerSourceTest passed; git diff --check passed

Task-Guard: theme-editor-reset-color-picker
2026-09-15 12:36:17 +08:00
Silent1566
a27f164aa3 fix(theme): expose master switch in mobile editor
Verification: ThemeControllerSourceTest passed; mobile Java/resource compilation passed; Gradle daemons stopped; available memory 3.5 GiB

Task-Guard: theme-color-switch-ui-20260915
2026-09-15 11:49:38 +08:00
Silent1566
3c3885256a fix(theme): fall back to current theme when master switch is off
Verification: ./gradlew :app:testMobileArm64_v8aDebugUnitTest --tests 'com.fongmi.android.tv.ui.dialog.SiteDialogThemeSourceTest' --no-daemon --console=plain; ./gradlew :app:compileMobileArm64_v8aDebugJavaWithJavac --no-daemon --console=plain

Task-Guard: site-dialog-off-fallback-20260915
2026-09-15 11:09:35 +08:00
Silent1566
8523d049e2 feat(theme): add master switch for theme colors, default off
Verification: ./gradlew :app:testMobileArm64_v8aDebugUnitTest --tests 'com.fongmi.android.tv.theme.*' --no-daemon --console=plain

Task-Guard: theme-color-switch-off-20260914
2026-09-15 00:10:43 +08:00
Silent1566
0503f8e3cf feat(theme): restore dynamic theme color system from validated history
Verification: Mobile/Leanback Arm64 Java compilation passed; Mobile theme-related JVM tests passed (13 classes, 59 tests, 0 failures); Leanback theme-related JVM tests passed (4 classes, 13 tests, 0 failures); git diff --check and task_guard check passed

Task-Guard: theme-revival-20260914
2026-09-14 21:44:22 +08:00
1210 changed files with 75995 additions and 29505 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5 KiB

Some files were not shown because too many files have changed in this diff Show more