Android Settings 从 Q 平台开始将搜索界面单独放到了 SettingsIntelligence 中,代码路径:packages/apps/SettingsIntelligence 。
查看 SettingsIntelligence 应用 AndroidManifest,发现启动 activity 为 SearchActivity,查看该 Activity。可以看到,onCreate() 方法中加载了一个 Fragment 用来填充 main_content,Fragment 有两个选择,其中 CarSearchFragment 是适配车机系统的,此处不做详解,主要跟进下 SearchFragment。
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
……
final LoaderManager loaderManager = getLoaderManager();
mSearchAdapter = new SearchResultsAdapter(this /* fragment */);
mSavedQueryController = new SavedQueryController(
getContext(), loaderManager, mSearchAdapter);
mSearchFeatureProvider.initFeedbackButton();
……
mSearchFeatureProvider.updateIndexAsync(getContext(), this /* indexingCallback */);
……
}
在 PreIndexDataCollector.java 中的最后 get*** 函数中创建 ContentResolver 来查询获取数据。
而数据的来源就是 Settings 中 SettingsSearchIndexablesProvider
, SettingsSearchIndexablesProvider 继承自 android.provider.SearchIndexablesProvider.java ,
<provider
android:name=".search.SettingsSearchIndexablesProvider"
android:authorities="com.android.settings"
android:multiprocess="false"
android:grantUriPermissions="true"
android:permission="android.permission.READ_SEARCH_INDEXABLES"
android:exported="true">
<intent-filter>
<action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER" />
</intent-filter>
</provider>
SearchIndexablesProvider 中只有一个 query 是有作用的,其他几个 insert delete update 操作都是抛出异常。 query 中对上面 PreIndexDataCollector 中的请求进行具体处理如下。
queryXmlResources 等几个操作具体实现就回到 Settings 应用模块中了,在 SettingsSearchIndexablesProvider 中进行实现,以 queryXmlResources 为例
最终通过 getProviderValues() 获取所有的带 @SearchIndexable
注释的类。再获取里面的 Indexable.SearchIndexProvider 内部类,所有的相关类里面的这个内部类都是一样的命名,好找
Settings 中常用方法,期间 Settings 中的 BaseSearchIndexProvider 需要着重关注下,该类实现 Indexable
.SearchIndexProvider 接口,直接给 Settings 的 SettingsSearchIndexablesProvider 提供数据。以后工作中会经常用到 BaseSearchIndexProvider 实现的几个方法,用来隐藏搜索项,添加搜索项。以下方法需要在各自的 fragment 中重写来实现。
// 添加 XML 中数据到搜索项
@Override
public List<SearchIndexableResource> getXmlResourcesToIndex(
Context context, boolean enabled) {
final SearchIndexableResource sir = new SearchIndexableResource(context);
sir.xmlResId = R.xml.connected_devices_advanced;
return Arrays.asList(sir);
}
// 添加 Controller 中数据到搜索项
@Override
public List<AbstractPreferenceController> createPreferenceControllers(
Context context) {
return buildPreferenceControllers(
context, null /* parent */, null /* authorities*/);
}
// 添加不可搜索项
@Override
public List<String> getNonIndexableKeys(Context context) {
final List<String> keys = super.getNonIndexableKeys(context);
return keys;
}
// 整个界面不可搜索
@Override
protected boolean isPageSearchEnabled(Context context) {
return false;
}
这里面重要的几个方法功能大致介绍下。首先构造函数中的 R.xml.display_settings ,这可以看下 BaseSearchIndexProvider 类中,其实就是给定 getXmlResourcesToIndex 方法的xml参数。添加xml中所有 key 的搜索项目。
getNonIndexableKeys 这个方法中返回就是无需搜索的,从搜索列表中移除的 key 的集合。
isPageSearchEnabled 这个返回 false 则表示这个 display_settings xml 中所有的 key 都不需要的搜索,全部移除。具体使用是在 BaseSearchIndexProvider 中。
通过在xml文件中配置也可达到不可搜索的目的
settings:searchable
=“false”
settings:keywords
=“keywords1, keywords2, keywords3”
searchable控制此项是否可搜索
keywords为此项的关键词,也可以被触发关键词而搜索到