Settings

Settings里搜索框的搜索流程

在这里插入图片描述
settings 里的 app info的搜索是单独的在InstalledAppResultTask 的query() 方法里,通过Settings.ACTION_APPLICATION_DETAILS_SETTINGS跳转

final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
        .setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
        .setData(
                Uri.fromParts(INTENT_SCHEME, info.packageName, null /* fragment */))

Settigs 中Search完整流程

一、Settigs 里的查找有好几种,有数据库,应用,设备,辅助服务等,如下:

  • 请添加图片描述

  • 除了数据库之外的其他几种都很直接,下面只看数据库的查找

  • 直接看adapter ,SearchResultsAdapter:

  • 1、设置viewHolder

    @Override
    public void onBindViewHolder(SearchViewHolder holder, int position) {
        holder.onBind(mFragment, mSearchResults.get(position));
    }
  • SearchViewHolder:
  • 2、给view设置图片文字等
    public void onBind(SearchFragment fragment, SearchResult result) {
        titleView.setText(result.title);
        // TODO (b/36101902) remove check for DYNAMIC_PLACEHOLDER
        if (TextUtils.isEmpty(result.summary)
                || TextUtils.equals(result.summary, mPlaceholderSummary)
                || TextUtils.equals(result.summary, DYNAMIC_PLACEHOLDER)) {
            summaryView.setVisibility(View.GONE);
        } else {
            summaryView.setText(result.summary);
            summaryView.setVisibility(View.VISIBLE);
        }

        if (result instanceof AppSearchResult) {
            AppSearchResult appResult = (AppSearchResult) result;
            PackageManager pm = fragment.getActivity().getPackageManager();
            iconView.setImageDrawable(appResult.info.loadIcon(pm));
        } else {
            // Valid even when result.icon is null.
            iconView.setImageDrawable(result.icon);
        }

        bindBreadcrumbView(result);
    }
  • 那么adapter的数据哪里来的呢?看SearchFragment:
  • Settings 3、得到搜索结果给adapter
    @Override
    public void onLoadFinished(Loader<List<? extends SearchResult>> loader,
            List<? extends SearchResult> data) {
        mSearchAdapter.postSearchResults(data);
    }
  • 这里的LoaderManager 是用来帮助方便查询的,具体可以看
  • https://developer.android.google.cn/reference/android/app/LoaderManager?hl=en
  • 先记住这个 Settings 4、mSearchFeatureProvider这里就是SearchFeatureProviderImpl,下面看这里的LoaderManager是如何查找到数据的
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mSearchFeatureProvider = FeatureFactory.get(context).searchFeatureProvider();
        mMetricsFeatureProvider = FeatureFactory.get(context).metricsFeatureProvider(context);
    }
  • restartLoaders() Settings 5、这里设置loadermanager后马上会走onCreateLoader,细节可以点进去看就可以:createAndInstallLoader。
    @Override
    public boolean onQueryTextChange(String query) {
        if (TextUtils.equals(query, mQuery)) {
            return true;
        }
        mEnterQueryTimestampMs = System.currentTimeMillis();
        final boolean isEmptyQuery = TextUtils.isEmpty(query);

        // Hide no-results-view when the new query is not a super-string of the previous
        if (mQuery != null
                && mNoResultsView.getVisibility() == View.VISIBLE
                && query.length() < mQuery.length()) {
            mNoResultsView.setVisibility(View.GONE);
        }

        mNeverEnteredQuery = false;
        mQuery = query;

        // If indexing is not finished, register the query text, but don't search.
        if (!mSearchFeatureProvider.isIndexingComplete(getActivity())) {
            return true;
        }
        

        if (isEmptyQuery) {
            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;
    }
  • LoaderManagerImpl:Settings 6、这里就是LoaderManager中转的地方
        void start() {
            if (mRetaining && mRetainingStarted) {
                // Our owner is started, but we were being retained from a
                // previous instance in the started state...  so there is really
                // nothing to do here, since the loaders are still started.
                mStarted = true;
                return;
            }

            if (mStarted) {
                // If loader already started, don't restart.
                return;
            }

            mStarted = true;
            
            if (DEBUG) Log.v(TAG, "  Starting: " + this);
            if (mLoader == null && mCallbacks != null) {
               mLoader = mCallbacks.onCreateLoader(mId, mArgs);
            }
            if (mLoader != null) {
                if (mLoader.getClass().isMemberClass()
                        && !Modifier.isStatic(mLoader.getClass().getModifiers())) {
                    throw new IllegalArgumentException(
                            "Object returned from onCreateLoader must not be a non-static inner member class: "
                            + mLoader);
                }
                if (!mListenerRegistered) {
                    mLoader.registerListener(mId, this);
                    mLoader.registerOnLoadCanceledListener(this);
                    mListenerRegistered = true;
                }
                mLoader.startLoading();//zsg 这个地方中转
            }
        }
  • AsyncLoader: Settings 7、开始执行Loader里的方法
    @Override
    protected void onStartLoading() {
        if (mResult != null) {
            deliverResult(mResult);
        }

        if (takeContentChanged() || mResult == null) {
            forceLoad();//zsg 这里
        }
    }
  • AsyncTaskLoader:Settings 8、这里是调用子类SearchResultLoader中的loadInBackground
        /* Runs on a worker thread */
        @Override
        protected D doInBackground(Void... params) {
            if (DEBUG) Log.v(TAG, this + " >>> doInBackground");
            try {
                D data = AsyncTaskLoader.this.onLoadInBackground();//zsg 这里
                if (DEBUG) Log.v(TAG, this + "  <<< doInBackground");
                return data;
            } catch (OperationCanceledException ex) {
                if (!isCancelled()) {
                    // onLoadInBackground threw a canceled exception spuriously.
                    // This is problematic because it means that the LoaderManager did not
                    // cancel the Loader itself and still expects to receive a result.
                    // Additionally, the Loader's own state will not have been updated to
                    // reflect the fact that the task was being canceled.
                    // So we treat this case as an unhandled exception.
                    throw ex;
                }
                if (DEBUG) Log.v(TAG, this + "  <<< doInBackground (was canceled)", ex);
                return null;
            }
        }
  • Loader:Settings 9、从AsyncTaskLoader里调用过来,最后调用到onLoadFinished。这里的listener就是LoaderManager
    public void deliverResult(D data) {
        if (mListener != null) {
            mListener.onLoadComplete(this, data);
        }
    }
  • SearchResultAggregator.java: Settings 10、开始执行SearchFeatureProviderImpl里的Task
    @NonNull
    public synchronized List<? extends SearchResult> fetchResults(Context context, String query) {
        final SearchFeatureProvider mFeatureProvider = FeatureFactory.get(context)
                .searchFeatureProvider();
        final ExecutorService executorService = mFeatureProvider.getExecutorService();

        final List<SearchQueryTask> tasks =
                mFeatureProvider.getSearchQueryTasks(context, query);
        // Start tasks
        for (SearchQueryTask task : tasks) {
            executorService.execute(task);//zsg 这里
        }
  • 上面就到了最开始截图部分的几个task了,也就是开始查询了,除了数据库之外都是直接查询的,但是数据库里的数据是哪里来的呢?
  • SearchFragment: Settings 11、updateIndexAsync 这里是最开始查找 所有contentprovide 生成数据库的地方
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        long startTime = System.currentTimeMillis();
        setHasOptionsMenu(true);

        final LoaderManager loaderManager = getLoaderManager();
        mSearchAdapter = new SearchResultsAdapter(this /* fragment */);
        mSavedQueryController = new SavedQueryController(
                getContext(), loaderManager, mSearchAdapter);
        mSearchFeatureProvider.initFeedbackButton();

        if (savedInstanceState != null) {
            mQuery = savedInstanceState.getString(SearchCommon.STATE_QUERY);
            mNeverEnteredQuery = savedInstanceState.getBoolean(SearchCommon.STATE_NEVER_ENTERED_QUERY);
            mShowingSavedQuery = savedInstanceState.getBoolean(SearchCommon.STATE_SHOWING_SAVED_QUERY);
        } else {
            mShowingSavedQuery = true;
        }
        mSearchFeatureProvider.updateIndexAsync(getContext(), this /* indexingCallback */);
        if (SearchFeatureProvider.DEBUG) {
            Log.d(TAG, "onCreate spent " + (System.currentTimeMillis() - startTime) + " ms");
        }
    }
  • DatabaseIndexingManager:Settings 12、这个里通过PROVIDER_INTERFACE 获取所有设置这个action的contentprovide
    public void performIndexing() {
        final Intent intent = new Intent(SearchIndexablesContract.PROVIDER_INTERFACE);
        final List<ResolveInfo> providers =
                mContext.getPackageManager().queryIntentContentProviders(intent, 0);

        final boolean isFullIndex = IndexDatabaseHelper.isFullIndex(mContext, providers);

        if (isFullIndex) {
            rebuildDatabase();
        }

        PreIndexData indexData = getIndexDataFromProviders(providers, isFullIndex);//zsg 这里

        final long updateDatabaseStartTime = System.currentTimeMillis();
        updateDatabase(indexData, isFullIndex);
        IndexDatabaseHelper.setIndexed(mContext, providers);
        if (DEBUG) {
            final long updateDatabaseTime = System.currentTimeMillis() - updateDatabaseStartTime;
            Log.d(TAG, "performIndexing updateDatabase took time: " + updateDatabaseTime);
        }
    }
  • PreIndexDataCollector: Settings 13、创建URI后通过getIndexablesForRawDataUri获取数据
    private void addIndexablesFromRemoteProvider(String packageName, String authority) {
        try {
            final Context context = mContext.createPackageContext(packageName, 0);

            final Uri uriForResources = buildUriForXmlResources(authority);
            mIndexData.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));

            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));
        }
    }
  • 这里就会去查询对应的contentprovide,以Settings的contentprovide为例
  • SearchIndexablesProvider: Settings 14、这里在framework里调用对应contentprovide的query
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
                        String sortOrder) {
        try {
            switch (mMatcher.match(uri)) {
                case MATCH_RES_CODE:
                    return queryXmlResources(null);
                case MATCH_RAW_CODE:
                    return queryRawData(null);
                case MATCH_NON_INDEXABLE_KEYS_CODE:
                    return queryNonIndexableKeys(null);
                case MATCH_SITE_MAP_PAIRS_CODE:
                    return querySiteMapPairs();
                case MATCH_SLICE_URI_PAIRS_CODE:
                    return querySliceUriPairs();
                case MATCH_DYNAMIC_RAW_CODE:
                    return queryDynamicRawData(null);
                default:
                    throw new UnsupportedOperationException("Unknown Uri " + uri);
            }
        } catch (UnsupportedOperationException e) {
            throw e;
        } catch (Exception e) {
            Log.e(TAG, "Provider querying exception:", e);
            return null;
        }
    }
  • SettingsSearchIndexablesProvider: Settings 15、最后调用到settings 里设置的用来搜索的BaseSearchIndexProvider ,这个不是contentprovide,只是继承了settinglib里的SearchIndexProvider接口,用来注解生成代码
    private List<SearchIndexableRaw> getSearchIndexableRawFromProvider(Context context) {
        final Collection<SearchIndexableData> bundles = FeatureFactory.getFactory(context)
                .getSearchFeatureProvider().getSearchIndexableResources().getProviderValues();
        final List<SearchIndexableRaw> rawList = new ArrayList<>();

        for (SearchIndexableData bundle : bundles) {
            Indexable.SearchIndexProvider provider = bundle.getSearchIndexProvider();
            final List<SearchIndexableRaw> providerRaws = provider.getRawDataToIndex(context,
                    true /* enabled */);//zsg 这里

            if (providerRaws == null) {
                continue;
            }

            for (SearchIndexableRaw raw : providerRaws) {
                // The classname and intent information comes from the PreIndexData
                // This will be more clear when provider conversion is done at PreIndex time.
                raw.className = bundle.getTargetClass().getName();
            }
            rawList.addAll(providerRaws);
        }

        return rawList;
    }

二、setting数据库查看到底被 哪个进程修改了

settings 里设置的值如何在手机里查看,可以看是某个app设置的

/data/system/users/0/settings_secure.xml
/data/system/users/0/settings_global.xml
/data/system/users/0/settings_global.xml
例如:

<setting id="64" name="keyboard_backlight_enable" value="0" package="android" defaultValue="0" defaultSysSet="true" />
  <setting id="89" name="user_setup_personalization_state" value="0" package="com.google.android.setupwizard" defaultValue="0" defaultSysSet="true" />
  <setting id="98" name="clock_seconds" package="com.android.systemui" />

/data/system/users/0/appwidgets.xml
widgets的存放路径

adb设置settings 数据库
adb shell settings put global device_provisioning_mobile_data 1

三、settings中通过action跳转页面

action 界面
ACTION_SETTINGS 系统设置界面
ACTION_APN_SETTINGS APN设置界面
ACTION_LOCATION_SOURCE_SETTINGS 定位设置界面
ACTION_AIRPLANE_MODE_SETTINGS 更多连接方式设置界面
ACTION_DATA_ROAMING_SETTINGS 双卡和移动网络设置界面
ACTION_ACCESSIBILITY_SETTINGS 无障碍设置界面/辅助功能界面
ACTION_SYNC_SETTINGS 同步设置界面
ACTION_ADD_ACCOUNT 添加账户界面
ACTION_NETWORK_OPERATOR_SETTINGS 选取运营商的界面
ACTION_SECURITY_SETTINGS 安全设置界面
ACTION_PRIVACY_SETTINGS 备份重置设置界面
ACTION_VPN_SETTINGS VPN设置界面,可能不存在
ACTION_WIFI_SETTINGS 无线网设置界面
ACTION_WIFI_IP_SETTINGS WIFI的IP设置
ACTION_BLUETOOTH_SETTINGS 蓝牙设置
ACTION_CAST_SETTINGS 投射设置
ACTION_DATE_SETTINGS 日期时间设置
ACTION_SOUND_SETTINGS 声音设置
ACTION_DISPLAY_SETTINGS 显示设置
ACTION_LOCALE_SETTINGS 语言设置
ACTION_VOICE_INPUT_SETTINGS 辅助应用和语音输入设置
ACTION_INPUT_METHOD_SETTINGS 语言和输入法设置
ACTION_USER_DICTIONARY_SETTINGS 个人字典设置界面
ACTION_INTERNAL_STORAGE_SETTINGS 存储空间设置的界面
ACTION_SEARCH_SETTINGS 搜索设置界面
ACTION_APPLICATION_DEVELOPMENT_SETTINGS 开发者选项
ACTION_DEVICE_INFO_SETTINGS 手机状态信息的界面
ACTION_DREAM_SETTINGS 互动屏保设置的界面
ACTION_NOTIFICATION_LISTENER_SETTINGS 通知使用权设置的界面
ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS 勿扰权限设置的界面
ACTION_CAPTIONING_SETTINGS 字幕设置的界面
ACTION_PRINT_SETTINGS 打印设置界面
ACTION_BATTERY_SAVER_SETTINGS 节电助手界面
ACTION_HOME_SETTINGS 主屏幕设置界面
ACTION_APPLICATION_DETAILS_SETTINGS 根据包名跳转到系统自带的应用程序信息
ACTION_APPLICATION_SETTINGS 应用程序列表
ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS 应用程序界面【所有的】
ACTION_MANAGE_APPLICATIONS_SETTINGS 应用程序列表界面【已安装的】
ACTION_INPUT_METHOD_SUBTYPE_SETTINGS 【API 11及以上】语言选择界面 【多国语言选择】
ACTION_NFCSHARING_SETTINGS 显示NFC共享设置【API 14及以上】
ACTION_NFC_SETTINGS 显示NFC设置【API 16及以上】
ACTION_QUICK_LAUNCH_SETTINGS 快速启动设置界面

其中,根据包名跳转到系统自带的应用程序信息界面的方式为:

Uri packageURI = Uri.parse(“package:” + “com.tencent.WBlog”);
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,packageURI);
startIntent(intent);

其他的跳转均可采用:

Intent intent = new Intent(Settings.***);
startIntent(intent);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值