路径 ./packages/apps/Setting/src/com/android/setting/
根据 AndroidManifest.xml 可以发现首页面为SettingsHomepageActivity,紧接着我们进入到 SettingsHomepageActivity
SettingHomeActivity
路径 ./homepage/SettingHomepageActivity.java
我们直接看它的onCreate方法
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.settings_homepage_container);
...
if (!getSystemService(ActivityManager.class).isLowRamDevice()) {
// Only allow contextual feature on high ram devices.
showFragment(new ContextualCardsFragment(), R.id.contextual_cards_content);
}
showFragment(new TopLevelSettings(), R.id.main_content);
...
}
showFragment方法很简单,加入对应的Fragment。由此,我们可以跟进到ContextualCardsFragment与
TopLevelSettings
TopLevelSettings
路径 .settings.homepage;
我们可以看到 TopLevelSettings <- DashboardFragment <- SettingsPreferenceFragment <- InstrumentedPreferenceFragment <- ObservablePreferenceFragment <- PreferenceFragmentCompat
在TopLevelSettings内可以看到这样一段代码,跟进文件继续看。
getPreferenceScreenResId 继承自 InstrumentedPreferenceFragment
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
// 默认为-1,如果大于-1,去加载布局
final int resId = getPreferenceScreenResId();
if (resId > 0) {
addPreferencesFromResource(resId);
}
}
···
/**
* Get the res id for static preference xml for this fragment.
*/
protected int getPreferenceScreenResId() {
return -1;
}
@Override
public void addPreferencesFromResource(@XmlRes int preferencesResId) {
super.addPreferencesFromResource(preferencesResId);
updateActivityTitleWithScreenTitle(getPreferenceScreen());
}
PreferenceFragmentCompat
/**
* Inflates the given XML resource and adds the preference hierarchy to the current
* preference hierarchy.
*
* @param preferencesResId The XML resource ID to inflate.
*/
public void addPreferencesFromResource(@XmlRes int preferencesResId) {
requirePreferenceManager();
setPreferenceScreen(mPreferenceManager.inflateFromResource(mStyledContext,
preferencesResId, getPreferenceScreen()));
}
此时我们在 TopLevelSettings 找到 getPreferenceScreenResId 方法
@Override
protected int getPreferenceScreenResId() {
return R.xml.top_level_settings;
}
去找到对应的XML文件
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="top_level_settings">
<Preference
android:key="top_level_network"
android:title="@string/network_dashboard_title"
android:summary="@string/summary_placeholder"
android:icon="@drawable/ic_homepage_network"
android:order="-120"
android:fragment="com.android.settings.network.NetworkDashboardFragment"
settings:controller="com.android.settings.network.TopLevelNetworkEntryPreferenceController"/>
···
<Preference
android:key="top_level_support"
android:summary="@string/support_summary"
android:title="@string/page_tab_title_support"
android:icon="@drawable/ic_homepage_support"
android:order="100"
settings:controller="com.android.settings.support.SupportPreferenceController"/>
</PreferenceScreen>
我们发现系统设置内用的是Preference方法构建的界面,到这里我们就很清楚了明白了Settings的一级界面布局。
在这里我们知道了一级菜单的数据,那我们也看下二级菜单的数据吧。我们在一级菜单里面可以看到有framgnet我们跟进去看看NetworkDashboardFragment。
在NetworkDashboardFragment内,我们同样可以看到 getPreferenceScreenResId 方法,所以明白了,一级菜单和二级菜单构建界面的方法如出一辙。
@Override
protected int getPreferenceScreenResId() {
if (FeatureFlagPersistent.isEnabled(getContext(), FeatureFlags.NETWORK_INTERNET_V2)) {
return R.xml.network_and_internet_v2;
} else {
return R.xml.network_and_internet;
}
}
我们继续跟进network_and_internet_v2去一探究竟。
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="network_and_internet_screen"
android:title="@string/network_dashboard_title"
settings:initialExpandedChildrenCount="5">
<PreferenceCategory
android:key="multi_network_header"
android:title="@string/summary_placeholder"
android:layout="@layout/preference_category_no_label"
settings:allowDividerBelow="true"
android:order="-40"
settings:controller="com.android.settings.network.MultiNetworkHeaderController"/>
<com.android.settings.widget.MasterSwitchPreference
android:fragment="com.android.settings.wifi.WifiSettings"
android:key="toggle_wifi"
android:title="@string/wifi_settings"
android:summary="@string/summary_placeholder"
android:icon="@drawable/ic_settings_wireless"
android:order="-30"
settings:allowDividerAbove="true">
<intent
android:action="android.settings.WIFI_SETTINGS"
android:targetClass="Settings$WifiSettingsActivity" />
</com.android.settings.widget.MasterSwitchPreference>
···
<com.android.settings.network.PrivateDnsModeDialogPreference
android:key="private_dns_settings"
android:title="@string/select_private_dns_configuration_title"
android:order="20"
android:dialogTitle="@string/select_private_dns_configuration_dialog_title"
android:dialogLayout="@layout/private_dns_mode_dialog"
android:positiveButtonText="@string/save"
android:negativeButtonText="@android:string/cancel" />
</PreferenceScreen>
我们可以看到这里是二级菜单,是不是和一级菜单一样呢,所以我们到这里就明白了Settings的菜单数据展示喽~
下一步我们看搜索栏是怎么实现的
在上面的文章中,我们知道了首页面为SettingsHomepageActivity,所以我们直接去看SettingsHomepageActivity就好。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.settings_homepage_container);
···
// 这里有initSearchToolbar,是不是感觉很像
FeatureFactory.getFactory(this).getSearchFeatureProvider()
.initSearchToolbar(this /* activity */, toolbar, SettingsEnums.SETTINGS_HOMEPAGE);
···
((FrameLayout) findViewById(R.id.main_content))
.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
}
我们可以找到 SearchFeatureProvider.initSearchToolbar
default void initSearchToolbar(Activity activity, Toolbar toolbar, int pageId) {
if (activity == null || toolbar == null) {
return;
}
if (!Utils.isDeviceProvisioned(activity) ||
!Utils.isPackageEnabled(activity, getSettingsIntelligencePkgName(activity))) {
final ViewGroup parent = (ViewGroup) toolbar.getParent();
if (parent != null) {
parent.setVisibility(View.GONE);
}
return;
}
final View navView = toolbar.getNavigationView();
navView.setClickable(false);
navView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
navView.setBackground(null);
// 在这里 我们可以看到点击事件的设置
toolbar.setOnClickListener(tb -> {
final Context context = activity.getApplicationContext();
// 这里有跳转意图 但是我们在本类中没有找到 buildSearchIntent 的实现
// 但是我们看到 SearchFeatureProvider 有一个实现类 SearchFeatureProviderImpl
// 我们进到 SearchFeatureProviderImpl 内部中看看具体实现
final Intent intent = buildSearchIntent(context, pageId);
if (activity.getPackageManager().queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) {
return;
}
FeatureFactory.getFactory(context).getSlicesFeatureProvider()
.indexSliceDataAsync(context);
FeatureFactory.getFactory(context).getMetricsFeatureProvider()
.action(context, SettingsEnums.ACTION_SEARCH_RESULTS);
activity.startActivityForResult(intent, REQUEST_CODE);
});
}
SearchFeatureProviderImpl.buildSearchIntent
@Override
public Intent buildSearchIntent(Context context, int pageId) {
return new Intent(Settings.ACTION_APP_SEARCH_SETTINGS)
.setPackage(getSettingsIntelligencePkgName(context))
.putExtra(Intent.EXTRA_REFERRER, buildReferrer(context, pageId));
}
我们此时可以看到,跳转意图为 Settings.ACTION_APP_SEARCH_SETTINGS,跳转到了搜索界面。
搜索界面是Android单独的一个模块
路径android/packages/apps/SettingsIntelligence下
未完待续 如有错误欢迎指出 共同学习 共同进步哈~