# B-210 Android 通话视觉打回返工

分支：`agent/agent/ede0aecc`（基于 B-204 `agent/agent/3a58b06e` HEAD `714794f`）
施工依据：B-91 视觉规范 v2；打回结论 B-209；姓名字号裁定 18px，32px 仅计时器。
本卡只做打回返工、构建验证和返工证据，不部署、不发布、不换标。

**结论：9 项阻塞 + 建议项已按规范收口；Android debug/release 真实构建通过。缺有效账号和 ARM64 真机，来电/通话页实机渲染、听筒/扬声器、静音、后台/锁屏、铃声震动继续标为未测。**

## 打回项对照

| # | 打回项 | 修改位置 | 结果 |
|---|---|---|---|
| 1 | 计时器 32px 纯白 tabular figures | `AppFont.callTimer`、`Styles.ts_callTimer`、`controls.dart` 通话中状态字 | 已改 |
| 2 | 通话页底 `#1D2129`，不复用 maskBg | `AppColors.callBg`、`Styles.c_callBg`、`call_state.dart` | 已改 |
| 3 | 呼出中仅居中 64 红色取消 | `controls.dart` `_buttonArea`、`LiveButton.cancel` | 已改 |
| 4 | 通话中 48 次按钮 + 居中红色挂断；Token 圆底线性图标 | `live_button.dart`、`controls.dart` | 已改，不再用位图 PNG |
| 5 | 姓名 → 状态 → 96 头像圆角 0.18 | `controls.dart` `_infoColumn` | 姓名 18px，头像 96×0.18 |
| 6 | 结束/失败展示 1.5s 后退出，失败 toast | `call_state.dart` `beginEnding`、`Styles.callEndHold` | 已结束 / 网络异常，通话中断 / 对方已拒绝 |
| 7 | 未接 60s +「未接通话」系统消息；清掉 30s 双来源 | `AppDuration.callInviteTimeout` → `LiveKitCallConfig` / `Styles` / `CallSessionGuard` / 信令 timeout | 超时插入 `CallState.timeout`，文案 `未接通话` |
| 8 | 进出 250ms 自下而上 ease-out，状态不可被重复回调破坏 | `call_page_host.dart`、`live_client.dart` close 防重入、`beginEnding` `_ending/_closed` | 已改 |
| 9 | 来电每 1s 震动，拒绝/接听/退出/销毁停止 | `live_controller.dart` `_startIncomingVibrate` / `_stopSound` | 已改；真机未测 |
| 10 | 状态字 14px 白 60%；文案；静音/免提；最小化点击区 48 | `ts_callStatus`、zh_CN 文案、`LiveButton.mute/handsFree`、最小化 `IconButton` 48 | 已改 |

## 提交主题（可逐项 `git revert`）

从新到旧回退：先本验收记录，再视觉返工。

| 主题 | SHA | 文件 |
|---|---|---|
| 本验收记录 | 本文件当次提交 | `docs/acceptance/b210-android-call-visual-rework.md` |
| 视觉打回返工 | `9bde926` | Token、文案、超时单一来源、通话页布局/按钮/结束态/动效/震动、测试 |

回退示例（新到旧）：

```
git revert <本验收提交>
git revert 9bde926
```

回退不影响 `mobile/`、`account-service/`、`config/`、`scripts/`、现网服务、PC 通话与已发布安装包。B-204 原提交 `3832e080` / `d7f7a6ae` / `714794f7` 仍可按原记录回退。

## 环境

- Flutter 3.24.5 / Dart 3.5.4（`C:\flutter324`）
- Temurin JDK 17.0.20+8
- Android SDK：既有 B-95 工具链（compileSdk 34）
- `org.gradle.jvmargs=-Xmx4096M`

## 检查与构建

### 定点测试

```
cd mobile-next
flutter test test/company/rtc_token_mapper_test.dart test/company/call_session_guard_test.dart test/company/call_visual_rework_test.dart
```

16 项通过：换票映射、占线/去重/超时/销毁、60s 单一来源、callBg≠maskBg、32px tabular figures、14px/18px、250ms/1.5s/48·64·96 尺寸。

定点 `flutter analyze` 修改文件：**0 error**。存量 info/warning 未作为本卡阻塞。

### Android（真实构建）

| 构建 | 结果 | 大小 | SHA256 | 产物 |
|---|---|---|---|---|
| debug | 成功 | 109,424,273 B | `415478F0908BB44449C7DA944F07C5214989888C77B7E13295E4D71082197308` | `mobile-next/build/app/outputs/flutter-apk/app-debug.apk` |
| release | 成功 | 53,289,471 B | `7D81C54D2A03920E0989DDCFD5E29C3433DEB4FDB15266DE2913864D6C4FFD1C` | `mobile-next/build/app/outputs/flutter-apk/app-release.apk` |

构建期告警同 B-204：Flutter Gradle apply-script 弃用；部分依赖 Kotlin metadata 1.8.0 vs 工程预期 1.6.0。均属上游，debug/release 均通过。APK 内嵌时间戳，哈希不可位级复现。

## 越界比对

相对 `714794f`（本卡开工 HEAD）：仅 `mobile-next/` 与本验收文档。

相对 `e26abad`：`mobile/`、`account-service/`、`config/`、`scripts/` **零改动**。本卡工作区 diff 不含 `pc-client/`。

`FeatureFlags.livekitCall` 门控保持：配置不足时入口隐藏。

## 已测 / 未测

已测（替身或构建）：

- Token 映射：callBg `#1D2129`、计时器 32px tabular figures、状态字 14px 白 60%、姓名 18px
- 未接超时 60s 单一来源（配置 / Styles / Guard）
- 占线、重复信令、超时取消、销毁释放计时器
- Android debug/release 可构建

未测（缺外部条件，禁止写成通过）：

- 无有效工号+密码，未登录
- Android ARM64 真机：呼入呼出、听筒/扬声器、静音、后台/锁屏、铃声与每秒震动
- 结束/失败 1.5s 退场与 250ms 滑入滑出的真机观感
- 「未接通话」系统消息在会话里的真机展示

## 风险与回退

- 真机铃声/震动依赖设备振动器与勿扰模式，静态审查不能代替点验
- 结束态 1.5s 内重复回调被 `_ending` 吞掉，属有意防护
- 回退：先 `git revert` 本验收提交，再 `git revert` 视觉返工提交
