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