news 2026/11/3 2:29:55

Android定制实战:从 SettingsIntelligence 源码定位应用搜索结果过滤点

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android定制实战:从 SettingsIntelligence 源码定位应用搜索结果过滤点

场景承接上篇《让指定系统应用在“所有应用”列表中隐身》:应用列表已经通过ApplicationsState.FILTER_NOT_HIDE过滤掉了,但用户在设置顶部搜索框里输入应用名,依然能搜到它。本文记录这条搜索链路的完整定位过程与修改方案。


一、问题:为什么列表过滤了,搜索还能搜到?

上篇方案改的是packages/apps/Settings(借 SettingsLib 的ApplicationsState)。但设置首页/各页面顶部的搜索框点击后,实际跳转到的是另一个独立 APK。

从SearchMenuController可以确认这一点:

// packages/apps/Settings/src/com/android/settings/search/actionbar/SearchMenuController.javafinalStringSettingsIntelligencePkgName=activity.getString(R.string.config_settingsintelligence_package_name);if(!Utils.isPackageEnabled(activity,SettingsIntelligencePkgName)){return;// 搜索菜单依赖这个包,没有它连搜索图标都不显示}...searchItem.setOnMenuItemClickListener(target->{finalIntentintent=FeatureFactory.getFactory(activity).getSearchFeatureProvider().buildSearchIntent(activity,mPageId);// 跳出到独立应用mHost.startActivityForResult(intent,SearchFeatureProvider.REQUEST_CODE);...});

包名在Settings/res/values/config.xml里:

<stringname="config_settingsintelligence_package_name"translatable="false">com.android.settings.intelligence</string>

即 AOSP 的SettingsIntelligence(packages/apps/SettingsIntelligence)。它是一个搜索聚合应用,负责界面、索引和查询编排;而 Settings 只是通过SearchIndexablesProvider(ContentProvider)把自己的可搜索条目暴露给它。

所以结论很明确:"所有应用列表"和"搜索"是两条完全独立的数据链路,只改 SettingsLib 后搜索结果里仍然会出现目标应用——这是一个非常典型的"改了一处以为全覆盖,漏了另一条链路"的定制坑。

二、搜索结果的数据来源

SettingsIntelligence 的搜索结果由多个SearchQueryTask.QueryWorker并行产出(设置项索引、应用列表、开关建议等),最终合并排序展示。应用类的结果来自:

packages/apps/SettingsIntelligence/src/com/android/settings/intelligence/search/query/InstalledAppResultTask.java

核心query()逻辑:

List<ApplicationInfo>appsInfo=mPackageManager.getInstalledApplications(PackageManager.MATCH_DISABLED_COMPONENTS|PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS|PackageManager.MATCH_INSTANT);for(ApplicationInfoinfo:appsInfo){if(!info.enabled&&mPackageManager.getApplicationEnabledSetting(info.packageName)!=PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER){// Disabled by something other than user, skip.continue;}finalCharSequencelabel=info.loadLabel(mPackageManager);finalintwordDiff=SearchQueryUtils.getWordDifference(label.toString(),mQuery);if(wordDiff==SearchQueryUtils.NAME_NO_MATCH){continue;// 应用名与搜索词不匹配,跳过}finalIntentintent=newIntent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(Uri.fromParts(INTENT_SCHEME,info.packageName,null/* fragment */))...;// 组装 AppSearchResult,点击后跳到该应用的"应用详情"页results.add(builder.build());}

几个值得注意的细节:

  1. 数据源是PackageManager.getInstalledApplications()直查,不经过ApplicationsState,因此 SettingsLib 里的过滤器对它无效;
  2. 匹配的是应用 label(显示名),不是包名——用户输入中文应用名同样能命中;
  3. 结果的 payload 是ACTION_APPLICATION_DETAILS_SETTINGSintent,也就是说搜索结果里点一下就能直达该应用的详情页——如果详情页本身也被隐藏需求覆盖,这条路径必须一并堵住。

三、修改方案

与列表过滤同样的思路:白名单数组 + 遍历入口处前置排除。

publicclassInstalledAppResultTaskextendsSearchQueryTask.QueryWorker{/** Custom: packages always hidden from Settings search results. */privatestaticfinalString[]HIDE_ALWAYS_PACKAGES={"com.example.dmapp",};@OverrideprotectedList<?extendsSearchResult>query(){...for(ApplicationInfoinfo:appsInfo){// Custom: always hide these packages from Settings search results.if(Arrays.asList(HIDE_ALWAYS_PACKAGES).contains(info.packageName)){continue;}if(!info.enabled&&...){continue;}...}}}

别忘了import java.util.Arrays;。

完整 diff

packages/apps/SettingsIntelligence/src/com/android/settings/intelligence/search/query/InstalledAppResultTask.java +import java.util.Arrays; + public class InstalledAppResultTask extends SearchQueryTask.QueryWorker { ... + /** Custom: packages always hidden from Settings search results. */ + private static final String[] HIDE_ALWAYS_PACKAGES = { + "com.example.dmapp", + }; + @Override protected List<? extends SearchResult> query() { ... for (ApplicationInfo info : appsInfo) { + // Custom: always hide these packages from Settings search results. + if (Arrays.asList(HIDE_ALWAYS_PACKAGES).contains(info.packageName)) { + continue; + } if (!info.enabled

四、为什么不改搜索的"索引"而改"查询"

SettingsIntelligence 有两阶段:

  • 索引阶段(Indexing):启动/更新时通过各应用的SearchIndexablesProvider抓取可搜索条目建库;
  • 查询阶段(Query):用户输入关键词时实时跑各QueryWorker。

应用类结果不走索引库——它是每次搜索时实时枚举已安装应用的,所以只能(也只需)在查询侧InstalledAppResultTask过滤。而设置项类结果走索引库,如果以后要隐藏某个设置项,思路则是在对应SearchIndexableRaw/BaseSearchIndexProvider的getNonIndexableKeys里返回该 key。两类目标的过滤点不同,这是本篇最值得记住的经验。

五、验证与编译

  1. 编译(注意目标不是 Settings):
sourcebuild/envsetup.sh lunch<product>-userdebugmakeSettingsIntelligence-j16
  1. 推送/刷入 SettingsIntelligence APK 后验证:
    • 设置 → 顶部搜索框 → 输入该应用的中文名/包名关键字:无结果;
    • 输入普通应用名(如 “Bluetooth”):其它应用照常出现,确认过滤器没有误伤;
    • make Settings SettingsLib的列表过滤结果同时生效(两个 APK 都要更新)。

六、总结:定制“隐藏”需求的链路检查清单

结合上篇(列表过滤),这类需求完整落地要过三关:

入口数据链路过滤点编译目标
设置 → 所有应用(含“显示系统应用”)ManageApplications→ApplicationsStateFILTER_NOT_HIDE.filterApp()SettingsLib/Settings
设置顶部搜索 → 应用名SettingsIntelligenceInstalledAppResultTaskquery()遍历前置排除SettingsIntelligence
桌面图标(如有)Launcher3不在本文范围,按需处理Launcher3

三条链路互相独立、源码分属不同进程甚至不同 APK。定制前先画清楚“用户能从几个地方看到这个应用”,再逐条找到各链路的统一收口点,才不会上线后被一条漏网路径打回。另外,本方案仅影响显示,com.example.dmapp的运行、被系统其它模块拉起的能力完全不受影响。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/3 2:28:29

在 Mac 上运行 Windows 程序:5 分钟上手的 Whisky 使用指南

在 Mac 上运行 Windows 程序&#xff1a;5 分钟上手的 Whisky 使用指南 【免费下载链接】Whisky A modern Wine wrapper for macOS built with SwiftUI 项目地址: https://gitcode.com/gh_mirrors/wh/Whisky Whisky 是一个基于 Wine 的 macOS 图形化工具&#xff0c;让你…

作者头像 李华
网站建设 2026/11/3 2:26:59

没有对齐录音也能训?拆 SheetSage2 + MERT2 如何给 YuE2 造监督信号

没有对齐录音也能训&#xff1f;拆 SheetSage2 MERT2 如何给 YuE2 造监督信号 在大模型音乐生成这条赛道上&#xff0c;"数据从哪来"往往比"模型长什么样"更能决定上限。语音合成领域可以靠海量带逐字时间戳的标注语料训练 TTS&#xff0c;而全曲音乐生成…

作者头像 李华
网站建设 2026/11/3 2:26:41

一周烧出 3.12 万亿 Token:Agnes 免费开放的生意账,能撑多久?

一周烧出 3.12 万亿 Token&#xff1a;Agnes 免费开放的生意账&#xff0c;能撑多久&#xff1f; 当别家把 API 价格战打到每百万 Token 几分钱时&#xff0c;新加坡 Agnes AI 直接把价格归零&#xff1a;文本、图像、视频三模态 API 无限期免费开放。效果立竿见影——智源社区…

作者头像 李华