Skip to content

Releases

v2.3.1

Choose a tag to compare

@github-actions github-actions released this 13 Nov 12:44

防御性小版本:把“打开方式”的 content scheme 显式写进 manifest,不改变框架语义,只是不再依赖框架的隐式推断。

Changed

  • VIEW filter 显式化:新增 <data android:mimeType="*/*" android:scheme="content"/> 的 filter,与原有的“只写 MIME”“只写 content scheme 兜底 null type”两条并存。框架本来就把“只声明 MIME”的 filter 视为支持 content: / file:(Data test 规则 4),显式写出来只是把“OEM 解析器没实现这条隐式规则”的可能性降到最低——HyperOS/MIUI 的 MiuiResolverActivity 会自己再算一遍候选列表,第三方模块(HyperSelect 等)也是围绕它做排序/隐藏。
  • SEND 保持不带 scheme:ACTION_SEND / SEND_MULTIPLE 仍然只写 MIME。分享请求一般没有 data URI,一旦带上 content scheme,scheme 为 null 的 Intent 会直接 NO_MATCH_DATA;新增用例守住这一点。
  • 版本号:versionName 2.3.1,versionCode 最低 19(覆盖 v2.3.0 的 18)。

Testing

  • 新增 sendIntentFilters_resolveTypedIntentsWithoutData(SEND / SEND_MULTIPLE 在无 data URI 时仍解析到本应用),API 36 instrumentation 共 20 条;JVM 仍 88 条。
  • qa_check.py 新增“VIEW 显式声明 content scheme + */*”断言。
  • README「已知限制」补充:HyperOS/MIUI 的“打开方式”由小米自己实现,候选会分成“推荐选项 / 其他选项”并按使用频率排序;看不到本应用时往下翻或设为默认即可,这不是 manifest 少声明了什么。

本包已签名,证书 SHA-256: 3682cce6d8fbf859b9b0a90ef8818acc747c82bb5f9d97418a4e6749cb6ccaca

校验安装包完整性: sha256sum -c SHA256SUMS.txt

v2.3.0

Choose a tag to compare

@github-actions github-actions released this 13 Nov 11:54

分享之外再开一个入口:文件管理器、邮件附件、浏览器下载完成后的“打开”也能直接调起本应用。进入后和单文件分享走同一条“复制 → 改名 → 发送/保存”,源文件依旧不动,依旧零权限。

Added

  • “打开方式”入口(ACTION_VIEW):<data android:mimeType="*/*"/> 覆盖任意格式的 content: / file: 请求;另加一条只声明 content scheme 的 filter,接住来源没 setType()、provider 也拿不到 MIME 的请求(框架的 */* filter 匹配不上 type 为 null 的 Intent)。只声明 MIME 的 filter 不会匹配 http(s),浏览器链接不会被接管。
  • 共用加载路径:VIEW 直接复用 loadSource,文件名 / MIME / 扩展名锁定 / 校验值 / 保存重名规则与分享完全一致;目录沿用 2.1.0 的策略按纯文本处理、不展开。文本兜底的“发送”原样转发来源 VIEW 请求,并给 data 里的 content:// 补 FLAG_GRANT_READ_URI_PERMISSION。
  • instrumentation:新增 4 条 API 36 用例(viewIntent_copiesFileLikeShare、viewIntent_withoutType_stillOpens、viewIntent_ofFolder_fallsBackToPlainText、viewIntentFilter_resolvesContentUris_andIgnoresWebLinks),模拟器门禁共 19 条。
  • qa_check.py:新增 VIEW action 断言,防止后续改动把入口删掉。

Changed

  • 版本号:versionName 2.3.0,versionCode 最低 18(覆盖 v2.2.0 的 17)。
  • 已知限制:file:// 裸路径能进来但零权限读不了,界面会提示“源文件不可用”,这类来源请改用文件管理器里的分享。

本包已签名,证书 SHA-256: 3682cce6d8fbf859b9b0a90ef8818acc747c82bb5f9d97418a4e6749cb6ccaca

校验安装包完整性: sha256sum -c SHA256SUMS.txt

v2.2.0

Choose a tag to compare

@github-actions github-actions released this 07 Nov 09:26

标题栏右上角加了一个垃圾桶:手动强制清空缓存,只留下当前正在用的那一份。Windows/Android 设置里的“清除缓存”语义,只是这个应用自己实现,不依赖系统。

Added

  • 清空缓存按钮:MainActivity 顶栏右侧 48dp 图标按钮,二次确认后删除 cacheDir/shared/ 下所有非活会话目录,以及 shared-state/ 里对应的交付标记、孤儿标记和原子写临时文件;当前会话(CacheState 登记 + sessionDir/currentFile/savePendingFile 兜底)绝不删除。
  • 结果提示:清理在 IO 线程执行,完成后 Toast 报告释放的字节数(B/KB/MB/GB),没有可清理内容时提示“没有可清理的缓存”。
  • 单测:新增 3 条 JVM 用例(保留活会话并删除其它、清孤儿标记与临时文件、目录不可读时不动标记),JVM 共 88 条。
  • instrumentation:新增 clearCacheButton_keepsCurrentSession_andDeletesOtherSessions(造一个旧会话 + 交付标记,点按钮并确认后断言旧会话/标记被删、当前会话仍在、发送仍可用),API 36 门禁共 15 条。

Changed

  • 版本号:versionName 2.2.0,versionCode 最低 17(覆盖 v2.1.0 的 16)。

本包已签名,证书 SHA-256: 3682cce6d8fbf859b9b0a90ef8818acc747c82bb5f9d97418a4e6749cb6ccaca

校验安装包完整性: sha256sum -c SHA256SUMS.txt

v2.1.0

Choose a tag to compare

@github-actions github-actions released this 07 Nov 09:05

撤回 2.0.0 的文件夹递归。跨应用分享只授予目录这一个 URI,列子项需要 FLAG_GRANT_PREFIX_URI_PERMISSION 或 SAF 树授权,普通 ACTION_SEND 不会给;HyperOS 3 等来源上文件夹分享必然失败。与其留一个假入口,不如把路径/链接当纯文本交出去。

Changed

  • 文件夹分享改为纯文本:分享的是文件夹时,直接把它的 URI/路径放进文本模式——可改名、可保存为 UTF-8 无 BOM 的 .txt、也可点“发送”原样转发来源请求;不再尝试读取文件夹内容。
  • 多文件:只处理文件;同时选中文件夹时跳过文件夹,状态栏提示跳过了几个;全部是文件夹时整单降级为纯文本。
  • 多文件保存路径:统一写 Download/ 根(Android 7–9 写用户选中目录的根),不再创建/复用来源的目录层级。
  • 版本号:versionName 2.1.0,versionCode 最低 16(覆盖 v2.0.0 的 15)。
  • 测试:folderShare_preservesNestedStructure 换成 folderShare_isTreatedAsPlainText——断言预览是文件夹 URI、可改名/保存/发送、重建后仍在,并校验保存的 .txt 内容就是该 URI。instrumentation 仍为 14 条。

Removed

  • 文件夹递归展开(DocumentsContract 子项遍历)、RELATIVE_PATH 子目录与 SAF 逐级建目录的代码及文案。
  • status_folder_unreadable(“无法读取分享的文件夹”)——这条失败路径已经不存在。

Fixed

  • 文件夹分享在真机上必然失败:来源只授予目录本身,列子项会抛 SecurityException,界面停在“无法读取分享的文件夹”。现在不再把文件夹当成可保存的目录树。
  • 文本模式的状态/提示能区分“普通文本”“未知请求转储”“文件夹路径”三种来源,不再是笼统的文本提示。

本包已签名,证书 SHA-256: 3682cce6d8fbf859b9b0a90ef8818acc747c82bb5f9d97418a4e6749cb6ccaca

校验安装包完整性: sha256sum -c SHA256SUMS.txt

v2.0.0

Choose a tag to compare

@github-actions github-actions released this 07 Nov 08:07

分享入口的又一次扩展:多文件分享可以带上整棵目录树;纯文本和无法识别的调用不再只是“落个 .txt”,还能原样转发给别的应用;顺手修掉 .ini 被存成 .ini.txt 的问题。因为新增了文件夹分享和转发能力,按语义化版本升到 2.0.0。

Added

  • 文件夹分享:ACTION_SEND / ACTION_SEND_MULTIPLE 中的目录/树 URI 会递归展开;Android 10+ 用 MediaStore 的 RELATIVE_PATH 保留 Download/<根目录>/<子目录>/...,Android 7–9 在 SAF 目标目录里逐级 createDocument(..., MIME_TYPE_DIR, ...)。不新增 manifest 权限,依赖来源 Provider 的目录/子项授权;空文件夹不复制。
  • 纯文本/未知请求的“发送”:文本模式和多文件以外的未知兜底现在启用发送按钮,直接把来源 Intent 复制到 chooser,不在应用里重新编码内容;仅在有 ClipData/EXTRA_STREAM 时补 FLAG_GRANT_READ_URI_PERMISSION。
  • 未知请求兜底:没有可读文件/文本的分享或非 ACTION_MAIN 调用,生成 Intent.toUri(URI_INTENT_SCHEME) 原始转储并保存为 .txt,同时保留原 Intent 供转发。

Changed

  • 纯文本模式:保存为 UTF-8 无 BOM .txt,不规范化换行(CRLF/CR/LF 原样);默认名仍是本地时区 YYYYMMDD_hhmmss。发送不再禁用。
  • 多文件 UI:列表显示相对路径(如 share-root/sub/b.txt),保存时按 multiPaths 创建/复用子目录。
  • 版本号:versionName 2.0.0,versionCode 最低 15(覆盖 v1.6.0 的 14)。
  • 测试:新增 debug-only TestFolderProvider 与 folderShare_preservesNestedStructure,覆盖文件夹递归展开和 MediaStore 相对路径;未知分享/畸形 EXTRA_STREAM 用例同步到新兜底行为。JVM 单测 85 条,API 36 instrumentation 14 条。

Fixed

  • 保存 .ini 等非标准扩展名时被追加 .txt:当分享方把文件报成 text/plain、而 Android 的 MIME 表里 text/plain 只对应 txt 时,MediaStore 会把 desktop.ini 保存成 desktop.ini.txt。保存时若源 MIME 的规范扩展名与当前扩展名冲突,改用扩展名推断的 MIME(推断不到则 application/octet-stream),单文件和多文件共用该规则,保留原扩展名。

本包已签名,证书 SHA-256: 3682cce6d8fbf859b9b0a90ef8818acc747c82bb5f9d97418a4e6749cb6ccaca

校验安装包完整性: sha256sum -c SHA256SUMS.txt

v1.5.0

Choose a tag to compare

@github-actions github-actions released this 28 Oct 11:44
4328435

复制完成后显示文件校验值,方便用户自行和源文件对比,验证传输/写盘后内容是否一致。

Added

  • MD5 / SHA-1 / SHA-256 展示:文件复制完成后,在输入框/按钮下方显示三个小写十六进制校验值;支持长按选择,以及“Copy all”一键复制三行。
  • 复制后回读计算:校验值是对 cacheDir/shared/<会话>/ 里的最终缓存文件做一次只读回读得到的,而不是边复制边算。这样显示的是真正会被分享/保存的那份文件,写盘阶段若发生损坏也能通过和源文件对比发现。
  • 计算进度:回读期间复用现有进度条,显示“Calculating checksums… %”;期间禁用发送/保存,避免在拿到校验值前交付。
  • 状态恢复:MD5/SHA-1/SHA-256 进入 onSaveInstanceState,深浅色/字体/语言重建后保留;新分享/重置/缓存失效时清空。
  • 失败可重试:回读失败显示“Could not calculate checksums. Tap Send to retry.”,不展示半套值,也不会把未完成校验的文件当成 ready。

Changed

  • 版本号:versionName 1.5.0,versionCode 最低 13(可覆盖 v1.4.0 的 12)。
  • 测试:新增 FileDigestUtilsTest(已知向量、空文件、二进制、进度、取消、十六进制填充),JVM 单测增加到 78 条;MainActivityFlowTest 增加“校验值展示 + 重建后保留”用例,API 36 模拟器门禁共 8 条 instrumentation。

Notes

  • 回读是一次额外的完整读盘;大文件期间界面仍可响应,但发送/保存要等校验值完成。
  • MD5/SHA-1 仅用于兼容旧工具和快速对比,完整性/安全性优先看 SHA-256。

本包已签名,证书 SHA-256: 3682cce6d8fbf859b9b0a90ef8818acc747c82bb5f9d97418a4e6749cb6ccaca

校验安装包完整性: sha256sum -c SHA256SUMS.txt

v1.4.0

Choose a tag to compare

@github-actions github-actions released this 18 Oct 13:23
6cfbc54

构建工具链升级到 AGP 9 / Gradle 9 / Kotlin 2.4,并把 compileSdk / targetSdk 升到 36(Android 16)。这是一个 minor 版本:targetSdk 36 带来强制 edge-to-edge,界面适配是本次的主要功能性改动。

Changed(工具链)

  • AGP 8.5.2 → 9.4.1,Gradle 8.9 → 9.6.0,Kotlin 2.0.21 → 2.4.21。
  • 按 AGP 9 的 built-in Kotlin 迁移:移除 org.jetbrains.kotlin.android 插件;在根 build.gradle.kts 的 buildscript classpath 中显式指定 KGP 2.4.21,避免沿用 AGP 内置的旧 KGP。
  • release 构建改用 AGP 9.3+ 的 optimization { enable = false } DSL,保持当前“不混淆、不 shrink”的行为。
  • AndroidX 依赖升级到当前 stable:core-ktx 1.18.0、appcompat 1.8.0、activity 1.13.0、lifecycle 2.11.0、material 1.14.0、coroutines 1.11.0;AndroidX Test 升到 runner 1.7.0 / ext-junit 1.3.0 / espresso 3.7.0。
  • compileSdk = 36、targetSdk = 36,minSdk 24 不变;Build Tools 使用 AGP 9.4 默认的 36.0.0。

Changed(Android 16 行为)

  • 强制 edge-to-edge:targetSdk 36 在 Android 16 上不能再通过 windowOptOutEdgeToEdgeEnforcement 退出。MainActivity 对 API 35+ 调用 WindowCompat.setDecorFitsSystemWindows(window, false),用 WindowInsets 给根布局加系统栏/刘海/IME padding;Toolbar 自身仍保持 56dp,状态栏区域由根布局让出。
  • 状态栏/导航栏图标明暗改用 WindowInsetsControllerCompat 跟随深浅色;API 34 及以下保留原有 statusBarColor + 系统栏行为。
  • 没有重写返回键,因此 Android 16 的 predictive back 默认行为不需要额外迁移;布局没有锁定方向/宽高比,大屏忽略 screenOrientation/resizableActivity 限制不会造成额外问题(已有的状态恢复继续覆盖重建)。
  • 未使用 native 库,不涉及 16 KB page size;未使用健康、蓝牙或 ScheduledExecutorService 固定频率任务。

Changed(验证)

  • Emulator 门禁从 API 34 升到 API 36,只保留 API 36 主门禁;ThemeUiTest 改为 edge-to-edge aware(Toolbar top = 根布局状态栏 padding,而不是 0)。
  • tools/qa_check.py 的 targetSdk 期望改为 36。
  • release versionCode 最低值提高到 12,确保能覆盖 v1.3.2 的 11。

本包已签名,证书 SHA-256: 3682cce6d8fbf859b9b0a90ef8818acc747c82bb5f9d97418a4e6749cb6ccaca

校验安装包完整性: sha256sum -c SHA256SUMS.txt

v1.3.2

Choose a tag to compare

@github-actions github-actions released this 18 Oct 12:55

底层逻辑集中修复:生命周期/状态恢复、保存竞态、缓存交付标记、主线程 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

v1.3.1

Choose a tag to compare

@github-actions github-actions released this 18 Oct 11:51

修复 v1.3.0 的重复标题,并把云端模拟器 UI 验证设为发布前的硬门槛。

Fixed

  • 界面出现两个标题:v1.3.0 给 Activity 加了自绘 56dp Toolbar,但主题仍继承 Theme.Material3.DayNight(自带系统 ActionBar),于是系统标题栏和自绘顶栏各显示一次应用名。现在改为 Theme.Material3.DayNight.NoActionBar,只保留与页面同色的 56dp 顶栏。

Added

  • 云端模拟器 UI 门禁:新增 .github/workflows/emulator-ui.yml,由 QA 与 Release 复用。在 GitHub Actions 的 API 34 模拟器上运行 instrumentation 测试,断言:
    • supportActionBar 必须为 null,且全屏只有一个应用名标题;
    • 顶栏紧贴内容区顶部,高度恰好 56dp;
    • 浅色模式白底黑字、深色模式黑底白字。
  • 验证通过后额外截取浅色 / 深色两张截图和 UI 层级,作为 Actions artifact 留存。
  • Release workflow 以模拟器验证为前置依赖:release job 通过 needs: emulator-verify 等待模拟器门禁;门禁失败时不会构建、更不会发布。

本包已签名,证书 SHA-256: 3682cce6d8fbf859b9b0a90ef8818acc747c82bb5f9d97418a4e6749cb6ccaca

校验安装包完整性: sha256sum -c SHA256SUMS.txt

v1.3.0

Choose a tag to compare

@github-actions github-actions released this 18 Oct 11:29

⚠️ 此版本存在重复标题问题(系统 ActionBar + 自绘顶栏),请改用 v1.3.1。

界面与命名更新:英文应用名改为 HelloRename;应用内跟随系统深色 / 浅色模式自动切换,只保留黑白两套默认配色。

Added

  • 56dp 顶部应用栏:标题显示当前语系的应用名,顶栏与页面同色,不额外加分割线或阴影(与 hellowidget 首页的默认设计一致)。
  • 状态栏颜色与顶栏一致,状态栏图标(时间 / 电量)在浅色模式下用深色、深色模式下用浅色。

Changed

  • 英文应用名从 hellorename 改为首字母大写的 HelloRename(中文名仍为「改名助手」)。
  • 深色 / 浅色模式自动切换:页面、顶栏、按钮、输入框、勾选框统一使用黑白配色 —— 浅色白底黑字,深色黑底白字;不提供用户自定义颜色的入口,只保留这两套默认配色。
  • 移除 Material 3 默认的品牌蓝强调色:主要按钮、输入框描边、勾选框等一并改为黑 / 白,避免深浅色模式下残留彩色元素。

Fixed

  • 深色模式切换后界面不跟着变色:MainActivity 原来在 configChanges 里声明了 uiMode,系统切换深浅色时 Activity 不会重建,已加载的界面继续使用旧配色。现在移除该声明,由系统正常重建 Activity 并应用 values / values-night 中对应的颜色资源。

本包已签名,证书 SHA-256: 3682cce6d8fbf859b9b0a90ef8818acc747c82bb5f9d97418a4e6749cb6ccaca

校验安装包完整性: sha256sum -c SHA256SUMS.txt