Material You
内置 HCT 色彩实现,可以按壁纸生成配色,悬浮层与卡片跟着系统色调走。
下面每一条都对应代码里真实存在的分支。标了「已验证」的有真机记录,标了「降级」的在别的机型上会走不同路径,标了「需自备」的要你提供东西。
这是寻墨和「随便一个悬浮搜题 App」唯一真正的区别。
在 MIUI / HyperOS 上,悬浮窗的 SurfaceControl 图层带一个厂商私有标志位(0x40,即「跳过快照」)。SurfaceFlinger 生成截屏、录屏画面时会直接略过这一层,屏幕上你照常看得见,抓出来的画面里没有它。
实现走 SurfaceControl.setSkipScreenshot(true),再用一个隐藏 API 解黑名单的库把它放开。整个过程发生在 App 进程内。
addView() 那一刻 SurfaceControl 还不存在,打标必须等首帧 relayout。寻墨的做法是每个窗口一条独立的重试链,在 onPreDraw(relayout 之后、绘制之前)打标;打标成功前先把根视图设成不可见当首帧闸门,超过 600ms 仍拿不到图层才放行,避免整块内容永远不出现。
窗口一共有九处登记点:搜索主窗、答案气泡、关键词选择框、框选层、悬浮球、输入法等等,每一处都要单独登记,缩小成球再展开仍然是隐身层。
识别不到 MIUI / HyperOS 时,回退成「把窗口标题伪装成录屏窗口」的旧做法。它不需要厂商支持,但那是让系统在界面里少显示一个标签,不是让抓图跳图层——隐身强度低于小米上的效果。
另外两条硬边界:MediaProjection 类抓屏路径不保证;把隐身开关关掉,截屏就能正常看见这一层。Android 8.1 及以下不需要解黑名单,也不会打标。
FLAG_SECURE 会让抓出来的画面是一块黑,MIUI 还会弹「不允许截屏」;alpha = 0 是你自己也看不见。图层标记是唯一既保留可见、又不进快照的做法。没有任何联网搜题,命中与否完全由你导入的那本题库决定。
输入按空格拆成多个关键词,每个都必须出现在题目里;比对的文本是题干 + A + B + C + D + 答案拼起来的一整段,忽略大小写做子串包含。
所以「下列 不属于」这种两词查询会收窄到同一题里两个词都出现的题目,答案是「不属于」的题也会被题干命中。
结果列表截断在 60 条,命中更多时请加关键词收窄。没有排序权重,按题库里的先后出现。
搜索窗里用标签切换。AI 解题把题目发到你自己在设置里填的 OpenAI 兼容接口(可以一键填 DeepSeek 或视觉模型),解答记录留在 App 里,可以选择把 AI 的答案自动写进题库。
标准列是 题目,A,B,C,D,答案,其他情况尽量兼容。
CSV、TXT、TSV、Markdown、XLSX、XLS、DOCX、DOC。第一行像表头就按表头取列,不像就按松散行的正则去猜题干与选项边界。
.xls / .doc 走兼容解析,遇到结构特殊的表格会失败,这时 App 会提示你把它「另存为」xlsx / docx 或 csv 再导。
题库页搜到那道题,题干、A/B/C/D、答案都能编辑,点保存写回本地题库,并推给正在显示的悬浮窗——不用重导入。
导入的题库也可以再导出成 CSV,改完的文本就是最终版本。
输入这件事也留在悬浮层里。
搜索窗自己画了一层键盘,走内置拼音词库出候选,不调起系统输入法。系统键盘不会弹出来,也就不会被录屏、投屏一起带出去。默认开启,可以在外观设置里关掉改用系统键盘。
四种入口,成功率取决于你的 ROM。
用自带键盘输入,或长按粘贴复制来的题干。
开启后按音量键唤起搜索,同时把前台窗口可见文字取进搜索框,需要授予无障碍权限。
框选层可以圈住题目区域;拍照路径把图交给接口做识别。
系统截图 API 在不少 ROM 上实现不完整,寻墨额外接了 Shizuku(API V23)作为取屏通道。
服务器只提供两个 JSON,纯静态,没有账号体系。
/v1/notice.json 决定首页公告内容与提示强度。当公告里的 version_code 大于你手机上的版本号、且 apk_url 不为空时,公告会常驻并额外出现「下载更新」按钮。
/v1/banks.json 给出每本题库的名字、题量、大小和 SHA-256 前缀。下载时按前缀校验,防止传输被改;内容先进内存,你在 App 里点保存才会落到本机题库。
设置页能填自定义云端地址,换服务器不用换 App。默认地址是明文 HTTP 白名单里唯一放行的一台;填别的地址请走 HTTPS,否则系统会拦。
悬浮窗是你要长时间盯着的东西,所以可调。
内置 HCT 色彩实现,可以按壁纸生成配色,悬浮层与卡片跟着系统色调走。
搜索窗能改大小、能收起成悬浮球,展开后位置与状态保持。
设置里能手动指定品牌,让隐身走厂商标记还是标题伪装,兼容报告里能看到当前判定结果。