要想了解setting,首先要对Preference的使用有一定的了解。
这里我参考官方文档过了一遍。
设置
首先,在gradle中添加依赖,这个可以通过project structure去添加。
![](https://img.haomeiwen.com/i4264767/6c11104e0b7fee9f.png)
我这里添加如下所示。
implementation 'androidx.preference:preference:1.1.0'
然后,在 res/xml/ 目录下新建一个文件preferences.xml。
<PreferenceScreen
xmlns:app="http://schemas.android.com/apk/res-auto">
<SwitchPreferenceCompat
app:key="notifications"
app:title="Enable message notifications"/>
<Preference
app:key="feedback"
app:title="Send feedback"
app:summary="Report technical issues or suggest new features"/>
</PreferenceScreen>
预览图如下所示:
![](https://img.haomeiwen.com/i4264767/0cbbe6d02488b8a7.png)
然后就是,这个xml文件的使用。
首先,需要新建一个继承PreferenceFragmentCompat的Fragment。这里新建了一个MySettingsFragment。
public class MySettingsFragment extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.preferences, rootKey);
}
}
MainActivity如下所示。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.settings_container, new MySettingsFragment())
.commit();
}
}
activity_main具体如下。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/settings_container"/>
</FrameLayout>
Preference的简单使用就基本是这样了。
如果修改preferences.xml,给SwitchPreferenceCompat和Preference分别套上PreferenceCategory,改为如下所示
<PreferenceScreen
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
app:key="notifications_category"
app:title="Notifications">
<SwitchPreferenceCompat
app:key="notifications"
app:title="Enable message notifications"/>
</PreferenceCategory>
<PreferenceCategory
app:key="help_category"
app:title="Help">
<Preference
app:key="feedback"
app:summary="Report technical issues or suggest new features"
app:title="Send feedback"/>
</PreferenceCategory>
</PreferenceScreen>
结果就会如下所示。
![](https://img.haomeiwen.com/i4264767/5d55de8bba74baa8.png)
如果想要使点击Preference后显示新的界面,可以在Preference下添加app:fragment="com.example.myapplication.xxx",或者使用Preference.setFragment()
首先,把preferences.xml改成如下所示。
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<Preference
app:fragment="com.example.myapplication.MessageFragment"
app:key="message_key"
app:title="message"
app:summary="AAAAAA"/>
<Preference
app:fragment="com.example.myapplication.SyncFragment"
app:key="sync_key"
app:title="sync"
app:summary="BBBBB"/>
</PreferenceScreen>
然后,新建MessageFragment和SyncFragment。
public class MessageFragment extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.preferences_message, rootKey);
}
}
public class SyncFragment extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.preferences_sync, rootKey);
}
}
preferences_message和preferences_sync分别如下所示。
<PreferenceScreen
xmlns:app="http://schemas.android.com/apk/res-auto">
<SwitchPreferenceCompat
app:key="message1"
app:title="1"/>
<Preference
app:key="message2"
app:title="2"
app:summary="CCC"/>
</PreferenceScreen>
<PreferenceScreen
xmlns:app="http://schemas.android.com/apk/res-auto">
<SwitchPreferenceCompat
app:key="sync1"
app:title="3"/>
<Preference
app:key="sync2"
app:title="4"
app:summary="SSSS"/>
</PreferenceScreen>
这样就实现了嵌套fragment。
结果就类似这种,一开始显示preferences.xml中定义的内容,点击不同的Preference后会显示不同的界面。
![](https://img.haomeiwen.com/i4264767/d999e023a8f46c0d.png)
Preference常用的属性
title
表示 Preference 标题的 String 值。
示例:app:title="Title"
summary
表示 Preference 摘要的 String 值。
示例:app:summary="Summary"
icon
表示 Preference 图标的 Drawable 。
示例:app:icon="@drawable/ic_camera"
key
String 值,表示用于保留关联 Preference 值的密钥。 使用密钥,您可以在运行时进一步自定义 Preference。 您应为层次结构中的每个 Preference 设置密钥。
示例:app:key="key"
打开Android设备中的setting界面,然后打开hierarchy view工具,点击com.android.settings.Settings。
![](https://img.haomeiwen.com/i4264767/33ba22066543bd55.png)
然后tree view中会显示界面构成。
![](https://img.haomeiwen.com/i4264767/b56fd9ef0f0f2579.png)
如果tree view没有正常显示,首先确定设备是否可以使用hierarchy view(需要能正常启动View Server),然后需要确定window下show view中tree view是否设置显示。
![](https://img.haomeiwen.com/i4264767/fb61e57d65a0bb09.png)
![](https://img.haomeiwen.com/i4264767/671fef84f25b8805.png)
然后,
![](https://img.haomeiwen.com/i4264767/38eac156398a9dc9.png)
界面的显示主要是FocusRecyclerView(id/dashboard_container)+LinearLayout(id/dashboard_tile)。
LinearLayout又由ImageView(id/icon)和TextView(id/title和id/summary)组成。
例如下图,icon就是那个图标,network就是title,mobile networks就是summary。
![](https://img.haomeiwen.com/i4264767/be64f5819db3584f.png)
然后在Android studio中使用ctrl+shift+f搜索id。例如dashboard_container。找到dashboard.xml和DashboardSummary,DashboardSummary是一个fragment,dashboard.xml中定义了使用了FocusRecyclerView。DashboardSummary就是显示的fragment。那么这个fragment是如何显示的?这些显示的数据又是在哪里产生的?
//\vendor\mediatek\proprietary\packages\xx\xx\src\com\android\settings\dashboard\DashboardSummary.java
public class DashboardSummary extends InstrumentedFragment
implements CategoryListener, ConditionListener,
FocusListener, SuggestionDismissController.Callback, DetachListener {
.....
private FocusRecyclerView mDashboard;
private DashboardAdapter mAdapter;
private SummaryLoader mSummaryLoader;
private ConditionManager mConditionManager;
private SuggestionParser mSuggestionParser;
private LinearLayoutManager mLayoutManager;
private SuggestionsChecks mSuggestionsChecks;
private DashboardFeatureProvider mDashboardFeatureProvider;
private SuggestionFeatureProvider mSuggestionFeatureProvider;
.....
}
fragment必定是依托于activity,DashboardSummary是在SettingsActivity中使用的。
//vendor\mediatek\proprietary\packages\xx\xx\src\com\android\settings\SettingsActivity.java
public class SettingsActivity extends SettingsDrawerActivity
implements PreferenceManager.OnPreferenceTreeClickListener,
PreferenceFragment.OnPreferenceStartFragmentCallback,
ButtonBarHandler, FragmentManager.OnBackStackChangedListener, OnClickListener {
.....
@VisibleForTesting
void launchSettingFragment(String initialFragmentName, boolean isSubSettings, Intent intent) {
if (!mIsShowingDashboard && initialFragmentName != null) {
// 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 {
// Show search icon as up affordance if we are displaying the main Dashboard
mDisplayHomeAsUpEnabled = true;
mInitialTitleResId = R.string.dashboard_title;
switchToFragment(DashboardSummary.class.getName(), null /* args */, false, false,
mInitialTitleResId, mInitialTitle, false);
}
}
.....
}
通过查看AndroidManifest.xml,可以发现启动activity是Settings。
AndroidManifest.xml中使用的是activity-alias 标签。
<activity-alias android:name="Settings"
android:taskAffinity="com.android.settings"
android:label="@string/settings_label_launcher"
android:launchMode="singleTask"
android:targetActivity="Settings">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts"/>
</activity-alias>
alias翻译为别名,化名。activity-alias是Android里为了重复使用Activity而设计的。
对于activity-alias标签,它有一个属性叫android:targentActivity,这个属性就是用来为该标签设置目标Activity的,或者说它就是这个目标Activity的别名。
那么来看看Settings 这个类。
//vendor\mediatek\proprietary\packages\xx\xx\src\com\android\settings\Settings.java
public class Settings extends SettingsActivity {
/*
* Settings subclasses for launching independently.
*/
public static class AssistGestureSettingsActivity extends SettingsActivity { /* empty */}
public static class BluetoothSettingsActivity extends SettingsActivity { /* empty */ }
public static class SimSettingsActivity extends SettingsActivity { /* empty */ }
public static class TetherSettingsActivity extends SettingsActivity { /* empty */ }
.....
}
.....
}
一堆的内部静态类xxxSettingsActivity继承自SettingsActivity,并且内容为empty,所以关键还是在SettingsActivity和DashboardSummary。看源码的时候很容易迷失在一堆代码中,所以找到关键点的时候最好是记下来,并且要注意侧重点,人的精力是有限的。
再回过头来看AndroidManifest.xml。其实这里面用的标签有点多,先简单看一下。
<!-- Wireless Controls -->
<activity android:name=".Settings$NetworkDashboardActivity"
android:taskAffinity="com.android.settings"
android:label="@string/network_dashboard_title"
android:icon="@drawable/ic_settings_wireless"
android:parentActivityName="Settings">
<intent-filter android:priority="1">
<action android:name="android.settings.WIRELESS_SETTINGS" />
<action android:name="android.settings.AIRPLANE_MODE_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" />
</intent-filter>
<intent-filter android:priority="11">
<action android:name="com.android.settings.action.SETTINGS"/>
</intent-filter>
<meta-data android:name="com.android.settings.category"
android:value="com.android.settings.category.ia.homepage"/>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.network.NetworkDashboardFragment"/>
<meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
android:value="true" />
</activity>
<intent-filter android:priority="1">表示是一级菜单。
<intent-filter android:priority="11">
在category中的物理位置(按优先级排序时用到,并不是指第9个位置,数越大优先级越大越靠前)
<action android:name="com.android.settings.action.SETTINGS"/>
指定此项在settings中显示。
看了一圈最后还是要回到DashboardSummary中去。
//\vendor\mediatek\proprietary\packages\xx\xx\src\com\android\settings\dashboard\DashboardSummary.java
public class DashboardSummary extends InstrumentedFragment ......{
private FocusRecyclerView mDashboard;
private DashboardAdapter mAdapter;
}
由于DashboardSummary 用的是RecyclerView,而填充RecyclerView的是DashboardAdapter,而RecyclerView的显示数据是给到Adapter去显示的。所以需要看DashboardAdapter。
//vendor\mediatek\proprietary\packages\xx\xx\src\com\android\settings\dashboard\DashboardAdapter.java
......
@Override
public void onBindViewHolder(DashboardItemHolder holder, int position) {
final int type = mDashboardData.getItemTypeByPosition(position);
switch (type) {
case R.layout.dashboard_tile:
final Tile tile = (Tile) mDashboardData.getItemEntityByPosition(position);
onBindTile(holder, tile);
holder.itemView.setTag(tile);
holder.itemView.setOnClickListener(mTileClickListener);
break;
case R.layout.suggestion_condition_container:
onBindConditionAndSuggestion(
(SuggestionAndConditionContainerHolder) holder, position);
break;
case R.layout.suggestion_condition_header:
onBindSuggestionConditionHeader((SuggestionAndConditionHeaderHolder) holder,
(SuggestionConditionHeaderData)
mDashboardData.getItemEntityByPosition(position));
break;
case R.layout.suggestion_condition_footer:
holder.itemView.setOnClickListener(v -> {
mMetricsFeatureProvider.action(mContext,
MetricsEvent.ACTION_SETTINGS_CONDITION_EXPAND, false);
DashboardData prevData = mDashboardData;
mDashboardData = new DashboardData.Builder(prevData).setSuggestionConditionMode(
DashboardData.HEADER_MODE_COLLAPSED).build();
notifyDashboardDataChanged(prevData);
mRecyclerView.scrollToPosition(SUGGESTION_CONDITION_HEADER_POSITION);
});
break;
}
}
......
这里会根据mDashboardData以及position去获取type,从而选择显示的layout文件。根据前面的分析可知,这里打开setting后首先显示的是dashboard_tile.xml,也就是所谓的setting的一级菜单内容。数据是存储在DashboardData中的。那么DashboardData是如何产生的?里面存储的数据到底是什么?从实际界面上来看,实际上一级菜单只是一些图标和文字,为什么要这样去做?下面带着这些疑惑去看DashboardData的产生。
//vendor\mediatek\proprietary\packages\xx\xx\src\com\android\settings\dashboard\DashboardAdapter.java
mDashboardData = new DashboardData.Builder()
.setConditions(conditions)
.setSuggestions(suggestions)
.setCategory(category)
.setSuggestionConditionMode(suggestionConditionMode)
.build();
这3个参数是需要重点关注的。conditions,suggestions和category。conditions和suggestions看起来比较复杂,所以先来看category。
//vendor\mediatek\proprietary\packages\xx\xx\src\com\android\settings\dashboard\DashboardData.java
.....
public static class Builder {
@HeaderMode
private int mSuggestionConditionMode = HEADER_MODE_DEFAULT;
private DashboardCategory mCategory;
private List<Condition> mConditions;
private List<Tile> mSuggestions;
}
.....
我尝试在DashboardData的setCategory(DashboardCategory category)函数中,加log
打印title。
Log.d(TAG,"mCategory = " + mCategory.title );
结果报错,说明其实Category传进来的title实际并没有初始化。
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.settings/com.android.settings.Settings}: java.lang.NullPointerException: Attempt to read from field 'java.lang.CharSequence com.android.settingslib.drawer.DashboardCategory.title' on a null object reference
既然如此,那就打印tiles。
if (mCategory != null && mCategory.tiles.size() != 0){
for(int i = 0; i < mCategory.tiles.size();i++){
Tile tile = mCategory.tiles.get(i);
Log.d("DashboardData","tile category = " + tile.category +
" , tile title = "+ tile.title + " ,tile summary = " + tile.summary);
}
}
log如下所示,发现传进来的是category全部都是
com.android.settings.category.ia.homepage。这个是在AndroidManifest.xml中定义的。
2010-01-07 06:04:26.394 1213-1213/? D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Network ,tile summary = Mobile networks
2010-01-07 06:04:26.394 1213-1213/? D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Connected devices ,tile summary = Bluetooth
2010-01-07 06:04:26.394 1213-1213/? D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Apps & notifications ,tile summary = Permissions, default apps
2010-01-07 06:04:26.394 1213-1213/? D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Battery ,tile summary = 100%
2010-01-07 06:04:26.394 1213-1213/? D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Display ,tile summary = Wallpaper, sleep, font size
2010-01-07 06:04:26.394 1213-1213/? D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Sound ,tile summary = Volume, Do Not Disturb
2010-01-07 06:04:26.394 1213-1213/? D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Storage ,tile summary = 24% used - 1.52 GB free
2010-01-07 06:04:26.394 1213-1213/? D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Security ,tile summary = Screen lock
2010-01-07 06:04:26.394 1213-1213/? D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = System ,tile summary = Languages, time, backup, updates
对比界面就可以发现,这些就是setting的一级菜单所显示的内容。
那么这个Category数据又是如何产生的呢?
加log打印。
//vendor\mediatek\proprietary\packages\xx\xx\src\com\android\settings\dashboard\DashboardSummary.java
@VisibleForTesting
void updateCategoryAndSuggestion(List<Tile> suggestions) {
final Activity activity = getActivity();
if (activity == null) {
return;
}
final DashboardCategory category = mDashboardFeatureProvider.getTilesForCategory(
CategoryKey.CATEGORY_HOMEPAGE);
Log.d(TAG,"after getTilesForCategory");
if (category != null && category.tiles.size() != 0){
for(int i = 0; i < category.tiles.size();i++){
Tile tile = category.tiles.get(i);
Log.d(TAG,"tile category = " + tile.category +
" , tile title = "+ tile.title + " ,tile summary = " + tile.summary);
}
}
mSummaryLoader.updateSummaryToCache(category);
if (suggestions != null) {
mAdapter.setCategoriesAndSuggestions(category, suggestions);
} else {
Log.d(TAG,"mAdapter.setCategory");
mAdapter.setCategory(category);
}
}
public static final String CATEGORY_HOMEPAGE = "com.android.settings.category.ia.homepage";
所以其实这里就是在AndroidManifest.xml中定义的数据。
通过加log打印发现,会多次调用getTilesForCategory函数去更新category 。
2010-01-07 06:31:04.599 1175-1175/com.android.settings D/DashboardSummary: after getTilesForCategory
2010-01-07 06:31:04.599 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Network ,tile summary = null
2010-01-07 06:31:04.599 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Connected devices ,tile summary = null
2010-01-07 06:31:04.599 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Apps & notifications ,tile summary = Permissions, default apps
2010-01-07 06:31:04.600 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Battery ,tile summary = null
2010-01-07 06:31:04.600 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Display ,tile summary = Wallpaper, sleep, font size
2010-01-07 06:31:04.600 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Sound ,tile summary = Volume, Do Not Disturb
2010-01-07 06:31:04.600 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Storage ,tile summary = null
2010-01-07 06:31:04.601 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Security ,tile summary = null
2010-01-07 06:31:04.601 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = System ,tile summary = Languages, time, backup, updates
2010-01-07 06:31:04.602 1175-1175/com.android.settings D/DashboardSummary: mAdapter.setCategory
2010-01-07 06:31:04.603 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Network ,tile summary = null
2010-01-07 06:31:04.603 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Connected devices ,tile summary = null
2010-01-07 06:31:04.603 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Apps & notifications ,tile summary = Permissions, default apps
2010-01-07 06:31:04.603 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Battery ,tile summary = null
2010-01-07 06:31:04.603 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Display ,tile summary = Wallpaper, sleep, font size
2010-01-07 06:31:04.603 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Sound ,tile summary = Volume, Do Not Disturb
2010-01-07 06:31:04.603 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Storage ,tile summary = null
2010-01-07 06:31:04.603 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Security ,tile summary = null
2010-01-07 06:31:04.603 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = System ,tile summary = Languages, time, backup, updates
2010-01-07 06:31:04.903 1175-1175/com.android.settings D/DashboardSummary: Listening for condition changes
2010-01-07 06:31:04.904 1175-1175/com.android.settings D/DashboardSummary: onConditionsChanged
2010-01-07 06:31:04.904 1175-1175/com.android.settings D/DashboardSummary: conditions refreshed
2010-01-07 06:31:04.931 1175-1175/com.android.settings D/DashboardSummary: Suggestion feature is disabled, skipping suggestion entirely
2010-01-07 06:31:04.932 1175-1175/com.android.settings D/DashboardSummary: after getTilesForCategory
2010-01-07 06:31:04.932 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Network ,tile summary = null
2010-01-07 06:31:04.932 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Connected devices ,tile summary = null
2010-01-07 06:31:04.932 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Apps & notifications ,tile summary = Permissions, default apps
2010-01-07 06:31:04.932 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Battery ,tile summary = null
2010-01-07 06:31:04.932 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Display ,tile summary = Wallpaper, sleep, font size
2010-01-07 06:31:04.932 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Sound ,tile summary = Volume, Do Not Disturb
2010-01-07 06:31:04.932 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Storage ,tile summary = null
2010-01-07 06:31:04.932 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Security ,tile summary = null
2010-01-07 06:31:04.932 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = System ,tile summary = Languages, time, backup, updates
2010-01-07 06:31:04.933 1175-1175/com.android.settings D/DashboardSummary: mAdapter.setCategory
2010-01-07 06:31:04.934 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Network ,tile summary = null
2010-01-07 06:31:04.935 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Connected devices ,tile summary = null
2010-01-07 06:31:04.935 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Apps & notifications ,tile summary = Permissions, default apps
2010-01-07 06:31:04.935 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Battery ,tile summary = null
2010-01-07 06:31:04.935 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Display ,tile summary = Wallpaper, sleep, font size
2010-01-07 06:31:04.935 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Sound ,tile summary = Volume, Do Not Disturb
2010-01-07 06:31:04.935 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Storage ,tile summary = null
2010-01-07 06:31:04.935 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Security ,tile summary = null
2010-01-07 06:31:04.935 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = System ,tile summary = Languages, time, backup, updates
2010-01-07 06:31:06.877 1175-1175/com.android.settings D/DashboardSummary: Suggestion feature is disabled, skipping suggestion entirely
2010-01-07 06:31:06.878 1175-1175/com.android.settings D/DashboardSummary: after getTilesForCategory
2010-01-07 06:31:06.878 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Network ,tile summary = Mobile networks
2010-01-07 06:31:06.878 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Connected devices ,tile summary = Bluetooth
2010-01-07 06:31:06.878 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Apps & notifications ,tile summary = Permissions, default apps
2010-01-07 06:31:06.878 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Battery ,tile summary = 100%
2010-01-07 06:31:06.878 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Display ,tile summary = Wallpaper, sleep, font size
2010-01-07 06:31:06.878 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Sound ,tile summary = Volume, Do Not Disturb
2010-01-07 06:31:06.878 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Storage ,tile summary = 24% used - 1.52 GB free
2010-01-07 06:31:06.878 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = Security ,tile summary = Screen lock
2010-01-07 06:31:06.878 1175-1175/com.android.settings D/DashboardSummary: tile category = com.android.settings.category.ia.homepage , tile title = System ,tile summary = Languages, time, backup, updates
2010-01-07 06:31:06.879 1175-1175/com.android.settings D/DashboardSummary: mAdapter.setCategory
2010-01-07 06:31:06.879 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Network ,tile summary = Mobile networks
2010-01-07 06:31:06.880 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Connected devices ,tile summary = Bluetooth
2010-01-07 06:31:06.880 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Apps & notifications ,tile summary = Permissions, default apps
2010-01-07 06:31:06.880 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Battery ,tile summary = 100%
2010-01-07 06:31:06.880 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Display ,tile summary = Wallpaper, sleep, font size
2010-01-07 06:31:06.880 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Sound ,tile summary = Volume, Do Not Disturb
2010-01-07 06:31:06.880 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Storage ,tile summary = 24% used - 1.52 GB free
2010-01-07 06:31:06.880 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = Security ,tile summary = Screen lock
2010-01-07 06:31:06.880 1175-1175/com.android.settings D/DashboardData: tile category = com.android.settings.category.ia.homepage , tile title = System ,tile summary = Languages, time, backup, updates
2010-01-07 06:31:07.030 1175-1175/com.android.settings D/DashboardSummary: Suggestion feature is disabled, skipping suggestion entirely
2010-01-07 06:31:07.030 1175-1175/com.android.settings D/DashboardSummary: after getTilesForCategory
一开始部分summary 为null是因为AndroidManifest.xml中部分activity中没有定义summary。
例如下面是AndroidManifest中的一个简单的activity的定义。
<meta-data android:name="com.android.settings.title"
android:resource="@string/wallpaper_suggestion_title" />
<meta-data android:name="com.android.settings.summary"
android:resource="@string/wallpaper_suggestion_summary" />
com.android.settings.title所定义的就是DashboardCategory 中的title,com.android.settings.summary所定义的就是DashboardCategory 中的summary。当AndroidManifest中没有定义summary的时候,数据又是从哪里来的?这部分涉及到mDashboardFeatureProvider这部分的内容就先不管了。
通过前面的分析,大致知道了一级菜单的数据的来源,那么下面来看二级菜单。
由于一级菜单的显示是DashboardSummary这个fragment,并且用的是RecyclerView,所以去DashboardAdapter里面找OnClickListener。
//vendor\mediatek\proprietary\packages\xx\xx\src\com\android\settings\dashboard\DashboardAdapter.java
........
private View.OnClickListener mTileClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
//TODO: get rid of setTag/getTag
mDashboardFeatureProvider.openTileIntent((Activity) mContext, (Tile) v.getTag());
}
};
........
@Override
public void onBindViewHolder(DashboardItemHolder holder, int position) {
final int type = mDashboardData.getItemTypeByPosition(position);
switch (type) {
case R.layout.dashboard_tile:
final Tile tile = (Tile) mDashboardData.getItemEntityByPosition(position);
onBindTile(holder, tile);
holder.itemView.setTag(tile);
holder.itemView.setOnClickListener(mTileClickListener);
break;
........
}
........
这里可以看出,主要是通过mDashboardFeatureProvider.openTileIntent去跳转不同的二级菜单。
DashboardFeatureProvider只是一个接口,openTileIntent的定义在DashboardFeatureProviderImpl中。openTileIntent会调用launchIntentOrSelectProfile从而实现activity的跳转。
//vendor\mediatek\proprietary\packages\xx\xx\src\com\android\settings\dashboard\DashboardFeatureProviderImpl.java
public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
........
@Override
public void openTileIntent(Activity activity, Tile tile) {
if (tile == null) {
Intent intent = new Intent(Settings.ACTION_SETTINGS).addFlags(
Intent.FLAG_ACTIVITY_CLEAR_TASK);
mContext.startActivity(intent);
return;
}
if (tile.intent == null) {
return;
}
final Intent intent = new Intent(tile.intent)
.putExtra(SettingsActivity.EXTRA_SOURCE_METRICS_CATEGORY,
MetricsEvent.DASHBOARD_SUMMARY)
.putExtra(SettingsDrawerActivity.EXTRA_SHOW_MENU, true)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
launchIntentOrSelectProfile(activity, tile, intent, MetricsEvent.DASHBOARD_SUMMARY);
}
private void launchIntentOrSelectProfile(Activity activity, Tile tile, Intent intent,
int sourceMetricCategory) {
if (!isIntentResolvable(intent)) {
Log.w(TAG, "Cannot resolve intent, skipping. " + intent);
return;
}
ProfileSelectDialog.updateUserHandlesIfNeeded(mContext, tile);
if (tile.userHandle == null) {
mMetricsFeatureProvider.logDashboardStartIntent(mContext, intent, sourceMetricCategory);
activity.startActivityForResult(intent, 0);
} else if (tile.userHandle.size() == 1) {
mMetricsFeatureProvider.logDashboardStartIntent(mContext, intent, sourceMetricCategory);
activity.startActivityForResultAsUser(intent, 0, tile.userHandle.get(0));
} else {
ProfileSelectDialog.show(activity.getFragmentManager(), tile);
}
}
........
}
所以其实二级菜单也是不同的activity。例如NetworkDashboardActivity和AppAndNotificationDashboardActivity。
NetworkDashboardActivity在注册表中写的是Settings$NetworkDashboardActivity
,为什么写Settings$xxxx
原因我没有弄清楚。下一篇是二级菜单的分析。
参考链接:
设置
Android7.1 Setting模块添加一级菜单跳转第三方应用
网友评论