【筆記】Android Settings 應用設置菜單的界面代碼介紹

簡介

Settings應用中,提供多類設置菜單入口,每個菜單內又有各模塊功能的實現。

那么各個模塊基于Settings 基礎的界面Fragment去實現UI,層層按不同業務進行封裝繼承實現子類:

  • DashboardFragment
  • SettingsPreferenceFragment

功能設置頁中的菜單又是通過Controller去實現業務并進行UI動態更新控制。

代碼

基于 Android U 平臺的實現進行介紹。

公用基類

DashboardFragment

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

package com.android.settings.dashboard;/*** Base fragment for dashboard style UI containing a list of static and dynamic setting items.*/
public abstract class DashboardFragment extends SettingsPreferenceFragmentimplements CategoryListener, Indexable, PreferenceGroup.OnExpandButtonClickListener,BasePreferenceController.UiBlockListener {public static final String CATEGORY = "category";private static final String TAG = "DashboardFragment";private static final long TIMEOUT_MILLIS = 50L;/*** Get a list of {@link AbstractPreferenceController} for this fragment.*/protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {return null;}
 

模塊案例

繼承關系:(自上而下,底層是父類,除了MobileNetwork,其他都是抽象類,直到Fragment)

  • MobileNetworkSettings --- 移動網絡設置
  • AbstractMobileNetworkSettings
  • RestrictedDashboardFragment
  • DashboardFragment
  • SettingsPreferenceFragment
  • InstrumentedPreferenceFragment -- /com/android/settings/core/
  • ObservablePreferenceFragment -- /frameworks/base/packages/SettingsLib
  • PreferenceFragmentCompat -- classes.jar/androidx.preference
  • Fragment

AbstractMobileNetworkSettings?是一個抽象類,用于提供移動網絡設置相關的基本功能和行為。

RestrictedDashboardFragment?是在DashboardFragment的基礎上添加了一些限制或額外的安全措施,以限制用戶對某些設置或操作的訪問或更改。可能會對一些敏感的設置進行限制,例如網絡設置、安全設置等。也可能會對某些功能進行權限控制,只允許特定用戶訪問。

DashboardFragment?是基礎的儀表盤樣式?UI Fragment,用于顯示靜態和動態的設置項列表。通常不會加入對設置的限制,而是專注于提供用戶友好的設置界面和功能。可能包含一些基本的設置項處理和展示邏輯,以便用戶能夠輕松地進行配置和操作。

MobileNetworkSettings 移動網絡設置(界面邏輯)

packages/apps/Settings/src/com/android/settings/network/telephony/MobileNetworkSettings.java

界面布局在mobile_network_settings.xml

MobileNetworkSettings API
APIFunction
onPreferenceTreeClick定義子功能pref點擊事件(override)
createPreferenceControllers創建子功能pref的控制器(override)
onAttach生命周期,use 各類 Controller(override)
onSubscriptionDetailChanged響應注冊狀態變化進行的操作
package com.android.settings.network.telephony;@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class MobileNetworkSettings extends AbstractMobileNetworkSettings implementsMobileNetworkRepository.MobileNetworkCallback {private static final String LOG_TAG = "NetworkSettings";//處理子菜單點擊事件/*** Invoked on each preference click in this hierarchy, overrides* PreferenceActivity's implementation.  Used to make sure we track the* preference click events.*/@Overridepublic boolean onPreferenceTreeClick(Preference preference) {if (super.onPreferenceTreeClick(preference)) {return true;}final String key = preference.getKey();if (TextUtils.equals(key, BUTTON_CDMA_SYSTEM_SELECT_KEY)|| TextUtils.equals(key, BUTTON_CDMA_SUBSCRIPTION_KEY)) {if (mTelephonyManager.getEmergencyCallbackMode()) {startActivityForResult(new Intent(TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null),REQUEST_CODE_EXIT_ECM);mClickedPrefKey = key;}return true;}//【客制化】可通過else if 定制其他keyt的點擊行為return false;}//創建各子菜單/功能選項的Controller@Overrideprotected List<AbstractPreferenceController> createPreferenceControllers(Context context) {if (!SubscriptionUtil.isSimHardwareVisible(context)) {finish();return Arrays.asList();}if (getArguments() == null) {Intent intent = getIntent();if (intent != null) {mSubId = intent.getIntExtra(Settings.EXTRA_SUB_ID,MobileNetworkUtils.getSearchableSubscriptionId(context));Log.d(LOG_TAG, "display subId from intent: " + mSubId);} else {Log.d(LOG_TAG, "intent is null, can not get subId " + mSubId + " from intent.");}} else {mSubId = getArguments().getInt(Settings.EXTRA_SUB_ID,MobileNetworkUtils.getSearchableSubscriptionId(context));Log.d(LOG_TAG, "display subId from getArguments(): " + mSubId);}mMobileNetworkRepository = MobileNetworkRepository.getInstance(context);mExecutor.execute(() -> {mSubscriptionInfoEntity = mMobileNetworkRepository.getSubInfoById(String.valueOf(mSubId));mMobileNetworkInfoEntity =mMobileNetworkRepository.queryMobileNetworkInfoBySubId(String.valueOf(mSubId));});return Arrays.asList(new DataUsageSummaryPreferenceController(getActivity(), getSettingsLifecycle(),this, mSubId),new RoamingPreferenceController(context, KEY_ROAMING_PREF, getSettingsLifecycle(),this, mSubId),new CallsDefaultSubscriptionController(context, KEY_CALLS_PREF,getSettingsLifecycle(), this),new SmsDefaultSubscriptionController(context, KEY_SMS_PREF, getSettingsLifecycle(),this),new MobileDataPreferenceController(context, KEY_MOBILE_DATA_PREF,getSettingsLifecycle(), this, mSubId),new ConvertToEsimPreferenceController(context, KEY_CONVERT_TO_ESIM_PREF,getSettingsLifecycle(), this, mSubId));}@Overridepublic void onAttach(Context context) {super.onAttach(context);if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {Log.d(LOG_TAG, "Invalid subId, get the default subscription to show.");SubscriptionInfo info = SubscriptionUtil.getSubscriptionOrDefault(context, mSubId);if (info == null) {Log.d(LOG_TAG, "Invalid subId request " + mSubId);return;}mSubId = info.getSubscriptionId();Log.d(LOG_TAG, "Show NetworkSettings fragment for subId" + mSubId);}Intent intent = getIntent();if (intent != null) {int updateSubscriptionIndex = intent.getIntExtra(Settings.EXTRA_SUB_ID,SubscriptionManager.INVALID_SUBSCRIPTION_ID);if (updateSubscriptionIndex != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {int oldSubId = mSubId;mSubId = updateSubscriptionIndex;// If the subscription has changed or the new intent does not contain the opt in// action,// remove the old discovery dialog. If the activity is being recreated, we will see// onCreate -> onNewIntent, so the dialog will first be recreated for the old// subscription// and then removed.if (updateSubscriptionIndex != oldSubId|| !MobileNetworkActivity.doesIntentContainOptInAction(intent)) {removeContactDiscoveryDialog(oldSubId);}// evaluate showing the new discovery dialog if this intent contains an action to// show the// opt-in.if (MobileNetworkActivity.doesIntentContainOptInAction(intent)) {showContactDiscoveryDialog();}}}final DataUsageSummaryPreferenceController dataUsageSummaryPreferenceController =use(DataUsageSummaryPreferenceController.class);if (dataUsageSummaryPreferenceController != null) {dataUsageSummaryPreferenceController.init(mSubId);}use(MobileNetworkSwitchController.class).init(mSubId);use(CarrierSettingsVersionPreferenceController.class).init(mSubId);use(BillingCyclePreferenceController.class).init(mSubId);use(MmsMessagePreferenceController.class).init(mSubId);use(AutoDataSwitchPreferenceController.class).init(mSubId);use(DisabledSubscriptionController.class).init(mSubId);use(DeleteSimProfilePreferenceController.class).init(mSubId, this,REQUEST_CODE_DELETE_SUBSCRIPTION);use(DisableSimFooterPreferenceController.class).init(mSubId);use(NrDisabledInDsdsFooterPreferenceController.class).init(mSubId);final MobileDataPreferenceController mobileDataPreferenceController =use(MobileDataPreferenceController.class);if (mobileDataPreferenceController != null) {mobileDataPreferenceController.init(getFragmentManager(), mSubId,mSubscriptionInfoEntity, mMobileNetworkInfoEntity);mobileDataPreferenceController.setWifiPickerTrackerHelper(new WifiPickerTrackerHelper(getSettingsLifecycle(), context,null /* WifiPickerTrackerCallback */));}final RoamingPreferenceController roamingPreferenceController =use(RoamingPreferenceController.class);if (roamingPreferenceController != null) {roamingPreferenceController.init(getFragmentManager(), mSubId,mMobileNetworkInfoEntity);}use(ApnPreferenceController.class).init(mSubId);use(CarrierPreferenceController.class).init(mSubId);use(DataUsagePreferenceController.class).init(mSubId);use(PreferredNetworkModePreferenceController.class).init(mSubId);use(EnabledNetworkModePreferenceController.class).init(mSubId);use(DataServiceSetupPreferenceController.class).init(mSubId);use(Enable2gPreferenceController.class).init(mSubId);use(CarrierWifiTogglePreferenceController.class).init(getLifecycle(), mSubId);final WifiCallingPreferenceController wifiCallingPreferenceController =use(WifiCallingPreferenceController.class).init(mSubId);final OpenNetworkSelectPagePreferenceController openNetworkSelectPagePreferenceController =use(OpenNetworkSelectPagePreferenceController.class).init(mSubId);final AutoSelectPreferenceController autoSelectPreferenceController =use(AutoSelectPreferenceController.class).init(getLifecycle(), mSubId).addListener(openNetworkSelectPagePreferenceController);use(NetworkPreferenceCategoryController.class).init(mSubId).setChildren(Arrays.asList(autoSelectPreferenceController));mCdmaSystemSelectPreferenceController = use(CdmaSystemSelectPreferenceController.class);mCdmaSystemSelectPreferenceController.init(getPreferenceManager(), mSubId);mCdmaSubscriptionPreferenceController = use(CdmaSubscriptionPreferenceController.class);mCdmaSubscriptionPreferenceController.init(getPreferenceManager(), mSubId);final VideoCallingPreferenceController videoCallingPreferenceController =use(VideoCallingPreferenceController.class).init(mSubId);use(CallingPreferenceCategoryController.class).setChildren(Arrays.asList(wifiCallingPreferenceController, videoCallingPreferenceController));use(Enhanced4gLtePreferenceController.class).init(mSubId).addListener(videoCallingPreferenceController);use(Enhanced4gCallingPreferenceController.class).init(mSubId).addListener(videoCallingPreferenceController);use(Enhanced4gAdvancedCallingPreferenceController.class).init(mSubId).addListener(videoCallingPreferenceController);use(ContactDiscoveryPreferenceController.class).init(getParentFragmentManager(), mSubId);use(NrAdvancedCallingPreferenceController.class).init(mSubId);use(TransferEsimPreferenceController.class).init(mSubId, mSubscriptionInfoEntity);final ConvertToEsimPreferenceController convertToEsimPreferenceController =use(ConvertToEsimPreferenceController.class);if (convertToEsimPreferenceController != null) {convertToEsimPreferenceController.init(mSubId, mSubscriptionInfoEntity);}List<AbstractSubscriptionPreferenceController> subscriptionPreferenceControllers =useAll(AbstractSubscriptionPreferenceController.class);for (AbstractSubscriptionPreferenceController controller :subscriptionPreferenceControllers) {controller.init(mSubId);}}private void onSubscriptionDetailChanged() {if (mSubscriptionInfoEntity != null) {/*** Update the title when SIM stats got changed*/final Consumer<Activity> renameTitle = activity -> {if (activity != null && !activity.isFinishing()) {if (activity instanceof SettingsActivity) {((SettingsActivity) activity).setTitle(mSubscriptionInfoEntity.uniqueName);}}};ThreadUtils.postOnMainThread(() -> {renameTitle.accept(getActivity());redrawPreferenceControllers();});}}//界面布局在mobile_network_settings.xml@Overrideprotected int getPreferenceScreenResId() {return R.xml.mobile_network_settings;}}

mobile_network_settings 布局

packages/apps/Settings/res/xml/mobile_network_settings.xml

  • MobileNetworkSwitchController?SIM卡移動網絡總開關邏輯
  • use_sim_switch 界面的資源key
  • mobile_network_use_sim_on 開關名稱title

以下僅展示部分功能選項/菜單:

<PreferenceScreenxmlns:android="http://schemas.android.com/apk/res/android"xmlns:settings="http://schemas.android.com/apk/res-auto"android:key="mobile_network_pref_screen"><com.android.settings.widget.SettingsMainSwitchPreferenceandroid:key="use_sim_switch"android:title="@string/mobile_network_use_sim_on"settings:controller="com.android.settings.network.telephony.MobileNetworkSwitchController"/><PreferenceCategoryandroid:key="enabled_state_container"android:title="@string/summary_placeholder"settings:controller="com.android.settings.network.telephony.DisabledSubscriptionController"android:layout="@layout/preference_category_no_label"><!--智能數據切換開關--><SwitchPreferenceandroid:key="auto_data_switch"android:title="@string/auto_data_switch_title"android:summary="@string/auto_data_switch_summary"settings:controller="com.android.settings.network.telephony.AutoDataSwitchPreferenceController"/><!--數據漫游開關--><com.android.settingslib.RestrictedSwitchPreferenceandroid:key="button_roaming_key"android:title="@string/roaming"android:persistent="false"android:summaryOn="@string/roaming_enable"android:summaryOff="@string/roaming_disable"settings:userRestriction="no_data_roaming"settings:controller="com.android.settings.network.telephony.RoamingPreferenceController"/><!--數據流量菜單入口--><Preferenceandroid:key="data_usage_summary"android:title="@string/mobile_data_usage_title"settings:controller="com.android.settings.network.telephony.DataUsagePreferenceController"/><!--網絡模式列表選擇--><ListPreferenceandroid:key="enabled_networks_key"android:title="@string/preferred_network_mode_title"android:summary="@string/preferred_network_mode_summary"android:entries="@array/enabled_networks_choices"android:entryValues="@array/enabled_networks_values"android:dialogTitle="@string/preferred_network_mode_dialogtitle"settings:controller="com.android.settings.network.telephony.EnabledNetworkModePreferenceController"/><!--Network目錄--><PreferenceCategoryandroid:key="network_operators_category_key"android:title="@string/network_operator_category"settings:controller="com.android.settings.network.telephony.NetworkPreferenceCategoryController"><!--自動選網開關--><SwitchPreferenceandroid:key="auto_select_key"android:title="@string/select_automatically"settings:controller="com.android.settings.network.telephony.gsm.AutoSelectPreferenceController"/><!--如果上述自動選網關閉,那么此手動選網菜單,可跳轉到網絡列表頁--><Preferenceandroid:key="choose_network_key"android:title="@string/choose_network_title"settings:controller="com.android.settings.network.telephony.gsm.OpenNetworkSelectPagePreferenceController"/></PreferenceCategory><!--APN設置入口--><!--We want separate APN setting from reset of settings because we want user to change it with caution--><com.android.settingslib.RestrictedPreferenceandroid:key="telephony_apn_key"android:persistent="false"android:title="@string/mobile_network_apn_title"settings:allowDividerAbove="true"settings:keywords="@string/keywords_access_point_names"settings:controller="com.android.settings.network.telephony.ApnPreferenceController"/></PreferenceCategory></PreferenceScreen>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/38613.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/38613.shtml
英文地址,請注明出處:http://en.pswp.cn/web/38613.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

植物大戰僵尸雜交版,最新安裝包(PC+手機+蘋果)+ 修改器+高清工具

植物大戰僵尸雜交版&#xff1a;全新游戲體驗與創意碰撞 游戲簡介 《植物大戰僵尸雜交版》是由B站知名UP主潛艇偉偉迷基于經典游戲《植物大戰僵尸》進行的一次大膽且富有創意的二次創作。這款游戲不僅保留了原版游戲的經典玩法&#xff0c;還融入了植物雜交的全新概念&#x…

Qt掃盲-QRect矩形描述類

QRect矩形描述總結 一、概述二、常用函數1. 移動類2. 屬性函數3. 判斷4. 比較計算 三、渲染三、坐標 一、概述 QRect類使用整數精度在平面中定義一個矩形。在繪圖的時候經常使用&#xff0c;作為一個二維的參數描述類。 一個矩形主要有兩個重要屬性&#xff0c;一個是坐標&am…

同步互斥與通信

目錄 一、同步與互斥的概念 二、同步與互斥并不簡單 三、各類方法的對比 一、同步與互斥的概念 一句話理解同步與互斥&#xff1a;我等你用完廁所&#xff0c;我再用廁所。 什么叫同步&#xff1f;就是&#xff1a;哎哎哎&#xff0c;我正在用廁所&#xff0c;你等會。 什…

【實戰場景】記一次UAT jvm故障排查經歷

【實戰場景】記一次UAT jvm故障排查經歷 開篇詞&#xff1a;干貨篇&#xff1a;1.查看系統資源使用情況2.將十進制進程號轉成十六進制3.使用jstack工具監視進程的垃圾回收情況4.輸出指定線程的堆內存信息5.觀察日志6.本地環境復現 總結篇&#xff1a;我是杰叔叔&#xff0c;一名…

線下促銷折扣視頻介紹

千呼新零售2.0系統是零售行業連鎖店一體化收銀系統&#xff0c;包括線下收銀線上商城連鎖店管理ERP管理商品管理供應商管理會員營銷等功能為一體&#xff0c;線上線下數據全部打通。 適用于商超、便利店、水果、生鮮、母嬰、服裝、零食、百貨、寵物等連鎖店使用。 詳細介紹請…

Linux上systemctl 和 service 兩個命令的區別和聯系

systemctl 和 service 兩個命令都是 Linux 系統中用于管理服務的工具&#xff0c;但它們分別關聯著不同的初始化系統&#xff08;init system&#xff09;&#xff0c;并且在功能和使用場景上有所差異。 service 命令 關聯的初始化系統&#xff1a;service 命令通常與 SysV i…

Python從零學習筆記(1)

1pip無法調用 剛入python&#xff0c;需要用到第三方模塊&#xff0c;但是按照教程使用>>>pip install 總是出現錯誤提示 網上查詢許久&#xff1a;語句沒錯&#xff1b;安裝沒錯&#xff1b;環境配置也正常 最后才知道是不能先進入python模式&#xff0c;而是使用p…

2024年道路運輸安全員考試題庫及答案

一、多選題 11.《放射性物品安全管理條例》規定&#xff0c;運輸放射性物品時&#xff0c;應當使用專用的放射性物品運輸包裝容器。在運輸過程中正確的做法有&#xff08; &#xff09;。 A.托運人和承運人應當按照國家放射性物品運輸安全標準和國家有關規定&#xff0c;在…

什么是定時器?

前言&#x1f440;~ 上一章我們介紹了阻塞隊列以及生產者消息模式&#xff0c;今天我們來講講定時器 定時器 標準庫中的定時器 schedule()方法 掃描線程 手動實現定時器 任務類 存儲任務的數據結構 定時器類 如果各位對文章的內容感興趣的話&#xff0c;請點點小贊&am…

【Python】列表

目錄 一、列表的概念 二、列表的創建 1.變量名 [ ] ..... 2.通過Python內置 的I ist類的構造函數來創建列表 三、操作列表元素的方法 1. 修改 2. 增加元素 3. 刪除 4. 其他操作 四、遍歷列表 五、列表排序 六、列表切片&#xff08;list slicing&#xff09; 七、…

淺談什么是計算機科學與技術(Computer Science,CS)

計算機科學的核心內容 計算機科學&#xff08;Computer Science, CS&#xff09;涵蓋了以下主要領域&#xff1a; 硬件&#xff1a;涉及數字電路、集成電路、存儲器和硬件設計與驗證方法等。 例子&#xff1a;學習如何設計和實現一個簡單的CPU&#xff0c;包括理解指令集、時鐘…

值得細讀的8個視覺大模型生成式預訓練方法

作者&#xff1a;vasgaowei&#xff08;已授權原創&#xff09; 編輯: AI生成未來 鏈接&#xff1a;https://zhuanlan.zhihu.com/p/677794719 大語言模型的進展催生出了ChatGPT這樣的應用&#xff0c;讓大家對“第四次工業革命”和“AGI”的來臨有了一些期待&#xff0c;也作為…

Linux基礎指令介紹與詳解——原理學習

前言&#xff1a;本節內容標題雖然為指令&#xff0c;但是并不只是講指令&#xff0c; 更多的是和指令相關的一些原理性的東西。 如果友友只想要查一查某個指令的用法&#xff0c; 很抱歉&#xff0c; 本節不是那種帶有字典性質的文章。但是如果友友是想要來學習的&#xff0c;…

[ALSA]從零開始,使用ALSA驅動播放一個音頻

前言 最近學了不少有關音頻相關的&#xff0c;最近搞一下ALSA驅動 安裝 參考Linux應用開發【第八章】ALSA應用開發 中提到的ALSA庫及工具章節&#xff0c;本文中有比較詳細的有關ALSA驅動引用程序怎么安裝的&#xff0c;這里不再贅述。 關于ALSA&#xff0c;就當成一個音頻…

深入淺出:npm常用命令詳解與實踐【保姆級教程】

大家好,我是CodeQi! 在我剛開始學習前端開發的時候,有一件事情讓我特別頭疼:管理和安裝各種各樣的依賴包。 那時候,我還不知道 npm 的存在,手動下載和管理這些庫簡直是噩夢。 后來,我終于接觸到了 npm(Node Package Manager),它不僅幫我解決了依賴管理問題,還讓我…

Python深度理解系列之【排序算法——冒泡排序】

讀者大大們好呀&#xff01;&#xff01;!?????? &#x1f440;期待大大的關注哦?????? &#x1f680;歡迎收看我的主頁文章??木道尋的主頁 文章目錄 &#x1f525;前言&#x1f680;冒泡排序python實現算法實現圖形化算法展示 ??????總結 &#x1f525;前…

Apache POI、EasyPoi、EasyExcel

目錄 ?編輯 &#xff08;一&#xff09;Apache PoI 使用 &#xff08;二&#xff09;EasyPoi使用 &#xff08;三&#xff09;EasyExcel使用 寫 讀 最簡單的讀? 最簡單的讀的excel示例? 最簡單的讀的對象? &#xff08;一&#xff09;Apache PoI 使用 &#xff08;二&…

golang go-bindata打包配置文件嵌入到二進制文件

go-bindata打包配置文件嵌入到二進制文件 項目中難免會用到一些靜態資源和配置文件&#xff0c;但是常規打包的二進制文件無法再其他目錄正常運行&#xff08;靜態資源和配置文件不存在&#xff09; 有類似需求的可以安裝使用&#xff1a;go-bindata進行編譯處理配置文件 go-bi…

train_encoder_decoder.py

train_encoder_decoder.py from __future__ import print_function #為了確保代碼同時兼容Python 2和Python 3版本中的print函數# 導入標準庫和第三方庫 import os.path #導入了Python的os.path模塊&#xff0c;用于處理文件和目錄路徑 from os import path #從os模塊中導入了…

【場景題】數據庫優化和接口優化——異步思想

理解 異步處理&#xff1a; 對于耗時的操作&#xff0c;可以考慮使用異步處理方式來提升接口的響應速度。用戶可以在不阻塞當前操作的情況下&#xff0c;等待異步操作的結果。 異步處理在數據庫優化中的應用 雖然數據庫操作本身&#xff08;如查詢、插入、更新等&#xff09…