当前位置: 首页 > ai >正文

SettingsIntelligence

  1. 代码路径
    源码:packages/apps/SettingsIntelligence/
    编译及安装:单编模块名SettingsIntelligence,可直接安装编译出来的 apk。

3.启动页







此处由设置代码易知,搜索启动如上 activity。接下来查看该界面的加载流程。

  1. 数据加载
    SearchActivity 在 onCreate 方法中加载了 SearchFragment,接下来查看 fragment 中的逻辑

@Override
public void onCreate(Bundle savedInstanceState) {

final LoaderManager loaderManager = getLoaderManager();
// 顾名思义,搜索结果适配器
mSearchAdapter = new SearchResultsAdapter(this /* fragment /);
mSavedQueryController = new SavedQueryController(
getContext(), loaderManager, mSearchAdapter);
mSearchFeatureProvider.initFeedbackButton();

// 异步加载索引数据
mSearchFeatureProvider.updateIndexAsync(getContext(), this /
indexingCallback */);
}

@Override
public void updateIndexAsync(Context context, IndexingCallback callback) {

getIndexingManager(context).indexDatabase(callback);
}

public void indexDatabase(IndexingCallback callback) {
// 启动异步任务加载数据
IndexingTask task = new IndexingTask(callback);
task.execute();
}

public class IndexingTask extends AsyncTask<Void, Void, Void> {

@Override
protected Void doInBackground(Void… voids) {
performIndexing();
return null;
}

}

public static final String PROVIDER_INTERFACE =
“android.content.action.SEARCH_INDEXABLES_PROVIDER”;

public void performIndexing() {
// 查询实现了 android.content.action.SEARCH_INDEXABLES_PROVIDER 的 provider
final Intent intent = new Intent(SearchIndexablesContract.PROVIDER_INTERFACE);
final List providers =
mContext.getPackageManager().queryIntentContentProviders(intent, 0);

final String localeStr = Locale.getDefault().toString();
final boolean isFullIndex = IndexDatabaseHelper.isFullIndex(mContext, providers, localeStr);// 判断是否需要重构数据库
if (isFullIndex) {rebuildDatabase();
}// 从 providers 中解析 indexData
PreIndexData indexData = getIndexDataFromProviders(providers, isFullIndex);// 更新数据库
updateDatabase(indexData, isFullIndex);
IndexDatabaseHelper.setIndexed(mContext, providers, localeStr);

}
4.1 从 provider 解析数据
PreIndexData indexData = getIndexDataFromProviders(providers, isFullIndex);

PreIndexData getIndexDataFromProviders(List providers, boolean isFullIndex) {
if (mCollector == null) {
mCollector = new PreIndexDataCollector(mContext);
}
return mCollector.collectIndexableData(providers, isFullIndex);
}

public PreIndexData collectIndexableData(List providers, boolean isFullIndex) {
mIndexData = new PreIndexData();

for (final ResolveInfo info : providers) {// 1,provider 需要添加权限 android.permission.READ_SEARCH_INDEXABLES// 2,实现 provider 的需要是系统应用if (!isWellKnownProvider(info)) {continue;}final String authority = info.providerInfo.authority;final String packageName = info.providerInfo.packageName;// 需要重构数据库时重新加载数据if (isFullIndex) {addIndexablesFromRemoteProvider(packageName, authority);}// 添加不可索引的数据addNonIndexablesKeysFromRemoteProvider(packageName, authority);
}return mIndexData;

}

// 数据加载
private void addIndexablesFromRemoteProvider(String packageName, String authority) {
try {
final Context context = mContext.createPackageContext(packageName, 0);

    // 构建 urifinal Uri uriForResources = buildUriForXmlResources(authority);// 根据提供的 provider 查询数据,添加到 mDataToUpdatemIndexData.addDataToUpdate(authority, getIndexablesForXmlResourceUri(context, packageName, uriForResources,SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS));final Uri uriForRawData = buildUriForRawData(authority);mIndexData.addDataToUpdate(authority, getIndexablesForRawDataUri(context, packageName, uriForRawData,SearchIndexablesContract.INDEXABLES_RAW_COLUMNS));//*/ freeme.caoguofeng, 20230713. Settings-search: add for Injection Index.final Uri uriForDynamicRawData = buildUriForDynamicRawData(authority);mIndexData.addDataToUpdate(authority, getIndexablesForRawDataUri(context, packageName, uriForDynamicRawData,SearchIndexablesContract.INDEXABLES_RAW_COLUMNS));//*/final Uri uriForSiteMap = buildUriForSiteMap(authority);mIndexData.addSiteMapPairs(getSiteMapFromProvider(context, uriForSiteMap));
} catch (PackageManager.NameNotFoundException e) {Log.w(TAG, "Could not create context for " + packageName + ": "+ Log.getStackTraceString(e));
}

}
4.2 更新 search_index.dp 数据库
void updateDatabase(PreIndexData preIndexData, boolean isFullIndex) {
// 获取不可索引的数据
final Map<String, Set> nonIndexableKeys = preIndexData.getNonIndexableKeys();

try {database.beginTransaction();// Convert all Pre-index data to Index data and and insert to db.List<IndexData> indexData = getIndexData(preIndexData);...// 数据插入insertIndexData(database, indexData);// Only check for non-indexable key updates after initial index.// Enabled state with non-indexable keys is checked when items are first inserted.if (!isFullIndex) {updateDataInDatabase(database, nonIndexableKeys);}database.setTransactionSuccessful();
} finally {database.endTransaction();
}

}

void updateDataInDatabase(SQLiteDatabase database,
Map<String, Set> nonIndexableKeys) {
// 索引是否可用的条件
final String whereEnabled = ENABLED + " = 1";
final String whereDisabled = ENABLED + " = 0";

// 获取之前可用的索引数据
final Cursor enabledResults = database.query(TABLE_PREFS_INDEX, SELECT_COLUMNS,whereEnabled, null, null, null, null);final ContentValues enabledToDisabledValue = new ContentValues();
enabledToDisabledValue.put(ENABLED, 0);String authority;
// TODO Refactor: Move these two loops into one method.
while (enabledResults.moveToNext()) {authority = enabledResults.getString(enabledResults.getColumnIndexOrThrow(DATA_AUTHORITY));final String key = enabledResults.getString(enabledResults.getColumnIndexOrThrow(DATA_KEY_REF));final Set<String> authorityKeys = nonIndexableKeys.get(authority);// 更新当前不可用的 key// The indexed item is set to Enabled but is now non-indexableif (authorityKeys != null && authorityKeys.contains(key)) {final String whereClause = getKeyWhereClause(key);database.update(TABLE_PREFS_INDEX, enabledToDisabledValue, whereClause, null);}
}
enabledResults.close();// 获取之前禁用的数据
final Cursor disabledResults = database.query(TABLE_PREFS_INDEX, SELECT_COLUMNS,whereDisabled, null, null, null, null);final ContentValues disabledToEnabledValue = new ContentValues();
disabledToEnabledValue.put(ENABLED, 1);while (disabledResults.moveToNext()) {authority = disabledResults.getString(disabledResults.getColumnIndexOrThrow(DATA_AUTHORITY));final String key = disabledResults.getString(disabledResults.getColumnIndexOrThrow(DATA_KEY_REF));final Set<String> authorityKeys = nonIndexableKeys.get(authority);// The indexed item is set to Disabled but is no longer non-indexable.// We do not enable keys when authorityKeys is null because it means the keys came// from an unrecognized authority and therefore should not be surfaced as results.// 更新为可用if (authorityKeys != null && !authorityKeys.contains(key)) {final String whereClause = getKeyWhereClause(key);database.update(TABLE_PREFS_INDEX, disabledToEnabledValue, whereClause, null);}
}
disabledResults.close();

}
5. 搜索流程
过滤 SearchFragment.java 代码,可以看到

// SearchFragment.java
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {

ActionBar actionBar = activity.getActionBar();
actionBar.setDisplayHomeAsUpEnabled(false);
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setDisplayShowCustomEnabled(true);
View actionbarLayout = LayoutInflater.from(getContext()).inflate(
R.layout.freeme_layout_actionar_searchview, null);
// 加载了一个 SearchView
actionBar.setCustomView(actionbarLayout);
mSearchView = actionbarLayout.findViewById(R.id.searchView);
mSearchView.setQuery(mQuery, false /* submitQuery */);
mSearchView.setOnQueryTextListener(this);
mSearchView.requestFocus();

return view;
}

// SearchFragment.java
@Override
public boolean onQueryTextChange(String query) {
if (TextUtils.equals(query, mQuery)) {
return true;
}
final boolean isEmptyQuery = TextUtils.isEmpty(query);

mNeverEnteredQuery = false;
mQuery = query;
mSearchAdapter.changQuery(mQuery);// If indexing is not finished, register the query text, but don't search.
if (!mSearchFeatureProvider.isIndexingComplete(getActivity())) {return true;
}if (isEmptyQuery) {// 更新视图mSearchAdapter.clearResults();mSearchAdapter.clearbackground();final LoaderManager loaderManager = getLoaderManager();loaderManager.destroyLoader(SearchCommon.SearchLoaderId.SEARCH_RESULT);mShowingSavedQuery = true;mSavedQueryController.loadSavedQueries();mSearchFeatureProvider.hideFeedbackButton(getView());
} else {mMetricsFeatureProvider.logEvent(SettingsIntelligenceEvent.PERFORM_SEARCH);// 重新启动加载器restartLoaders();
}return true;

}

// SearchFragment.java
private void restartLoaders() {
mShowingSavedQuery = false;
final LoaderManager loaderManager = getLoaderManager();
loaderManager.restartLoader(SearchCommon.SearchLoaderId.SEARCH_RESULT,
null /* args /, this / callback */);
}

// SearchFragment.java 创建 SearchResultLoader
@Override
public Loader<List<? extends SearchResult>> onCreateLoader(int id, Bundle args) {
final Activity activity = getActivity();

switch (id) {case SearchCommon.SearchLoaderId.SEARCH_RESULT:return mSearchFeatureProvider.getSearchResultLoader(activity, mQuery);default:return null;
}

}

// SearchFeatureProviderImpl.java
@Override
public SearchResultLoader getSearchResultLoader(Context context, String query) {
return new SearchResultLoader(context, cleanQuery(query));
}

public class SearchResultLoader extends AsyncLoader<List<? extends SearchResult>> {

@Override
public List<? extends SearchResult> loadInBackground() {
SearchResultAggregator aggregator = SearchResultAggregator.getInstance();
// 重点看 SearchResultAggregator 的 fetchResults 方法
return aggregator.fetchResults(getContext(), mQuery);
}

}

// SearchResultAggregator.java
public class SearchResultAggregator {

@NonNull
public synchronized List<? extends SearchResult> fetchResults(Context context, String query) {
final SearchFeatureProvider mFeatureProvider = FeatureFactory.get(context)
.searchFeatureProvider();
final ExecutorService executorService = mFeatureProvider.getExecutorService();

    // 获取异步任务并执行,具体 task 可查看 SearchFeatureProviderImpl.java 中的 getSearchQueryTasks 方法// 每个 task 的查询规则可自行查看final List<SearchQueryTask> tasks =mFeatureProvider.getSearchQueryTasks(context, query);// Start tasksfor (SearchQueryTask task : tasks) {executorService.execute(task);}// Collect resultsfinal Map<Integer, List<? extends SearchResult>> taskResults = new ArrayMap<>();final long allTasksStart = System.currentTimeMillis();for (SearchQueryTask task : tasks) {final int taskId = task.getTaskId();try {taskResults.put(taskId,task.get(SHORT_CHECK_TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS));} catch (TimeoutException | InterruptedException | ExecutionException e) {Log.d(TAG, "Could not retrieve result in time: " + taskId, e);taskResults.put(taskId, Collections.EMPTY_LIST);}}// Merge resultsfinal List<? extends SearchResult> mergedResults = mergeSearchResults(taskResults);// 返回搜索结果return mergedResults;
}// TODO (b/68255021) scale the dynamic search results ranks
private List<? extends SearchResult> mergeSearchResults(Map<Integer, List<? extends SearchResult>> taskResults) {final List<SearchResult> searchResults = new ArrayList<>();// First add db results as a special case// 添加 DatabaseResultTask 返回的数据searchResults.addAll(taskResults.remove(DatabaseResultTask.QUERY_WORKER_ID));// Merge the rest into result list: add everything to heap then pop them out one by one.final PriorityQueue<SearchResult> heap = new PriorityQueue<>();for (List<? extends SearchResult> taskResult : taskResults.values()) {heap.addAll(taskResult);}while (!heap.isEmpty()) {searchResults.add(heap.poll());}return searchResults;
}

}

// SearchFragment.java 数据加载完成后,渲染 UI
@Override
public void onLoadFinished(Loader<List<? extends SearchResult>> loader,
List<? extends SearchResult> data) {

mSearchAdapter.postSearchResults(data);
}

http://www.xdnf.cn/news/6699.html

相关文章:

  • 梦熊解析:202505基础算法
  • debugfs:Linux 内核调试的利器
  • 如何有效的开展接口自动化测试?
  • 今日行情明日机会——20250516
  • PMP-第十二章 项目采购管理
  • windows平台监控目录、子目录下的文件变化
  • 革新直流计量!安科瑞DJSF1352-D电表:360A免分流直连,精度与空间双突破
  • Linux远程连接服务
  • 1基·2台·3空间·6主体——蓝象智联解码可信数据空间的“数智密码”
  • 5 Celery多节点部署
  • c++,linux,多线程编程详细介绍
  • FC7300 ADC采样理论介绍
  • 宽河道流量监测——阵列雷达波测流系统如何监测河道流量
  • GTS-400 系列运动控制器板卡介绍(三十六)--- 电机到位检测功能
  • Ubuntu 22.04 上安装 Drupal 10并配置 Nginx, mysql 和 php
  • Java 多线程基础:Thread 类核心用法详解
  • E-R图合并时的三种冲突
  • SDT-5土体动力特性测试系统
  • 工具生态构建对比分析
  • 进阶-数据结构部分:1、数据结构入门
  • ASP.NET/IIS New StreamContent(context.Request.InputStream) 不会立即复制整个请求流的内容到内存
  • 什么是本地事务,什么是分布式事务
  • 【MATLAB例程】线性卡尔曼滤波的程序,三维状态量和观测量,较为简单,可用于理解多维KF,附代码下载链接
  • ESP32开发之freeRTOS的任务通知
  • OpenCV CUDA模块中矩阵操作------归一化与变换操作
  • window nvidia-smi命令 Failed to initialize NVML: Unknown Error
  • 【学习笔记】因果推理导论第1课
  • 3D一览通为山东融科MES系统补全车间看图能力
  • 车道线检测----CLRNet
  • Elasticsearch倒排索引核心原理面试题