Repository navigation
v1.3.2
底层逻辑集中修复:生命周期/状态恢复、保存竞态、缓存交付标记、主线程 Provider 查询、MediaStore/SAF 异常路径、文件名与 Intent 健壮性。全部修复都有对应的 JVM 单测或 API 34 模拟器 instrumentation 覆盖。
Fixed(生命周期与状态)
- H1 深浅色/字体/语言切换后丢状态:Activity 重建时通过
onSaveInstanceState保存并恢复源 URI、MIME、原文件名、缓存会话/当前文件、复制状态、输入框内容、扩展名锁定、已交付路径和 SAF 待保存文件。复制未完成会自动重试;已完成的文件不会重新复制。 - H11 SAF 待保存文件在重建后丢失:
savePendingFile进入保存状态,重建后仍能接住ACTION_CREATE_DOCUMENT的回调,不再把保存静默变成“已取消”。 - L6/L7 MAIN/纯文本 Intent 与后台启动:已有文件时收到
ACTION_MAIN或纯文本分享不再清空界面;prepare 完成时如果界面已经onStop,不会从后台启动分享面板/SAF,而是提示回到应用重试。 - H8
showEmptyState不失效旧任务:重置/新入口统一递增操作代际并取消复制、prepare、MediaStore 保存和 SAF 写入;旧任务回到主线程后不再改 UI、不再 finish。
Fixed(保存竞态与错误处理)
- H2 保存中收到新分享会关掉新界面:MediaStore/SAF 保存都捕获自己的操作代际,新分享后旧任务只清理自己的半成品,不再
finish新界面、不再弹旧 Toast。 - H5 MediaStore 异常/孤儿条目:
insert、openOutputStream、写入、update(IS_PENDING=0)全部捕获;update返回<= 0视为失败,删除 pending 条目;整个保存流程不会因 Provider 异常崩溃。 - H6 SAF
wt部分写入后回退w:只有一个字节都没写进去时才回退"w";已经写了部分数据时不再盲目重写,失败后尝试deleteDocument/"wt"截断,并明确提示目标文件可能不完整;成功时校验写入字节数。
Fixed(缓存与交付标记)
- H7 交付标记在分享之后写:改为先写标记再启动分享面板;
startActivity失败会回滚标记;标记写不进去时不启动分享,避免把死链交给目标 App。 - H3 清理误删新会话标记:
cleanup只 prune 本次真正列到过、且确实已经删除的会话标记;清理开始后新建的会话标记不会被误删。listFiles()返回 null 时直接跳过 prune,不再把“读不出来”当成空目录。清理加进程内互斥,避免两个强制清理并发 prune。 - H12 会话目录撞名:会话名改为“时间戳 + 会话号 + UUID”,时钟回拨/进程重启/同毫秒都不会复用旧目录;目录已存在时重新生成,不再复用。
- H9 后台未交付缓存永远不清理:
onStop后给 30 分钟宽限,期间返回仍受保护;30 分钟后且没有复制/保存在跑时撤掉活会话登记,让 10 分钟未交付 TTL 生效。返回时如果缓存文件已被清理,会自动重试复制。 - L9 移除无用的持久化 URI 授权:不再对每次 SAF 选择的文件调用
takePersistableUriPermission,避免长期累积授权。
Fixed(复制与空间)
- H4 主线程查询 ContentProvider:
getType/query移到 IO 线程,界面先显示“正在读取文件”;mkdirs也移出主线程。慢/恶意 Provider 不会再直接 ANR。 - H10 32MB 固定预留拒绝小文件:预留量改为
min(32MB, 剩余空间/4),只剩 20MB 的设备也能复制 1KB 文件。 - L4 未知大小流无上限:未知大小(或报 0)的流最多复制
min(2GB, 可写空间 - 动态预留);超限时删除半成品并明确提示,不会无限填满磁盘。 - 复制路径健壮性:
statSize == 0不再走“空文件成功”快路径;statSize < 0复用已经打开的 PFD;读写0字节时让出而不是忙等;同目录copyFile改用copyTo并校验字节数,避免transferTo瞬时 0 导致改名失败。
Fixed(文件名 / Intent / 其它)
- L1 文件名劈开 emoji 代理对:先按 code point 再按 UTF-8 字节截断,ASCII 前缀 + emoji 不再产生
?;Toast 文件名也按 code point 省略。 - L2 控制字符 / 双向控制符:C0/C1 控制字符替换为
_,bidi 控制符(U+061C、U+200E/200F、U+202A–202E、U+2066–2069)直接移除,避免文件名伪装。 - L5
EXTRA_STREAM类型不安全:支持Uri、ArrayList<Uri>、Parcelable[],其他 Parcelable/坏数据按“没有文件”处理,不再ClassCastException/BadParcelableException崩溃;clipData解析也做了兜底。 - L3 分享面板包含自己:chooser 通过
EXTRA_EXCLUDE_COMPONENTS排除 HelloRename,底部警示语保留作为双保险。 - L8 空间不足文案识别:补充
not enough space、disk full、quota、insufficient storage、storage full。 - 时钟回拨导致清理永久节流:
CacheState.shouldCleanup检测到now < lastCleanupAt时重置基准并放行一次。
Tests
- JVM 单测增加到 71 条:新增
StreamCopierTest、OperationRegistryTest,并补充CacheCleanerTest(prune 竞态、listFiles为 null、原子标记、UUID、动态预留、未知流上限、时钟回拨、isNoSpace)与FileNameUtilsTest(代理对、控制符、bidi、Toast 省略)。 - API 34 模拟器新增
MainActivityFlowTest:分享复制、重建后恢复输入/旧文件名、ACTION_MAIN不清空、异常EXTRA_STREAM不崩溃、Parcelable[]形式仍可用;与ThemeUiTest一起作为 QA/Release 的模拟器门禁。
本包已签名,证书 SHA-256: 3682cce6d8fbf859b9b0a90ef8818acc747c82bb5f9d97418a4e6749cb6ccaca
校验安装包完整性: sha256sum -c SHA256SUMS.txt