Android 7.1 Settings详解

最近一直在看settings的问题,觉得不错,就研究了下,写出来方便以后查找问题,不用每次都去重新看,如有不对的地方,欢迎纠正。
在Android N 上Settings是带有侧拉菜单的,我们先从界面的角度大致看下Settings是怎么显示出来,然后再看下view对应的数据是如何加载而来的,先来看看设置的界面如下:
图一
从图片可以看出主界面有点类似listview的感觉,只不过所有的item分为四类,依次为无线和网络、设备、个人、系统,接着我们就从源码的角度看下界面是如何显示出来的。Settings源码分为两个部分,分别为
“packages/apps/Settings”和“frameworks/base/packages/SettingsLib”,主界面对应的布局文件如下:

frameworks/base/packages/SettingsLib/res/layout/settings_with_drawer.xml
    <android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?android:attr/colorPrimaryDark">
    <!-- 设置主界面 -->
    <LinearLayout
        android:id="@+id/content_parent"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:fitsSystemWindows="true" >
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            style="?android:attr/actionBarStyle">
            <Toolbar
                xmlns:android="http://schemas.android.com/apk/res/android"
                android:id="@+id/action_bar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:navigationContentDescription="@*android:string/action_bar_up_description"
                android:theme="?android:attr/actionBarTheme"
                style="?android:attr/toolbarStyle"
                android:background="?android:attr/colorPrimary" />
        </FrameLayout>
        <FrameLayout
            android:id="@+id/content_header_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            style="?android:attr/actionBarStyle" />
        <FrameLayout
            android:id="@+id/content_frame"
            android:layout_width="match_parent"
            android:layout_height="fill_parent"
            android:background="?android:attr/windowBackground" />
    </LinearLayout>
    <!-- 侧拉抽屉 -->
    <ListView android:id="@+id/left_drawer"
        android:layout_width="300dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:background="?android:attr/colorBackground" />
    </android.support.v4.widget.DrawerLayout>

从布局文件可看出,整个布局为DrawerLayout,主界面为一个FrameLayout,还有个left_drawer对应侧边的侧滑栏,界面显示如下:
设置侧拉菜单
左边的侧滑栏比较简单就不罗嗦了,主要看下settings主界面是如何显示出来的,设置主界面入口为SettingsActivity.java是SettingsDrawerActivity.java的子类

packages/apps/Settings/src/com/android/settings/SettingsActivity.java
    @Override
    protected void onCreate(Bundle savedState) {
        super.onCreate(savedState);

        ...
        setContentView(mIsShowingDashboard ?
                R.layout.settings_main_dashboard : R.layout.settings_main_prefs);加载主界面,为一个fragment

        mContent = (ViewGroup) findViewById(R.id.main_content);

        getFragmentManager().addOnBackStackChangedListener(this);


        if (savedState != null) {
            // We are restarting from a previous saved state; used that to initialize, instead
            // of starting fresh.
            mSearchMenuItemExpanded = savedState.getBoolean(SAVE_KEY_SEARCH_MENU_EXPANDED);
            mSearchQuery = savedState.getString(SAVE_KEY_SEARCH_QUERY);
            setTitleFromIntent(intent);

            ArrayList<DashboardCategory> categories =
                    savedState.getParcelableArrayList(SAVE_KEY_CATEGORIES);
            if (categories != null) {
                mCategories.clear();
                mCategories.addAll(categories);
                setTitleFromBackStack();
            }

            mDisplayHomeAsUpEnabled = savedState.getBoolean(SAVE_KEY_SHOW_HOME_AS_UP);
            mDisplaySearch = savedState.getBoolean(SAVE_KEY_SHOW_SEARCH);

        } else {
            if (!mIsShowingDashboard) {
                mDisplaySearch = false;
                // UP will be shown only if it is a sub settings
                if (mIsShortcut) {
                    mDisplayHomeAsUpEnabled = isSubSettings;
                } else if (isSubSettings) {
                    mDisplayHomeAsUpEnabled = true;
                } else {
                    mDisplayHomeAsUpEnabled = false;
                }
                setTitleFromIntent(intent);

                Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
                switchToFragment(initialFragmentName, initialArguments, true, false,
                        mInitialTitleResId, mInitialTitle, false);
            } else {
                // No UP affordance if we are displaying the main Dashboard
                mDisplayHomeAsUpEnabled = false;
                // Show Search affordance
                mDisplaySearch = true;
                mInitialTitleResId = R.string.dashboard_title;

                // add argument to indicate which settings tab should be initially selected
                final Bundle args = new Bundle();
                final String extraName = DashboardContainerFragment.EXTRA_SELECT_SETTINGS_TAB;
                args.putString(extraName, intent.getStringExtra(extraName));

                switchToFragment(DashboardContainerFragment.class.getName(), args, false, false,mInitialTitleResId, mInitialTitle, false);切换到DashboardContainerFragment
            }
        }
        ...
    }

在onCreate中加载了一个R.layout.settings_main_dashboard,布局文件很简单里面就一个FrameLayout,然后通过
switchToFragment,切换到DashboardContainerFragment,需要注意的是在调用switchToFragment切换到DashboardContainerFragment之前会检查Fragment是否有效,通过判断当前fragmentName是否为SettingsActivity.ENTRY_FRAGMENTS数组里定义的,否则会抛出IllegalArgumentException “Invalid fragment for this activity: “,到这里我们继续接着DashboardContainerFragment分析,DashboardContainerFragment的onCreateView如下:

packages/apps/Settings/src/com/android/settings/dashboard/DashboardContainerFragment.java
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        final View content = inflater.inflate(R.layout.dashboard_container, parent, false);加载一个自定义的viewpager
        mViewPager = (RtlCompatibleViewPager) content.findViewById(R.id.pager);
        mPagerAdapter = new DashboardViewPagerAdapter(getContext(),
                getChildFragmentManager(), mViewPager);
        mViewPager.setAdapter(mPagerAdapter);
        mViewPager.addOnPageChangeListener(
                new TabChangeListener((SettingsActivity) getActivity()));

        // check if support tab needs to be selected
        final String selectedTab = getArguments().
            getString(EXTRA_SELECT_SETTINGS_TAB, ARG_SUMMARY_TAB);
        if (TextUtils.equals(selectedTab, ARG_SUPPORT_TAB)) {
            mViewPager.setCurrentItem(INDEX_SUPPORT_FRAGMENT);
        } else {
            mViewPager.setCurrentItem(INDEX_SUMMARY_FRAGMENT);
        }

        mHeaderView = inflater.inflate(R.layout.dashboard_container_header, parent, false);
        ((SlidingTabLayout) mHeaderView).setViewPager(mViewPager);
        return content;
    }

加载了一个RtlCompatibleViewPager,然后设置adapter为DashboardViewPagerAdapter,addOnPageChangeListener为TabChangeListener,DashboardViewPagerAdapter为FragmentPagerAdapter的子类,其实现如下:

packages/apps/Settings/src/com/android/settings/dashboard/DashboardContainerFragment.java
    private static final class DashboardViewPagerAdapter extends FragmentPagerAdapter {

        private final Context mContext;
        private final SupportFeatureProvider mSupportFeatureProvider;
        private final RtlCompatibleViewPager mViewPager;

        public DashboardViewPagerAdapter(Context context, FragmentManager fragmentManager,
                RtlCompatibleViewPager viewPager) {
            super(fragmentManager);
            mContext = context;
            mSupportFeatureProvider =
                    FeatureFactory.getFactory(context).getSupportFeatureProvider(context);
            mViewPager = viewPager;
        }

        @Override
        public CharSequence getPageTitle(int position) {
            switch (position) {
                case INDEX_SUMMARY_FRAGMENT:
                    return mContext.getString(R.string.page_tab_title_summary);
                case INDEX_SUPPORT_FRAGMENT:
                    return mContext.getString(R.string.page_tab_title_support);
            }
            return super.getPageTitle(position);
        }

        @Override
        public Fragment getItem(int position) {
            switch (position) {返回DashboardSummary
                case INDEX_SUMMARY_FRAGMENT:
                    return new DashboardSummary();
                case INDEX_SUPPORT_FRAGMENT:
                    return new SupportFragment();
                default:
                    throw new IllegalArgumentException(
                            String.format(
                                    "Position %d does not map to a valid dashboard fragment",
                                    position));
            }
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            return super.instantiateItem(container,
                    mViewPager.getRtlAwareIndex(position));
        }

        @Override
        public int getCount() {
            return mSupportFeatureProvider == null ? 1 : 2;
        }
    }

mSupportFeatureProvider为null,默认只有一页即显示DashboardSummary,在DashboardSummary@onCreateView里填充了R.layout.dashboard,这个布局文件主要包含一个FocusRecyclerView

packages/apps/Settings/src/com/android/settings/dashboard/DashboardSummary.java
    @Override
    public void onViewCreated(View view, Bundle bundle) {
        long startTime = System.currentTimeMillis();
        mDashboard = (FocusRecyclerView) view.findViewById(R.id.dashboard_container);
        mLayoutManager = new LinearLayoutManager(getContext());
        mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        if (bundle != null) {
            int scrollPosition = bundle.getInt(EXTRA_SCROLL_POSITION);
            mLayoutManager.scrollToPosition(scrollPosition);
        }
        mDashboard.setLayoutManager(mLayoutManager);
        mDashboard.setHasFixedSize(true);
        mDashboard.setListener(this);
        mDashboard.addItemDecoration(new DashboardDecorator(getContext()));设置分割线
        mAdapter = new DashboardAdapter(getContext(), mSuggestionParser, bundle,
                mConditionManager.getConditions());
        mDashboard.setAdapter(mAdapter);设置adapter
        mSummaryLoader.setAdapter(mAdapter);
        ConditionAdapterUtils.addDismiss(mDashboard);
        if (DEBUG_TIMING) Log.d(TAG, "onViewCreated took "
                + (System.currentTimeMillis() - startTime) + " ms");
        rebuildUI();
    }

在这儿设置RecyclerView的setLayoutManager为垂直线性布局,设置adapter为DashboardAdapter以及rebuildUI,接下来主要看下DashboardAdapter,DashboardAdapter为RecyclerView.Adapter的子类,通过onCreateViewHolder和onBindViewHolder来创建和显示view

packages/apps/Settings/src/com/android/settings/dashboard/DashboardAdapter.java

    @Override
    public DashboardItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new DashboardItemHolder(LayoutInflater.from(parent.getContext()).inflate(
                viewType, parent, false), (viewType == R.layout.dashboard_tile_switch));
    }

    @Override
    public void onBindViewHolder(DashboardItemHolder holder, int position) {
        switch (mTypes.get(position)) {
            case R.layout.dashboard_category:对应类别
                onBindCategory(holder, (DashboardCategory) mItems.get(position));
                break;
            case R.layout.dashboard_tile:对应每个子item
                final Tile tile = (Tile) mItems.get(position);
                onBindTile(holder, tile);
                holder.itemView.setTag(tile);
                holder.itemView.setOnClickListener(this);
                break;
            case R.layout.dashboard_tile_switch:
                final Tile tileSitch = (Tile) mItems.get(position);
                mLte4GEnablerHolder = holder;
                onBindTile(holder, tileSitch);
                holder.itemView.setOnClickListener(this);
                mSw = (Switch) holder.itemView.findViewById(R.id.switchWidget);
                mLte4GEnabler.setSwitch(mSw);
                holder.itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                       mSw.setChecked(!mSw.isChecked());
                       set4GEnableSummary(mSw.isChecked());
                    }
                });
                updateLte4GEnabler();
                break;
            case R.layout.suggestion_header:
                onBindSuggestionHeader(holder);
                break;
            case R.layout.suggestion_tile:
                final Tile suggestion = (Tile) mItems.get(position);
                onBindTile(holder, suggestion);
                holder.itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        MetricsLogger.action(mContext, MetricsEvent.ACTION_SETTINGS_SUGGESTION,
                                DashboardAdapter.getSuggestionIdentifier(mContext, suggestion));
                        ((SettingsActivity) mContext).startSuggestion(suggestion.intent);
                    }
                });
                holder.itemView.findViewById(R.id.overflow).setOnClickListener(
                        new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                showRemoveOption(v, suggestion);
                            }
                        });
                break;
            case R.layout.see_all:
                onBindSeeAll(holder);
                break;
            case R.layout.condition_card:
                ConditionAdapterUtils.bindViews((Condition) mItems.get(position), holder,
                        mItems.get(position) == mExpandedCondition, this,
                        new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                onExpandClick(v);
                            }
                        });
                break;
        }
    }

    @Override
    public int getItemViewType(int position) {
        return mTypes.get(position);
    }

    @Override
    public int getItemCount() {
        return mIds.size();
    }

在onBindViewHolder中通过type类型来创建不同的view类型并设置相应的点击事件R.layout.dashboard_category,对应着前面提到的四种类别(无线和网络、设备、个人、系统),R.layout.dashboard_tile对应着每个类别下的item(WLAN、蓝牙、流量使用情况等),每个item点击后,会调用 ((SettingsActivity) mContext).openTile((Tile) v.getTag())跳转到对应的界面,讲到这整个界面的显示就说的差不多了,接下来看下界面对应的数据是怎么来的。
在DashboardSummary@rebuildUI里会调用DashboardAdapter@setCategories的

packages/apps/Settings/src/com/android/settings/dashboard/DashboardAdapter.java
    public void setCategories(List<DashboardCategory> categories) {
        mCategories = categories;

        // TODO: Better place for tinting?
        TypedValue tintColor = new TypedValue();
        mContext.getTheme().resolveAttribute(com.android.internal.R.attr.colorAccent,
                tintColor, true);
        for (int i = 0; i < categories.size(); i++) {
            for (int j = 0; j < categories.get(i).tiles.size(); j++) {
                Tile tile = categories.get(i).tiles.get(j);

                if (!mContext.getPackageName().equals(
                        tile.intent.getComponent().getPackageName())) {
                    // If this drawable is coming from outside Settings, tint it to match the
                    // color.
                    tile.icon.setTint(tintColor.data);
                }
            }
        }
        recountItems();  //根据categories重新构建item,为DashboardAdapter提供数据
    }
    private void recountItems() {
        reset();
        boolean hasConditions = false;
        for (int i = 0; mConditions != null && i < mConditions.size(); i++) {
            boolean shouldShow = mConditions.get(i).shouldShow();
            hasConditions |= shouldShow;
            countItem(mConditions.get(i), R.layout.condition_card, shouldShow, NS_CONDITION);
        }
        boolean hasSuggestions = mSuggestions != null && mSuggestions.size() != 0;
        countItem(null, R.layout.dashboard_spacer, hasConditions && hasSuggestions, NS_SPACER);
        countItem(null, R.layout.suggestion_header, hasSuggestions, NS_SPACER);
        resetCount();
        if (mSuggestions != null) {
            int maxSuggestions = getDisplayableSuggestionCount();
            for (int i = 0; i < mSuggestions.size(); i++) {
                countItem(mSuggestions.get(i), R.layout.suggestion_tile, i < maxSuggestions,
                        NS_SUGGESTION);
            }
        }
        resetCount();
        for (int i = 0; mCategories != null && i < mCategories.size(); i++) {
            DashboardCategory category = mCategories.get(i);
            countItem(category, R.layout.dashboard_category, mIsShowingAll, NS_ITEMS);
            for (int j = 0; j < category.tiles.size(); j++) {
                Tile tile = category.tiles.get(j);
                if (tile.intent.getComponent().getClassName().contains(LTE_4G_ACTIVITY)) {
                    countItem(tile, R.layout.dashboard_tile_switch, mIsShowingAll ||
                            ArrayUtils.contains(DashboardSummary.INITIAL_ITEMS,
                            tile.intent.getComponent().getClassName()), NS_ITEMS);
                } else {
                        countItem(tile, R.layout.dashboard_tile, mIsShowingAll
                            || ArrayUtils.contains(DashboardSummary.INITIAL_ITEMS,
                            tile.intent.getComponent().getClassName()), NS_ITEMS);
                    }
                }
            }
        }
        notifyDataSetChanged();
    }

那么DashboardAdapter@setCategories(List <DashboardCategory> categories) 传入的categories从何而来来呢

    private void rebuildUI() {
        if (!isAdded()) {
            Log.w(TAG, "Cannot build the DashboardSummary UI yet as the Fragment is not added");
            return;
        }

        List<DashboardCategory> categories =
                ((SettingsActivity) getActivity()).getDashboardCategories();
        mAdapter.setCategories(categories);

        // recheck to see if any suggestions have been changed.
        new SuggestionLoader().execute();
    }

在DashboardSummary@rebuildUI中我们知道,categories是调用SettingsActivity的方法获取的,getDashboardCategories这个方法是定义在SettingsActivity的父类SettingsDrawerActivity.java里定义的,如下:

frameworks/base/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
    public List<DashboardCategory> getDashboardCategories() {
        if (sDashboardCategories == null) {
            sTileCache = new HashMap<>();
            sConfigTracker = new InterestingConfigChanges();
            // Apply initial current config.
            sConfigTracker.applyNewConfig(getResources());
            sDashboardCategories = TileUtils.getCategories(this, sTileCache);
        }
        return sDashboardCategories;
    }

sDashboardCategories是通过TileUtils.getCategories赋值的,接着我们继续跟下这个方法

frameworks/base/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
    public static List<DashboardCategory> getCategories(Context context,
            HashMap<Pair<String, String>, Tile> cache) {
        final long startTime = System.currentTimeMillis();
        boolean setup = Global.getInt(context.getContentResolver(), Global.DEVICE_PROVISIONED, 0)
                != 0;
        ArrayList<Tile> tiles = new ArrayList<>();
        UserManager userManager = UserManager.get(context);
        for (UserHandle user : userManager.getUserProfiles()) {
            // TODO: Needs much optimization, too many PM queries going on here.
            if (user.getIdentifier() == ActivityManager.getCurrentUser()) {
                // Only add Settings for this user.
                //解析AndroidManifest.xml
                getTilesForAction(context, user, SETTINGS_ACTION, cache, null, tiles, true);
                getTilesForAction(context, user, OPERATOR_SETTINGS, cache,
                        OPERATOR_DEFAULT_CATEGORY, tiles, false);
                getTilesForAction(context, user, MANUFACTURER_SETTINGS, cache,
                        MANUFACTURER_DEFAULT_CATEGORY, tiles, false);
            }
            if (setup) {
                getTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, null, tiles, false);
            }
        }
        HashMap<String, DashboardCategory> categoryMap = new HashMap<>();
        for (Tile tile : tiles) {
            DashboardCategory category = categoryMap.get(tile.category);
            if (category == null) {
                //通过已有的category作为action去查找DashboardCategory,即(无线网络、设备、个人、系统)
                category = createCategory(context, tile.category);
                if (category == null) {
                    Log.w(LOG_TAG, "Couldn't find category " + tile.category);
                    continue;
                }
                categoryMap.put(category.key, category);
            }
            category.addTile(tile);
        }
        ArrayList<DashboardCategory> categories = new ArrayList<>(categoryMap.values());
        for (DashboardCategory category : categories) {
            Collections.sort(category.tiles, TILE_COMPARATOR);
        }
        Collections.sort(categories, CATEGORY_COMPARATOR);
        if (DEBUG_TIMING) Log.d(LOG_TAG, "getCategories took "
                + (System.currentTimeMillis() - startTime) + " ms");
        return categories;
    }

在这个方法中主要通过getTilesForIntent获取所有的Tile,其实主要就是通过PackageManager@queryIntentActivitiesAsUser通过传入的intnet解析AndroidManifest.xml配置的每项,解析设置中每个item(WLAN、蓝牙、流量使用情况、显示、通知…)

frameworks/base/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
    public static void getTilesForIntent(Context context, UserHandle user, Intent intent,
            Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles,
            boolean usePriority, boolean checkCategory) {
        PackageManager pm = context.getPackageManager();
         /*<action android:name="com.android.settings.action.SETTINGS" /> 根据action去查找所有匹配的项*/
        List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent,
                PackageManager.GET_META_DATA, user.getIdentifier());
        for (ResolveInfo resolved : results) {
            if (!resolved.system) {
                // Do not allow any app to add to settings, only system ones.
                continue;
            }
            ActivityInfo activityInfo = resolved.activityInfo;
            /*解析xml中的meta-data节点*/
            Bundle metaData = activityInfo.metaData;
            String categoryKey = defaultCategory;
            if (checkCategory && ((metaData == null) || !metaData.containsKey(EXTRA_CATEGORY_KEY))
                    && categoryKey == null) {
                Log.w(LOG_TAG, "Found " + resolved.activityInfo.name + " for intent "
                        + intent + " missing metadata "
                        + (metaData == null ? "" : EXTRA_CATEGORY_KEY));
                continue;
            } else {
                categoryKey = metaData.getString(EXTRA_CATEGORY_KEY);
            }
            Pair<String, String> key = new Pair<String, String>(activityInfo.packageName,
                    activityInfo.name);
            Tile tile = addedCache.get(key);
            if (tile == null) {
                tile = new Tile();
                tile.intent = new Intent().setClassName(
                        activityInfo.packageName, activityInfo.name);
                tile.category = categoryKey;
                tile.priority = usePriority ? resolved.priority : 0;
                tile.metaData = activityInfo.metaData;
                updateTileData(context, tile, activityInfo, activityInfo.applicationInfo,
                        pm);
                if (DEBUG) Log.d(LOG_TAG, "Adding tile " + tile.title);

                addedCache.put(key, tile);
            }
            if (!tile.userHandle.contains(user)) {
                tile.userHandle.add(user);
            }
            if (!outTiles.contains(tile)) {
                outTiles.add(tile);
            }
        }
    }

对应解析的文件如下:

  packages/apps/Settings/AndroidManifest.xml
    <activity android:name="Settings$WifiSettingsActivity"
            android:taskAffinity=""
            android:label="@string/wifi_settings"
            android:icon="@drawable/ic_settings_wireless"
            android:configChanges="orientation|keyboardHidden|screenSize">
        <intent-filter android:priority="1">
            <action android:name="android.settings.WIFI_SETTINGS" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.VOICE_LAUNCH" />
            <category android:name="com.android.settings.SHORTCUT" />
        </intent-filter>
        <intent-filter android:priority="4">
            <action android:name="com.android.settings.action.SETTINGS" />
        </intent-filter>
        <meta-data android:name="com.android.settings.category"
            android:value="com.android.settings.category.wireless" />
        <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
            android:value="com.android.settings.wifi.WifiSettings" />
        <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
            android:value="true" />
    </activity>

解析并创建对应类别,如无线和网络,设备、个人、系统

frameworks/base/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
     private static DashboardCategory createCategory(Context context, String categoryKey) {
        DashboardCategory category = new DashboardCategory();
        category.key = categoryKey;
        PackageManager pm = context.getPackageManager();
        List<ResolveInfo> results = pm.queryIntentActivities(new Intent(categoryKey), 0);
        if (results.size() == 0) {
            return null;
        }
        for (ResolveInfo resolved : results) {
            if (!resolved.system) {
                // Do not allow any app to add to settings, only system ones.
                continue;
            }
            category.title = resolved.activityInfo.loadLabel(pm);
            category.priority = SETTING_PKG.equals(
                    resolved.activityInfo.applicationInfo.packageName) ? resolved.priority : 0;
            if (DEBUG) Log.d(LOG_TAG, "Adding category " + category.title +" ,categoryKey="+categoryKey);
        }

        return category;
    }

对应解析的xml文件

 packages/apps/Settings/AndroidManifest.xml
    <activity android:name=".Settings$WirelessSettings"
            android:label="@string/header_category_wireless_networks">
            <intent-filter android:priority="4">
                <action android:name="com.android.settings.category.wireless" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
    </activity>

所有的data都是通过解析AndroidManifest.xml文件,然后把对应数据显示在界面的,讲到这就分解的差不多了,简单总结下:
1、设置对应的界面是SettingsActivity extends SettingsDrawerActivity,在SettingsActivity最后是加载了DashboardSummary,这个fragment加载了一个FocusRecyclerView,并设置adapter为DashboardAdapter
2、DashboardAdapter的数据是通过TileUtils@getCategories里的getTilesForAction和createCategory解析AndroidManifest.xml文件,返回List < DashboardCategory >供DashboardAdapter使用

发布了104 篇原创文章 · 获赞 124 · 访问量 40万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览