Files
MAG160C/docs/android_app/session_state.md
T

209 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MAG160C 安卓统一 APP — 会话状态与心跳锚点
> 本文件是本任务("整合 4 个官方 APP 重写为 Android 16 现代化 APP")的心跳锚点。
> 每完成一个里程碑更新勾选;会话中断先读本文件 + `reverse_apk_features.md`
> 再按"下一步"继续。约定:不弹询问窗,按计划自主推进,重大分歧点才停下来问。
## 任务目标
1. 逆向 C:\Project\MAG160C\app 4 个官方 APP(普通版/专业版/ThermoScope/demo)→ 已完成
2. 整合全部功能开发一款安卓 APP:适配 Android 16API 36)、现代 UI、横竖屏、
无流氓文件夹、干爽简洁 → **进行中**
3. 背景问题:专业版在用户 Android 16 手机上花屏(根因见 reverse_apk_features.md §6
## 已完成的里程碑
- [x] 工具链:jadx 1.5.1C:\Tools\jadx)、Ghidra 12.1.2C:\Tools)、IDA MCP 可用
- [x] 4 APK 解包 + jadx 全量反编译(%TEMP%\opencode\apkwork\jadx_*
- [x] 普通版/专业版/ThermoScope/demo 功能清单 → docs/android_app/reverse_apk_features.md
- [x] IDApro libcoresdk.so GetOutputImage/copyBitmap 位图格式证实(ARGB_8888
- [x] Ghidralibcxsdk.so 导出 C++ API 清单(CFunctions 族,与 ARM64 coresdk 同源)
- [x] 花屏根因分析(32 位专属库 + targetSdk25 legacy 渲染栈)
## 关键事实速查(开发时直接用)
- USBVID 0x833C PID 1EP 0x03/0x82/0x81/0x84,帧 28B 头+38400B+尾,15fps
- 协议/渲染/温度算法全部已逆向:analysis/protocol_spec.md + csdk/(逐像素验证过的官方管线)
- csdk 的 mag160c_render 无平台依赖:USB 帧 → 320×240 RGB24 + 探针测温(毫度)
- DDT 标定文件:可从设备经 0x6BB6B66D/E 下载(官方 prepareProcessImage 同款),仓库有
build-artifacts/mag160c_official.ddt1.8MBSN 160043865
- MDT 文件格式:reverse_apk_features.md §4152B Tail + 5 段布局 + ROI 256B 记录)
- 温度:毫度 intMDT 解码走 ConvertResponse2Temperature + T2E(Revise) + CorrectTemperature
## 用户已确认的范围(2026-09-06
- 云功能:预留 Retrofit 接口模块,默认关闭
- 扫码打标 + 任务巡检(sqlite/xml) + 红外基准图叠加:v1 全部实现
- **网络互连(用户新增需求)**:主机手机插 USB 热像仪,局域网内另一台手机
远程实时预览——UDP 广播自动发现 + 手动添加内网 IP;自定义轻量协议
(控制通道 JSON + 图像流),不走厂商 33596/33597 协议
## 当前阶段
**阶段 2/8 完成:纯Kotlin核心管线移植并逐字节验证(2026-09-06**
## 已完成里程碑(本任务)
- [x] 阶段1:轻量工具链定案——NDK/CMake/zig 全部卸载(-2.4GB),纯 Kotlin 方案:
渲染管线+温度算法+帧解析从 C 移植为 KotlinGradle 8.14.3 + SDK 已有组件
- [x] 阶段2:项目骨架(android/AGP 8.11.1 + Kotlin 2.2.0 + Compose BOM
compileSdk/targetSdk 36minSdk 26),最小APK可构建
- [x] 阶段2:表数据自动生成 analysis/gen_kotlin_tables.py → OfficialTables.kt
palette256 ARGB / T2E 646 / T2E274 / E2T_ACC_Q10
- [x] 阶段2:核心移植 FrameStream / RenderPipeline / TempMath(毫度测温)
- [x] 阶段2PC端参考工具 analysis/render_offline.cgcc 编译)+ 差分测试:
**Kotlin 输出与C参考逐字节一致**(60帧序列,首渲染帧32,NUC/LUT/灰度/输出全同)
- [x] 阶段2FrameStream 分块重组测试 + 温度换算单调性测试全过
## 移植陷阱记录(教训)
- C 无符号32位回绕:乘积/减法必须 u32() 掩码(cdf*denom、0xffc0000-iv7*0x40000、
(v-win_lo)*S 等)
- lutRebuild 的 u12 基址是常量 iv7*0x10+0x10**不是**链式 u21vu21v 只用于曲线钳制比较
- Kotlin ByteArray 存 255 = -1lut[bfmax] != 0xFF 判断必须 (b.toInt() and 0xFF)
- 暖机窗口内 FFC 状态机暂停(warm check 在 ffc_step 之前)——移植时保持顺序
## 用户反馈修复(2026-09-07
- [x] **中文乱码根因**:部分源码曾被python以GBK重写(AppRoot.kt),编译出的字符串
mojibake。已写 fix_encoding.py 全量转UTF-8 + kotlin.daemon.jvmargs 锁UTF-8 +
dex字节级验证(classes5/9.dex 中"媒体库"UTF-8正确)
- [x] **权限弹窗**Manifest 加 USB_DEVICE_ATTACHED intent-filter + device_filter
(插热像仪系统自动弹权限/启动);相册页运行时申请 READ_MEDIA_IMAGES
(模拟器实测弹窗正常)
- [x] **图标**:全部重绘为可验证几何图形(双弧圆/直线/矩形),横竖屏截图确认渲染正确
- [x] **专业版三大功能补齐**:多点测温(点击加Pt1..PtN、再点删除)、右侧色标条
(渐变+最高/最低温标注)、最高温追踪开关(追踪·开/关)
- [x] **演示模式**:无设备时用真实管线+DDT渲染合成帧(热块场景),全UI可探索;
demo温度用局部线性显示映射(真机温度走管线数学)
- [x] Android 16.1 模拟器(Medium_Phone AVD)实机验证:中文/图标/布局/横竖屏正常,
预览图在 analysis/preview/preview_*.png
## 用户反馈修复 第二轮(2026-09-07
- [x] 竖屏时热像图旋转90°竖着显示(填满屏宽);横屏时保持传感器原生4:3方向
填满屏高——两个方向下显示区域都最大化(用户要求的官方行为)
- [x] 横屏:控制栏移到屏幕右侧(竖列),竖屏保持底部横排6项等分——切换时
不再跳位
- [x] 追踪/测温点标记改为大号"圆环+实心点"图标,字高随密度缩放(更大)
- [x] 色标条放大(宽20dp、高0.8视口)+更大刻度字号
- [x] ScreenOrientation=fullSensor:跟随传感器旋转(系统旋转锁定时也转,
与官方普通版一致)
- [x] **SurfaceView旋转存活**AppRoot/LiveScreen改为稳定单分支布局(导航/控制
栏做成overlay),SurfaceView不再因横竖屏切换被销毁重建(此前横屏花屏空
白的根因)
- [x] 模拟器实测:竖屏/横屏截图确认全部生效(analysis/preview/
## 用户反馈修复 第三轮(2026-09-07
- [x] **布局重构**:控制项(FFC/变倍/追踪/调色板/拍照/录像/调色板名)移到**顶部横栏**,
横竖屏都显示;底栏导航(实时/相册/分析/设置)保持原位置(竖屏底部栏/横屏左侧栏)
- [x] **图像内容世界固定**:绘制角度 = (90 - 显示器rotation×90) mod 360
四向旋转(竖屏/左横/右横/倒竖屏)图像内容都不随手机转,只转图标文字
(修复"向右横屏图像颠倒"问题)
- [x] **状态栏沉浸**insetsController 隐藏状态栏(下滑临时显示),底栏导航仍可用
- [x] **inset感知渲染**:渲染器 viewport = 全屏减顶栏/底栏insetAppRoot横屏时
导航栏宽度不再误算为底部inset)
- [x] 顶栏通过 onSizeChanged 上报 vm.uiTopPx;导航 overlay 高度经 UiInsets 单例
同步 vm.uiBottomPx
- [x] **(重要教训)python 裸写文件会用 GBK**:所有 python 编辑必须显式
encoding='utf-8';本次 LiveScreen.kt 双重乱码已重写恢复,dex 验证 CJK 正常
- [x] 模拟器验证:顶栏/左导航/图像/色标/标记布局正确,中文正常,状态栏隐藏生效
## 用户反馈修复 第四轮(2026-09-07,最终布局约定)
- [x] **顶栏/底栏位置固定**:顶栏=控制项(FFC/变倍/追踪/调色板/拍照/录像)恒在顶部;
底栏=导航恒在底部。横竖屏都不移动(**取消横屏左栏**),图标文字跟随屏幕方向(恒可读)
- [x] **图像区域永不旋转**:图像恒 90°CW 绘制为 3:4 竖向,填满顶栏~底栏之间可用区,
手机怎么转都不动;只转标记文字(文字恒屏幕水平,位置经 probeToScreen 固定90°映射)
- [x] **顶栏适配挖孔屏**`WindowInsets.safeDrawing.only(Top)` 顶部安全区 padding
- [x] 去掉 display-rotation 依赖(uiRotation/drawRotationDeg 已删,tapImage/probeToScreen
用固定 90° 映射)
- [x] 完整交接文档:docs/android_app/HANDOFF_DEVELOPMENT.md(含给新模型的读取提示词)
## 用户反馈修复 第五轮(2026-09-07,布局约定最终定稿:构图钉死竖屏框架)
- [x] **用户澄清**:"顶栏底栏位置不变"指**绝对位置**——永远贴着手机竖屏的物理顶边
(挖孔侧)与物理底边;热像区域也**完全不动**。不是"横屏后显示区域跟着屏幕转":
那样屏显方向会和镜头实际方向对不上。
- [x] **根因与修复**:此前 fullSensor 下渲染"相对当前屏幕固定 90°CW",手机横过来时
屏幕本身转 90°,整个构图相对手机框架也转 90° → 与镜头方向脱节。修复 =
**Activity 锁定竖屏**manifest `screenOrientation="portrait"`):屏幕相对手机框架
永不旋转,构图(顶栏/热像区/底栏)永远钉在竖屏框架上;手机怎么物理旋转都一样。
- [x] 顺带清理:GalleryScreen 去掉 isLandscape() 死逻辑(恒 3 列);
AppRoot/LiveScreen/LiveRenderer/UiInsets 注释同步更新。
- [x] 模拟器四方向实测(0/90/180/270°,`adb emu rotate`):**四个方向截图逐字节一致**
(MD5 相同)——构图绝对固定;演示画面/顶栏/底栏/色标/标记/中文均正常
analysis/preview/preview_rot*_v5.png)。
- [x] 单元测试全过;APK 已更新 build-artifacts/mag160c-app-debug.apk。
- 注:不要再改回 fullSensor/sensor 横屏;横竖屏适配类需求一律以"竖屏构图恒定"为准。
## 用户反馈修复 第六轮(2026-09-07,横屏持机图标文字可读)
- [x] **用户反馈**:竖屏锁定后,横过来拿手机时顶栏/底栏里的图标和文字不旋转(侧着)。
约定补全:**构图钉死竖屏框架不变**(条栏绝对位置+热像区域不动),但条栏内容
(图标+文字)与 OSD 文字要按**物理持机朝向**补偿旋转,保持可读。
- [x] 新增 `ui/DeviceOrientation.kt`:加速度计→手机相对竖屏的顺时针物理转角
φ∈{0,90,180,270}(主轴判定+2.5m/s² 滞回;竖屏锁定下 Display.rotation 恒 0 不可用)。
- [x] 顶栏 7 控制项/底部导航 4 项:`graphicsLayer rotationZ=-φ` 原位预旋转(布局不动)。
- [x] 渲染器 OSD 文字(中心温/探针标注/色标最高最低数字)`canvas.rotate(-φ)` 绕锚点
旋转;标记圆点、色标条几何仍钉死在图像上。
- [x] 模拟器实测(`adb emu sensor set acceleration` 驱动 4 姿态):四姿态下热像区域
完全一致,图标/文字按姿态正确补偿(analysis/preview/preview_pose*_v6.png);
姿态复位 0° 后输出与第五轮逐字节一致(MD5 相同)。
- [x] 单元测试全过;APK 已更新。
- 注:对话框(调色板等)与其他页签内容未做补偿旋转(保持竖屏可读),如需再加。
## 待办
- 真机USB实测(温度绝对值标定、FFC/录像/MDT保存端到端)
- 网络互连远程预览(用户需求:UDP自动发现+手动IP)
- 离线MDT温度解码(ConvertResponse2Temperature+标定参数,待真机文件对照)
- 厂商12调色板精确提取(需运行时抓取)
- 可见光PIP融合、云模块(预留结构)
## 里程碑日志
- 阶段3b 完成(2026-09-06 晚): 拍照 MDT 容器(jpg+info块+raw帧+备注)存入
MediaStore DCIM/MAG160CMP4 录像 = Surface 编码 H.264 @320×240 15fps 2Mbps
- 阶段4 完成: 媒体库(MediaStore 扫描 + 内嵌 JPEG 缩略图 + MDT 尾部校验)
- 阶段5a 完成: 分析查看器(detectTransformGestures 缩放1-4x/平移、12 调色板
重渲染原始帧、自动窗口、备注编辑回写容器、温度探针近似)
- 阶段5b 完成: PDF 巡检报告(PdfDocument:标题/7×4信息表/热像图/结果/建议/测试员)
- 阶段6a 完成: 设置页(默认调色板/发射率/报警温度/关于,SharedPreferences 私有)
+ 任务巡检解析器 TaskParsersqlite task/region/device/part/phase + XML title/target
## 阶段3a 完成(2026-09-06 晚)
- [x] USB传输层 usb/UsbTransport.ktVID 0x833C 枚举/权限/claim/EP查找)
- [x] 命令协议 usb/MagProtocol.kt4B命令+FFC 8B0x5BB5B55B 信息块解析)
- [x] 直播会话 usb/IrSession.kt66b/66c/66f → FFC(0)x2 → 300ms → START(73)
读线程→FrameStream→RenderPipeline→帧回调;STOP(74);手动FFC
- [x] 官方12调色板 core/Palettes.kt(铁虹=官方提取表,其余为标准曲线近似)
- [x] UI骨架:底部导航4区(实时/相册/分析/设置,横屏自动切侧栏 NavigationRail
- [x] 实时画面 ui/live/SurfaceView+软件Canvas渲染(letterbox+数码变倍+OSD
中心温/最高最低温标记),ViewModel驱动,慢速测温定时器
- [x] DDT标定文件打包进 assets/mag160c.ddt
- [x] 全APK assembleDebug 成功(11.7MB,无material-icons膨胀)
- [ ] 待实机验证USB流(需插设备)
## 开发计划(待确认后逐阶段执行)
- 阶段 1:环境(cmdline-tools/NDK r27+/gradle 8.x + 16KB 对齐配置 + AGP 8.x
- 阶段 2:新仓库 app-androidKotlin + Compose M3 + NDK 移植 csdk 渲染/温度 C 代码 + Kotlin USB 层)
- 阶段 3:实时画面(USB 流+官方管线+OSD+ROI+调色板+FFC+增强+PIP 可见光+拍照 MDT+MP4 录像)
- 阶段 4:媒体库(MediaStoreDCIM/MAG160C,无流氓文件夹)
- 阶段 5:MDT 离线分析(缩放/ROI/参数/PDF 报告/备注)
- 阶段 6:设置/任务巡检/可选云(Retrofit opt-in
- 阶段 7Android 16 专项适配验收(16KB 对齐/横竖屏/深色/预测性返回)
- 阶段 8:打包安装到用户手机实测
## 心跳约定
- 每完成一个阶段:更新本文件勾选 + git commit(不 push)。
- 中断恢复:读本文件 → 按"下一步"继续 → 环境检查命令:
```powershell
Test-Path C:\Users\ZXC\AppData\Local\Android\Sdk\ndk\<ver>
Get-Command java; Get-Command gradle
```