您好,登錄后才能下訂單哦!
Android 4.4 系統(tǒng)的設(shè)置源碼閱讀記錄
----------2014-7-3------------------
AndroidManifest.xml
launch的activity是 Settings,另外有40多個(gè)activity繼承于它,比如設(shè)置的一級(jí)菜單: wifi,藍(lán)牙,聲音,顯示,安全,應(yīng)用程序,語言和時(shí)間,關(guān)于設(shè)備等等。實(shí)際上都是這一個(gè)acitivy。
這里從安全設(shè)置看起,SecuritySettings.java
以資源文件R.xml.security_settings_* 填充【根據(jù)當(dāng)前鎖屏方式,擁有者信息,密碼顯示等具體情形,加載不同的資源或配置】,具體在createPreferenceHierarchy() 和 onResume中
以改鎖屏方式為主線,點(diǎn)擊鎖屏項(xiàng)時(shí),onPreferenceTreeClick調(diào)用,
key值為KEY_UNLOCK_SET_OR_CHANGE,則轉(zhuǎn)到了fragment --- “com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment"中()(未知源-preference為mToggleAppInstallation,則setNonMarketAppsAllowed為false或?qū)υ捒蛱崾?,確認(rèn)后設(shè)true; 最終修改了Settings.Global.INSTALL_NON_MARKET_APPS的值 enabled ? 1 : 0)。值存儲(chǔ)在了setting provider中,目錄/data/data/com.android.providers.settings/的db文件,表secure的install_non_market_apps字段。
ChooseLockGeneric中的 ChooseLockGenericFragment
onCreate中updatePreferencesOrFinish()加載資源R.xml.security_settings_picker,含汗鎖屏方式:無,滑動(dòng),人臉解鎖,圖案,PIN,密碼6中方式。
選擇一種方式后,執(zhí)行updateUnlockMethodAndFinish(方式,啟用鎖屏?),以圖案方式為例,啟動(dòng)activity--ChooseLockPattern
ChooseLockPattern
這里它應(yīng)內(nèi)含其Fragment--ChooseLockPatternFragment,但沒看明白它怎么add上的(填充到activity)。
onCreateView中加載資源R.layout.choose_lock_pattern, onClick中,根據(jù)mUiStage狀態(tài)和click的按鈕(繼續(xù)還是取消),做不同的回饋。 最終確認(rèn)后執(zhí)行saveChosenPatternAndFinish()保存密碼,修改鎖屏方式。
LockPatternUtils.saveLockPattern(密碼,isFallback)
LockPatternUtils.setLockPatternEnabled(true);
其中用到了一些內(nèi)部的API,例如com.android.internal.widget.LockPatternUtils,和@hide的API類似,都是僅系統(tǒng)應(yīng)用可使用的API。
非系統(tǒng)應(yīng)用使用則需要通過一些特殊方法才能使用,例如,反射,可參見:http://blog.csdn.net/linghu_java/article/details/8283042
2014-7-4/5------------------------
Settings的一級(jí)菜單:
1 Settings.java
com.android.settings.Settings這個(gè)PreferenceActivity在onCreate()中調(diào)用onBuildHeaders(),此方法是重點(diǎn),用來加載設(shè)置的一級(jí)菜單的:加載資源子R.xml.settings_headers,然后調(diào)用updateHeaderList()進(jìn)行一定的過濾,若設(shè)備不支持wifi則去除wifi的header,(使用packagemanger的hasSystemFeature()檢測(cè)是否支持某功能/特性---wifi,藍(lán)牙,NFC);開發(fā)者選項(xiàng)的顯示則根據(jù)它的sharedPreference的值來確定是否顯示。
內(nèi)部的HeaderAdapter 是Settings的list的adapter,(Settings重寫了setListAdapter()設(shè)置了HeaderAdapter為L(zhǎng)istActivity的adapter),先看wifi項(xiàng),HeaderAdapter成員mWifiEnabler是WifiEnabler的實(shí)例,
2 WifiEnabler
com.android.settings.wifi.WifiEnabler主要用來開關(guān)wifi,并監(jiān)視wifi狀態(tài)以更新switch組件。在其初始化時(shí)new一個(gè) BroadcastReceiver mReceiver,并在onResume時(shí)注冊(cè),在onPause時(shí)注銷。監(jiān)聽3個(gè)action:
WIFI_STATE_CHANGED_ACTION, SUPPLICANT_STATE_CHANGED_ACTION, NETWORK_STATE_CHANGED_ACTION,在wifi狀態(tài)改變時(shí),調(diào)用handleWifiStateChanged()來更新switch組件狀態(tài);而另外2個(gè)action則調(diào)用了handleStateChanged()而此方法現(xiàn)在內(nèi)容為空。開關(guān)wifi:onCheckedChanged()中調(diào)用WifiManager.setWifiEnabled(boolean)進(jìn)行開關(guān)
3 BluetoothEnabler
com.android.settings.bluetooth.BluetoothEnabler 和WiFiEnabler類似,用來開關(guān)藍(lán)牙,監(jiān)視藍(lán)牙狀態(tài)并更新switch組件。同樣的 remuse時(shí)注冊(cè)了ACTION_STATE_CHANGED,pause時(shí)注銷;使用handleStateChanged()更新switch組件的狀態(tài);開關(guān)藍(lán)牙:使用LocalBluetoothAdapter.setBluetoothEnabled(boolean),實(shí)際上是BluetoothAdapter.enable()和disable()
2014-7-7
wifi設(shè)置--二級(jí)菜單
設(shè)置的R.xml.settings_headers資源布局了設(shè)置的內(nèi)容,其中第一項(xiàng)為wifi,其中指明 header的fragment :com.android.settings.wifi.WifiSettings,
Scanner 一個(gè)主線程的handler,在resume期間每個(gè)10s進(jìn)行一次wifi掃描。
mReceiver 監(jiān)聽wifi相關(guān)的8中action,并做相應(yīng)的處理。調(diào)用handleEvent(context,intent),根據(jù)intent進(jìn)行更新wifi狀態(tài)、刷新AP列表、更新連接狀態(tài)等操作。
mSetupWizardMode標(biāo)示是否是第一次啟動(dòng),首次啟動(dòng)設(shè)備連接wifi時(shí)亦在這里
onActivityCreated()中獲取wifiManager等;初始化3種wifi操作的結(jié)果監(jiān)聽,連接、保存、忘記,用來操作結(jié)果失敗時(shí)給用戶一個(gè)Toast提示操作失敗;在非mSetupWizardMode時(shí),添加
Switch組件(右上角的切換開關(guān))到actionbar,并和WifiEnabler(wifi開關(guān)和監(jiān)視器)關(guān)聯(lián),注冊(cè)長(zhǎng)按事件registerForContextMenu()
onResume() fragment可見時(shí),啟用WifiEnabler,注冊(cè)mReceiver,刷新wifi--AccessPoint(AP)列表;
onPause() 焦點(diǎn)不在此fragment時(shí),禁用WifiEnable,注銷mReceiver,停止Scanner;
刷新wifi列表updateAccessPoints(),在wifi可用時(shí),通過constructAccessPoints()獲取AccessPoint集合并依次add到preference中,而constructAccessPoints()是通過WifiManager的
getConfiguredNetworks()和getScanResults()的結(jié)果進(jìn)行過濾排序后得到的可用wifi列表。
wifi連接---click某條AccessPoint時(shí),執(zhí)行onPreferenceTreeClick():若此AP以保存密碼則使用WIfiManager的隱藏接口connect()直接連接,若之前沒保存,則showDialog(WIFI_DIALOG_ID)
,顯示自定義的com.android.settings.wifi.WifiDialog,點(diǎn)擊對(duì)話框的按鈕后onClick()被調(diào)用,根據(jù)button的id進(jìn)行不同操作(忘記AP或提交、保存密碼-之后刷新AP列表)。
長(zhǎng)按某AP項(xiàng)時(shí),調(diào)用onCreateContextMenu(),根據(jù)此AP是否已保存,顯示 連接網(wǎng)絡(luò) 或者 忘記、修改 網(wǎng)絡(luò),選中菜單調(diào)用onContextItemSelected()進(jìn)行連接、忘記或修改網(wǎng)絡(luò)操作。
2014-7-8
Bluetooth設(shè)置-- 二級(jí)菜單
主要的輔助類有
BluetoothEnabler 藍(lán)牙開關(guān)的控制,狀態(tài)監(jiān)聽;
BluetoothDiscoverableEnabler 藍(lán)牙可見性的管理幫助類,控制可見性以及延遲若干時(shí)間后不可見;提供pause() resume()在fragment的pause
和resume時(shí)調(diào)用它們,就如同BluetoothEnabler,WifiEnabler一樣;
BluetoothDevicePreference 藍(lán)牙列表中一個(gè)條目(包括未配對(duì),已配對(duì),已連接),被點(diǎn)擊時(shí)根據(jù)自身狀態(tài)做不同處理,未配對(duì)的開始配對(duì)流程
pair(),已配對(duì)的開始連接流程 mCachedDevice.connect(),已連接的斷開連接askDisconnect();
LocalBluetoothAdapter (使用單例模式)提供一個(gè)訪問BluetoothAdapter的本地接口,中轉(zhuǎn)了如下的接口:
cancelDiscovery() 取消掃描附件藍(lán)牙設(shè)備
enable()/disable() 僅開關(guān)藍(lán)牙(不同步狀態(tài))
getState(), 獲取藍(lán)牙開關(guān)的狀態(tài)
isDiscovering() 是否正在掃描附件藍(lán)牙
isEnabled() 藍(lán)牙是否開啟
setDiscoverableTimeout() 設(shè)置可見性時(shí)長(zhǎng)
setName() 修改本設(shè)備藍(lán)牙名稱
setScanMode() 設(shè)置掃描模式(是否可見)
startScanning()/stopScanning()開始/停止掃描藍(lán)牙設(shè)備
syncBluetoothState() 使藍(lán)牙狀態(tài)和當(dāng)前緩存的狀態(tài)一致
setBluetoothEnabled()開關(guān)藍(lán)牙
影響設(shè)備的連接和綁定狀態(tài)由CachedBluetoothDeviceManager,BluetoothEventManager,和LocalBluetoothProfileManager處理。
本fragment主要的邏輯如下:
mReceiver在resume狀態(tài)注冊(cè)藍(lán)牙名稱變動(dòng)的action,有變動(dòng)時(shí)更新UI上的名稱;
包括兩組Preference列表: 已配對(duì)的設(shè)備列表 和 可用(掃描到的)設(shè)備列表
從父類的onCreate可見:先通過addPreferencesForActivity填充preference列表(添加preferencescreen),然后在onResume()中調(diào)用
updateContent()進(jìn)行刷新列表,updateContent()根據(jù)藍(lán)牙狀態(tài)和掃描狀態(tài)更新列表:
1 獲取PreferenceScreen ps.
2 藍(lán)牙開的狀態(tài) STATE_ON:
2.1 清空ps ps.removeAll()
2.2 初始化本設(shè)備的preference,然后添加到ps中
2.3 初始化已配對(duì)的preference并添加配對(duì)的列表到mPairedDevicesCategory,記錄其數(shù)量num1,并添加到ps中
2.4 初始化可用設(shè)備的preference并添加可用設(shè)備列表到mAvailableDevicesCategory,記錄其數(shù)量num2,并添加到ps中
注意:2.3 2.4的添加都是使用addDeviceCategory(x,x,filter)添加符合filter的設(shè)備
2.5 若num2為0, 則移除mAvailableDevicesCategory
2.6 若num1為0, 則移除mPairedDevicesCategory,同時(shí)若掃描參數(shù)true則開始掃描附近設(shè)備startScanning();
2.7 重建options menu,然后 return 返回。
3 藍(lán)牙狀態(tài)為 正在關(guān)閉、已關(guān)閉 和正在打開時(shí),設(shè)置messageId(即設(shè)置消息字符id),移除preferences的所有條目,設(shè)置EmptyView的消息為前面指定的message,重建options menu。
2014-7-9
設(shè)置 ---- 流量使用情況
流量使用的UI位于fragment:com.android.settings.DataUsageSummary,主要用來統(tǒng)計(jì)應(yīng)用使用的移動(dòng)數(shù)據(jù)信息。
ChartGridView 網(wǎng)格式的流量View,
它的加載流程如下
onCreate()中
1 獲取 網(wǎng)絡(luò)管理服務(wù)、網(wǎng)絡(luò)狀態(tài)服務(wù)、網(wǎng)絡(luò)策略管理以及網(wǎng)絡(luò)連接管理 的實(shí)例引用
2 通過StatsService.openSession()打開stateSession
3 獲取sharedPreference中的是否顯示wifi和以太網(wǎng)網(wǎng)絡(luò)的流量信息;若手機(jī)radio未就緒,則設(shè)置兩者為ture
4 設(shè)置options menu可見
onCreateView()中
1 加載布局R.layout.data_usage_summary
2 初始化UidDetailProvider ,然后尋找相關(guān)View:tabhost,tabs_container,tabs,list,header
3 設(shè)置tabhost,并監(jiān)聽tab變化;設(shè)置listView的屬性,添加header
4 添加 移動(dòng)數(shù)據(jù)開關(guān)的switch,并設(shè)置checked變動(dòng)監(jiān)聽 mDataEnabledListener;
添加 數(shù)據(jù)限制的checkbox,并設(shè)置click監(jiān)聽 mDisableAtLimitListener
5 設(shè)置ChartDataUsageView的Listener,并bindNetworkPolicy()
6 設(shè)置CycleView及其CycleAdapter,
7 初始化DataUsageAdapter,并設(shè)置為listview的adapter,設(shè)置listview的item點(diǎn)擊監(jiān)聽mListListener。
onResume()中
1 根據(jù)activity的intent計(jì)算應(yīng)顯示那個(gè)tab,是wifi還是數(shù)據(jù)流量的
2 更新tabs, updateTabs():先clear所有tabs,再判斷應(yīng)該加載哪個(gè)tab
3 在AsyncTask中,updateBody更新當(dāng)前tab,重新加載圖標(biāo)數(shù)據(jù)
數(shù)據(jù)流量應(yīng)用列表的加載,即DataUsageAdapter的數(shù)據(jù)獲取和排序:
流量變化引起bindStats(stats,uids){ 根據(jù)uids,利用stats獲取AppItem,即一個(gè)應(yīng)用的使用流量信息,最終add到mItems,并對(duì)其排序}
getView()中根據(jù)mItems生成對(duì)應(yīng)的UidDetail(),然后根據(jù)UidDetail設(shè)置需要的itemView。
這里涉及到不少內(nèi)部API,需要根據(jù)framework層的隱藏API一起分析,才更清晰。
2014-7-10
設(shè)置 ---- 流量使用情況(2)
應(yīng)用的流量統(tǒng)計(jì)獲取來源:
從前文知,com.android.settings.DatausageSummary$DataUsageAdapter.bindStats()用來獲取每個(gè)應(yīng)用的瀏覽信息。
android.net.NetworkStats系統(tǒng)的一個(gè)隱藏API;它是網(wǎng)絡(luò)統(tǒng)計(jì)的集合,包括每個(gè)UID的統(tǒng)計(jì)信息,內(nèi)部主要包括幾個(gè)數(shù)組:
int[] uid, long[] rxBytes, rxPackets, txBytes, txPackets;以及這些數(shù)組(size一樣)的size
NetworkStats.Entry從其字段看,表示一個(gè)UID的某次流量信息:uid,上下行字節(jié)/包數(shù)量,uid相同時(shí)疊加流量。
bindStats()是在mSummaryCallbacks這個(gè)loader中onLoadFinished()被回調(diào)的,
而此mSummaryCallbacks 是在updateDetailData()中restartLoader(id,Bundle,mSummaryCallbacks)的回調(diào),LoaderCallbacks 在加載完成后回調(diào)。bundle中含有要統(tǒng)計(jì)的(從ChartDataUsageView中獲取的)起止時(shí)間,SummaryForAllUidLoaderloader的創(chuàng)建是通過SummaryForAllUidLoader建一個(gè)加載NetworkStats的Loader。從SummaryForAllUidLoader的loadInBackground()中可見統(tǒng)計(jì)數(shù)據(jù)是在work線程中用mStatsSession.getSummaryForAllUid()獲取的。
mStatsSession是通過mStatsService.openSession()得到的,mStatsService=INetworkStatsService.Stub.asInterface(ServiceManager.getService(Context.NETWORK_STATS_SERVICE));而這個(gè)service的實(shí)現(xiàn)則位于framework/base/services/下的com.android.server.net.NetworkStatsService;這個(gè)service這里就不繼續(xù)分析了。
流量網(wǎng)格圖ChartDataUsageView 在DataUsageSummary中的mChart設(shè)置監(jiān)聽mChartListener,當(dāng)統(tǒng)計(jì)時(shí)間范圍變動(dòng)時(shí),onInspectRangeChanged()執(zhí)行,即調(diào)用updateDetailData()進(jìn)行重啟一個(gè)Loader,用來更新本fragment下面的應(yīng)用流量統(tǒng)計(jì)列表ListView。
2014-7-11
更多/無線網(wǎng)絡(luò)設(shè)置--設(shè)置
com.android.settings.WirelessSettings
此設(shè)置項(xiàng)主要設(shè)置設(shè)備的無線網(wǎng)絡(luò),主要包括 飛行模式,默認(rèn)短信應(yīng)用,NFC,androidBeam,移動(dòng)網(wǎng)絡(luò),×××,手機(jī)網(wǎng)絡(luò),手機(jī)套餐,WIMAX,nsd,代理和小區(qū)廣播。
onCreate中,獲取需要的服務(wù)如ConnectivityManager,TelephonyManager,加載資源R.xml.wireless_settings,設(shè)置相關(guān)的監(jiān)聽,然后根據(jù)設(shè)備的具體配置特性移除不支持的條目,比如NFC,WIMAX,nsd等;初始化 AirplaneMode,NFC,NSD的監(jiān)聽,它們和前面的wifiEnabler,bluetoothEnabler一樣。
其中短信應(yīng)用的配置的初始化也在此處,主要是獲取短信應(yīng)用的集合,并列出相關(guān)應(yīng)用的名稱;而獲取來源是內(nèi)部API即com.android.internal.telephony.SmsApplication,短信應(yīng)用用SmsApplicationData表示,包括名稱,包名,接收短彩信的class,以及uid;最后將所有短信應(yīng)用添加到SmsListPreference這個(gè)listPreference。
在onResume和onPause中,主要對(duì)Airplane,NFC,NSD的監(jiān)聽等做了恢復(fù)和暫停;
在下一級(jí)的選項(xiàng)/目錄中,有NFC.AndroidBeam 移動(dòng)網(wǎng)絡(luò) ××× 以及 代理。其中移動(dòng)網(wǎng)絡(luò)項(xiàng),即com.android.settings.TetherSettings。
onCreate中,加載資源R.xml.tether_prefs,包括四項(xiàng):USB共享網(wǎng)絡(luò),便攜式 WLAN 熱點(diǎn),設(shè)置WLAN熱點(diǎn),藍(lán)牙共享網(wǎng)絡(luò);
NFC.androidbeam中 com.android.settings.nfc.AndroidBeam
主要包括一個(gè)NFC的Switch組件,以及一個(gè)androidBeam的說明;在Switch切換時(shí),通過android.os.NfcAdapter的enableNdefPush和disableNdefPush方法來啟用/禁用NDEF push功能; 而其API enable和disable才是NFC的啟用/禁用。
2014-7-14
HOME設(shè)置 -- 默認(rèn)桌面的設(shè)置
從一級(jí)菜單中Settings.java中的updateHomeSettingHeaders()可見,當(dāng)設(shè)備中僅有一個(gè)Launcher時(shí),會(huì)移除此條目。
有多個(gè)Launcher時(shí),進(jìn)入此fragment后,會(huì)更新每個(gè)Launcher,即buildHomeActivitiesList()中會(huì)找到每一個(gè)Launcher,并將它們添加到ArrayList中,同時(shí)new一個(gè)preference添加到本preferenceGroup中且有默認(rèn)Launcer時(shí)保留其Preference未mCurrentHome,完成后,設(shè)置mCurrentHome為選中狀態(tài)。
修改默認(rèn)Launcher的方法:由mHomeClickListener中可見,當(dāng)click非默認(rèn)Launcher的preference時(shí),執(zhí)行makeCurrentHome()來修改當(dāng)前默認(rèn)Launcher:
1 取消當(dāng)前Launcher狀態(tài),并設(shè)置新Launcher的狀態(tài);2 通過PackageManager.replacePreferredActivity()來替換默認(rèn)的activity即Launcher。
聲音設(shè)置
即com.android.settings.SoundSettings這個(gè)Fragment,
onCreate()中
1 獲取AudioManager, 加載資源 R.xml.sound_settings,
2 根據(jù)設(shè)備配置,移除若干preference; 例如:若非CDMA的Phone,則去掉emergency_tone;
3 查找相關(guān)preference,如震動(dòng),撥號(hào)鍵盤音效,觸摸提示音,觸摸時(shí)震動(dòng),鎖屏提示音,基座等;
onResume()中
4 起一個(gè)work線程,更新鈴聲名稱,和通知鈴聲的詳細(xì)信息 new Thread(mRingtoneLookupRunnable).start();注冊(cè)dock的BroadcastReceiver
音量的子條目如下
a 音量 --控制鈴聲、通知、鬧鐘音量的特殊Fragment即 RingerVolumePreference
包括四個(gè)Seekbar的條目,調(diào)節(jié)其音量: 媒體,鈴聲,通知,鬧鐘;
這些設(shè)置的click事件處理大致如下:
1 mVibrateWhenRinging響鈴時(shí)震動(dòng),將0/1存到Settings的provider,Settings.System.VIBRATE_WHEN_RINGING
2 dtmf-撥號(hào)鍵盤音效同1;觸屏聲音,同1且通過AudioManager修改音效;同樣的還有震動(dòng)反饋,鎖屏聲音,基座等設(shè)置。
2014-7-15
顯示設(shè)置
即 com.android.settings.DisplaySettings
onCreate中,加載資源 R.xml.display_settings,從這個(gè)xml資源中可見其可設(shè)置項(xiàng)目如下:
1 亮度 即com.android.settings.BrightnessPreference,click后發(fā)一個(gè)broadcast以顯示亮度調(diào)節(jié)dialog;
2 壁紙 轉(zhuǎn)到com.android.settings.WallpaperTypeSettings處理
3 自動(dòng)旋轉(zhuǎn)屏幕 key:accelerometer_title
4 休眠 key: screen_timeout,一個(gè) ListPreference
5 互動(dòng)屏保 轉(zhuǎn)到com.android.settings.DreamSettings
6 字體大小 即com.android.settings.WarnedListPreference,但在此修改字體
7 收到通知時(shí)指示燈閃爍 key:notification_pulse 一個(gè)checkbox
8 投射屏幕 轉(zhuǎn)到com.android.settings.wfd.WifiDisplaySettings
接下來,根據(jù)設(shè)備的特性/配置,移除不必要的Preference;再給相關(guān)preference設(shè)置監(jiān)聽,即setOnPreferenceChangeListener()和setOnPreferenceClickListener(),以便在用戶操作preference時(shí)候做相應(yīng)的相應(yīng),即執(zhí)行 onPreferenceChange()和onPreferenceTreeClick();根據(jù)當(dāng)前設(shè)置修改顯示條目,如更新當(dāng)前的休眠超時(shí)time。
onResume中主要更新了當(dāng)前的配置項(xiàng)目,自動(dòng)旋轉(zhuǎn)屏幕,字體大小,互動(dòng)屏保。
壁紙的設(shè)置- WallpaperTypeSettings 流程如下:
加載R.xml.wallpaper_settings,并查找PackageManager中可設(shè)置壁紙的app組件,然后設(shè)置每一個(gè)組件對(duì)應(yīng)一個(gè)Preference,并設(shè)置preference對(duì)應(yīng)的intent。即選中某個(gè)preference后,轉(zhuǎn)到對(duì)應(yīng)的組件設(shè)置壁紙。
2014-7-16
存儲(chǔ)設(shè)置
即com.android.settings.deviceinfo.Memory主要用來(按類型)查看設(shè)備中的文件,列出每類所占用設(shè)備的大小。
onCreate()中獲取 UsbManager,StorageManager, 添加內(nèi)部存儲(chǔ)Category,然后列出StorageManager中包含的每個(gè)category,并addCategory()添加到此fragment;這里使用StorageVolumePreferenceCategory來初始化每個(gè)category。
onResume()中注冊(cè)兩個(gè)intentFilter到mMediaScannerReceiver,并onResume每個(gè)category;
onPause() 中注銷mMediaScannerReceiver,并且onPause每個(gè)category。
category的click處理流程在onPreferenceTresClick(),主要如下:
對(duì)于cache項(xiàng),顯示一個(gè)ConfirmClearCacheFragment的對(duì)話框后返回(清空應(yīng)用的緩存的邏輯也在此,清空后的回調(diào)為ClearCacheObserver);
其他的,通過StorageVolumePreferenceCategory.intentForClick()獲取一個(gè)intent,若intent不空,則啟動(dòng)此intent指向的activity即可,若intent是空,則說明這個(gè)category是usb存儲(chǔ),則執(zhí)行掛載、卸載的過程(掛載的主要執(zhí)行mountService.mountVolume()即可,卸載則是顯示一個(gè)AlertDialog,確認(rèn)后執(zhí)行卸載doUnmount(),同樣是由mountService.unmountVolume()完成的)。由此可見,大多數(shù)category的click處理還是它們本身的intent決定。
下面說明下StorageVolumePreferenceCategory,此類 表示 內(nèi)部存儲(chǔ)器 和 外置SD卡 (有些設(shè)備稱 USB存儲(chǔ))
內(nèi)部存儲(chǔ)包括包括這幾個(gè) Preference: (后跟click的intent)
1 總?cè)萘縨ItemTotal null
2 可用mItemAvailable null
3 應(yīng)用程序mItemApps, 指向com.android.settings.Settings.ManagerApplicationsActivity即應(yīng)用程序管理
4 圖片視頻mItemDcim, action: Intent.ACTION_VIEW data: Media.EXTERNAL_CONTENT_URI
5 音頻mItemMusic, action: Intent.ACTION_GET_CONTENT type: audio/mp3
6 下載內(nèi)容mItemDownloads, action: DownloadManager.ACTION_VIEW_DOWNLOADS
7 緩存mItemCache,
8 雜項(xiàng)(其他)mItemMisc 指向 MiscFilesHandler
外置SD卡/USB存儲(chǔ)的preference:
1 總?cè)萘縨ItemTotal,可用mItemAvailable 同上
2 卸載 null
3 格式化 action: Intent.ACTION_VIEW 指向 com.android.settings.MediaFormat
2014-7-17
電量/電池
com.android.settings.fuelgauge.PowerUsageSummary主要用來顯示當(dāng)前電量,以及當(dāng)前耗電量較多的前十個(gè)應(yīng)用/服務(wù)。
BatteryStatsHelper接收 應(yīng)用/服務(wù)耗電量信息的輔助類
主Fragment的主要加載流程如下: (PowerUsageSummary)
首先 實(shí)例化廣播mBatteryInfoReceiver:用來在收到電量變化的廣播后更新耗電量列表refreshStats()
然后 實(shí)例化mHandler: 用來傳給mStatsHelper,
onAttach() 實(shí)例化BatteryStatsHelper,即 mStatsHelper
onCreate() 初始化mStatsHelper; 加載R.xml.power_usage_summary,并定位preference
onResume() 注冊(cè)廣播mBatteryInfoReceiver; 刷新耗電量列表 refreshStats()
onPause() 注銷廣播mBatteryInfoReceiver; mStatsHelper.pause();移除mHandler的message
onDestory() mStatsHelper.destroy()
其中最重要的刷新耗電量列表refreshStats()如下:
1 先清空mAppListGroup列表,并設(shè)置其排序不按照添加順序顯示;
2 添加耗電量的總信息mBatteryStatusPref
3 若mStatsHelper的返回列表中應(yīng)用/服務(wù)的個(gè)數(shù)小于10則return
4 通過mStatsHelper獲取耗電量的列表 List<BatterySipper> usageList
5 依次遍歷usageList,生成對(duì)應(yīng)的preference,添加到mAppListGroup;
BatteryStatsHelper說明:
在刷新時(shí),即refreshStats() 中(重)啟一個(gè)Thread(最低優(yōu)先級(jí)),(若Thread運(yùn)行,先abort,再啟此線程),此線程主要是:依次從mRequestQueue中取出一個(gè)BatterySipper,BatterySipper.loadNameAndIcon(),直到mRequestQueue中為空或者abort才終止Thread。
BatterySipper表示一個(gè)應(yīng)用或服務(wù)的耗電量信息,包括 包名,圖標(biāo),耗電量,使用時(shí)間,cpu時(shí)間,GPS、WIFI、等時(shí)間;而此類主要的方法加載名字和圖標(biāo)loadNameAndIcon(),從PackageManager中加載icon,name,packageName,并發(fā)送message到mHandler以便更新列表的顯示
2014-7-18
應(yīng)用程序管理
com.android.settings.application.ManagerApplicationsActivity
onCreate中,獲取Intent,根據(jù)intent獲取默認(rèn)的加載列表(TabInfo),添加tab包括: 已下載,(USB 存儲(chǔ)設(shè)備(若USB可)),正在運(yùn)行,全部,已停用。
這里綁定了服務(wù)com.android.defcontainer.DefaultContainerService,
onCreateView中初始化ViewPager,MyPagerAdapter,PagerTabString,并設(shè)置監(jiān)聽,并設(shè)置當(dāng)前Tab為onCreate中的默認(rèn)tab
onResume中,更新當(dāng)前Tab,NumTabs,和菜單
onPause中,同樣pause每個(gè)Tab的列表
onDestoryView中 對(duì)每個(gè)Tab做detachView
當(dāng)選中某一應(yīng)用時(shí),則執(zhí)行startApplicationDetailsActivity()到此應(yīng)用的詳情界面,即InstalledAppDetails,同時(shí)傳遞packageName給它,
InstalledAppDetails用來顯示一個(gè)應(yīng)用的詳情信息,
mHandler中主要接收三個(gè)msg:清空數(shù)據(jù),清空緩存,卸載。
onCreate中,通過retrieveAppEntry()接收Intent中的packageName,并根據(jù)包名得到一個(gè)AppEntry(AppEntry包括應(yīng)用的id,label,占據(jù)的內(nèi)部、外部存儲(chǔ)空間,圖標(biāo)等信息),并根據(jù)AppEntry獲取PackageInfo,并更新mAppEntry和mPackageInfo
onCreateView,加載R.layout.installed_app_details,并find到相關(guān)View(如TextView,CheckBox,CompoundButton),設(shè)置Button的初始狀態(tài)
onResume中,主要刷新UI,即refreshUI(),并返回是否成功刷新,主要流程是:
判斷一些初始狀態(tài), 然后從PackageManager中獲取HomeActivity即桌面的activity,然后獲取默認(rèn)的應(yīng)用(主要判斷本應(yīng)用是否為默認(rèn)應(yīng)用),checkForceStop()中設(shè)置“停止運(yùn)行”按鈕的啟用禁用,判斷依據(jù)為:1 是否含有設(shè)備管理DevicePolicyManager.packageHasActivityAdmins(packageName)),2 標(biāo)識(shí)mAppEntry.info.flags ;在enable時(shí),監(jiān)聽click,showDialogInner(),在AlertDialog中的確認(rèn)按鈕click后,強(qiáng)制終止應(yīng)用,即getOwner().forceStopPackage(packageName)。
2014-7-21
應(yīng)用程序管理(2)
應(yīng)用程序詳情界面InstalledAppDetails,如之前所述,這里說明下它的幾種操作
初始化狀態(tài)在initUninstallButtons(),點(diǎn)擊處理即onClick()
1 卸載/卸載更新 即按鈕mUninstallButton
若是系統(tǒng)應(yīng)用的升級(jí)版本,則show一個(gè)對(duì)話框,id為DLG_FACTORY_RESET=2;
若是系統(tǒng)應(yīng)用且狀態(tài)為啟用,則show一個(gè)dialog,id DLG_DISABLE = 7;
若是系統(tǒng)應(yīng)用但狀態(tài)為禁用,則啟動(dòng)異步任務(wù)DisableChanger()來啟用它;
若應(yīng)用是為當(dāng)前用戶安裝的,則執(zhí)行卸載uninstallPkg(pkgName,true,false);
若應(yīng)用不為當(dāng)前用戶安裝,則執(zhí)行卸載uninstallPkg(pkgName,false,false)。
其中卸載更新和卸載應(yīng)用是通過uninstallPkg(){則使用Action="android.intent.action.UNINSTALL_PACKAGE",包名的URI實(shí)例一intent,啟動(dòng)Activity來卸載此應(yīng)用},啟用禁用應(yīng)用是通過DisableChanger的AsyncTask{使用packageManager.setApplicationEnabledSetting()}。
2 清空默認(rèn)設(shè)置 即按鈕mActivitiesButton
refreshUI()中更新其狀態(tài)以及click監(jiān)聽,清除默認(rèn)設(shè)置的方法如下:
通過PackageManager的clearPackagePreferredActivities()清除默認(rèn),然后通過UsbManager的clearDefaults()清除usb中的中的默認(rèn),最后更新mActivitiesButton的顯示狀態(tài)。
4 清除數(shù)據(jù) mClearDataButton
啟動(dòng)AppEntry.info中指定的activity來清除應(yīng)用的數(shù)據(jù),或者顯示id為DLG_CLEAR_DATA的dialog來清除。實(shí)際為使用ActivityManager的clearApplicationUserData()方法來清除應(yīng)用的數(shù)據(jù)。
5 清除緩存 mClearCacheButton
即使用PackageManager的deleteApplicationCacheFiles()清除緩存。
權(quán)限管理部分
refreshUI()中,刷新了權(quán)限的列表,其中AppSecurityPermissions asp為本應(yīng)用的權(quán)限,這里對(duì)SMS短信做了單獨(dú)處理,應(yīng)用是4.4系統(tǒng)多了的設(shè)置默認(rèn)短信應(yīng)用的功能引起的;然后在權(quán)限列表security_settings_list中添加了權(quán)限列表的View,通過asp.getPermissionsViewWithRevokeButtons()獲取的權(quán)限View。
2014-7-22
安全設(shè)置
SecuritySettings.java
在onResume中加載資源R.xml.security_settings,并根據(jù)當(dāng)前狀態(tài)顯示/移除一些項(xiàng),在7月3號(hào)的閱讀已經(jīng)說明鎖屏設(shè)置以及未知源的處理,這里不再復(fù)述。
SIM卡的PIN碼設(shè)置:
1 若TelephonyManager.hasIccCard()為false即設(shè)備沒有SIM卡,則移除此項(xiàng);
2 若TelephonyManager.getSimState()是absent或未知,則禁用此項(xiàng)(可見但不可設(shè)置);
加密手機(jī)/平板
根據(jù) android.app.admin.DevicePolicyManager.getStorageEncryptionStatus()的返回狀態(tài)加載 R.xml.security_settings_encrypted(已經(jīng)加密)或者R.xml.security_settings_unencrypted(需要加密/可以加密),加密最終到CryptKeeperConfirm.java中的Blankz這個(gè)activity,在這里加載它的布局R.layout.crypt_keeper_blank后,就通過服務(wù)StatusBarManager禁用了狀態(tài)欄的下拉、通知、警告框、HOME按鍵、搜索鍵、返回鍵以及最近的任務(wù)列表鍵等,然后向handler發(fā)了一個(gè)延遲700ms的runnable,這個(gè)runnable就是上層應(yīng)用最終進(jìn)行加密調(diào)用的位置,如下:
1 通過ServiceManager利用binder機(jī)制獲取mount服務(wù), mountService
2 調(diào)用mountService的encryptStorage(密碼),進(jìn)行加密
2014-7-23
語言和輸入法設(shè)置
com.android.settings.inputmethod.InputMethodAndLanguageSettings
1 語言 Fragment com.android.settings.LocalePicker繼承自 com.android.internal.app.LocalePicker是一個(gè)ListFragment
從com.android.internal.app.LocalePicker中,onActivityCreated()中設(shè)置adapter,即獲取系統(tǒng)支持的語言 Locale;當(dāng)click時(shí)調(diào)用onListItemClick(),若listener不空,則執(zhí)行l(wèi)istener的onLocaleSelected(),即 在com.android.settings.LocalePicker中的onLocaleSelected(),若是多用戶則在Dialog中提示,否則執(zhí)行一個(gè)runnable來修改系統(tǒng)語言,runnable如下:移除dialog(若有),虛擬按下返回鍵,使用LocalePicker.updateLocale(mTargetLocale)更新系統(tǒng)語言。
獲取系統(tǒng)支持的語言主要在com.android.internal.app.LocalePicker的adapter中,
1) 通過AssetManager.getLocales()獲取支持的語言列表 localeList
2) 通過resources獲取資源R.array.special_locale_codes和R.array.special_locale_names,即語言的編碼和名稱
3) 對(duì)locals的列表排序,然后遍歷其元素 s,(每個(gè)local的長(zhǎng)度必須為5,前兩個(gè)字符表示語言,后兩個(gè)字符表示國家)
即 language = s.substring(0,2); country = s.substring(3,5);
Local l = new Local(language, country); 然后將每個(gè)local添加到數(shù)組preprocess[],localeInfos[]
4) 對(duì)localeInfos排序,使用localeInfos填充ArrayAdapter,即設(shè)置item的每個(gè)TextView setText(label) setTextLocale(locale)
接下來的是 拼寫檢查,個(gè)人詞典, 輸入法, 物理鍵盤,語音識(shí)別,觸控板,游戲控制器。
輸入法的設(shè)置
在onResume的最后,更新了輸入法的列表,即updateInputMethodPreferenceViews(),更新流程如下:
1) 首先,移除所有的輸入法preference,然后再清空輸入法的數(shù)組列表mInputMethodPreferenceList;
2) 從InputMethodSettingValuesWrapper中獲取最新的輸入法列表,遍歷列表,每個(gè)元素構(gòu)造一個(gè)Preference并添加到mInputMethodPreferenceList列表,然后添加到視圖mKeyboardSettingsCategory中
3) 更新每個(gè)輸入法的狀態(tài)和名稱updatePreferenceViews() updateCurrentImeName()
2014-7-24
日期和時(shí)間
這里注冊(cè)廣播mIntentReceiver,監(jiān)聽action--ACTION_TIME_TICK, ACTION_TIME_CHANGED, ACTION_TIMEZONE_CHANGED.
當(dāng)時(shí)間、日期或時(shí)區(qū)變化時(shí),調(diào)用updateTimeAndDateDisplay()更是UI顯示。
當(dāng)click時(shí)間/日期的Preference時(shí),創(chuàng)建相應(yīng)的對(duì)話框DatePickerDialog,TimePickerDialog來修改時(shí)間,設(shè)置的方法如下:
設(shè)置后回調(diào)到本class,OnTimeSetListener.onTimeSet()和OnDateSetListener.onDateSet(),然后 setTime或setDate后,更新UI的顯示,updateTimeAndDateDisplay(),而設(shè)置時(shí)間、日期的接口如下:
時(shí)間的設(shè)置在setTime(),主要是調(diào)用 Alarm服務(wù)的setTime(long )來設(shè)置;
日期的設(shè)置在setDate(), 方法和 時(shí)間設(shè)置一致,只是生成long的參數(shù)有差異。
12/24小時(shí)格式,通過設(shè)置Settings.System.TIME_12_24的值 修改settingProvider;
關(guān)于手機(jī)
首先在onCreate中加載資源R.xml.device_info_settings,包括如下選項(xiàng):
1 系統(tǒng)更新 Intent, android.settings.SYSTEM_UPDATE_SETTINGS
2 其他系統(tǒng)更新 指向res/strings中指向的資源 地址
3 狀態(tài)信息 轉(zhuǎn)到com.android.settings.deviceinfo.Status
4 法律信息
5 安全信息 Intent android.settings.SAFETY
6 監(jiān)管信息 Intent android.settings.SHOW_REGULATORY_INFO
7 型號(hào) key device_model 來源 Build.MODEL
8 Android版本 key firmware_version 來源 Build.VERSION.RELEASE
9 設(shè)備ID key fcc_equipment_id 來源 SystemProperties的 ro.ril.fccid
10 基帶版本 key baseband_version 來源 SystemProperties的 gsm.version.baseband
11 內(nèi)核版本 key kernel_version 來源 getFormattedKernelVersion(),即文件 "/proc/version",并格式下string
12 版本號(hào) key build_number 來源 Build.DISPLAY
13 SELinux狀態(tài) key selinux_status 來源 SELinux的狀態(tài) (未啟用/許可/執(zhí)行中)
但上面的Preference需要根據(jù)設(shè)備的具體配置做改動(dòng),比如:
SELinux狀態(tài),安全信息,設(shè)備ID需要根據(jù)SystemProperties中對(duì)于的key值來決定 移除or保留;基帶版本 則在 wifi-only的設(shè)備中移除。
連續(xù)點(diǎn)擊幾次android的版本號(hào)出現(xiàn)的彩蛋可在onPreferenceTreeClick()見其處理:
System.arraycopy(mHits, 1, mHits, 0, mHits.length-1);
mHits[mHits.length-1] = SystemClock.updateMillis();
if(mHits[0] >= (SystemClock.updateMillis() - 500)) 則轉(zhuǎn)到Activity:com.android.internal.app.PlatLogoActivity
開啟調(diào)試模式的處理也在這里:
在 sharedPreference中存的mDevHitCountdown整數(shù),當(dāng)連續(xù)7次才會(huì)開啟開發(fā)者選項(xiàng)的顯示。
在這里使用了個(gè) R.plurals.的資源,就是指的 單復(fù)數(shù),源代碼中的使用方法是:
getResources().getQuantityString(R.plurals.show_dev_countdown, mDevHitCountdown, mDevHitCountdown)
對(duì)應(yīng)的在res/values-zh-rCN/strings.xml中的內(nèi)容如下:
<plurals name="show_dev_countdown">
<item quantity="one" msgid="5295687242294085452">"只需 <xliff:g id="STEP_COUNT">%1$d</xliff:g> 步操作即可進(jìn)入開發(fā)者模式。"</item>
<item quantity="other" msgid="6722953419953594148">"只需 <xliff:g id="STEP_COUNT">%1$d</xliff:g> 步操作即可進(jìn)入開發(fā)者模式。"</item>
</plurals>
當(dāng)然主要是用來區(qū)分應(yīng)用中的單復(fù)數(shù) 例如 引用資源 step 還是 steps。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。