Android源碼AOSP之設置Settings閱讀記錄

Android 4.4 系統的設置源碼閱讀記錄

----------2014-7-3------------------

AndroidManifest.xml

launch的activity是 Settings,另外有40多個activity繼承於它,比如設置的一級菜單: wifi,藍牙,聲音,顯示,安全,應用程序,語言和時間,關於設備等等。實際上都是這一個acitivy。

這裏從安全設置看起,SecuritySettings.java

以資源文件R.xml.security_settings_* 填充【根據當前鎖屏方式,擁有者信息,密碼顯示等具體情形,加載不同的資源或配置】,具體在createPreferenceHierarchy() 和 onResume中

以改鎖屏方式爲主線,點擊鎖屏項時,onPreferenceTreeClick調用,

key值爲KEY_UNLOCK_SET_OR_CHANGE,則轉到了fragment --- “com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment"中()(未知源-preference爲mToggleAppInstallation,則setNonMarketAppsAllowed爲false或對話框提示,確認後設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中方式。

選擇一種方式後,執行updateUnlockMethodAndFinish(方式,啓用鎖屏?),以圖案方式爲例,啓動activity--ChooseLockPattern

ChooseLockPattern

這裏它應內含其Fragment--ChooseLockPatternFragment,但沒看明白它怎麼add上的(填充到activity)。

onCreateView中加載資源R.layout.choose_lock_pattern, onClick中,根據mUiStage狀態和click的按鈕(繼續還是取消),做不同的回饋。 最終確認後執行saveChosenPatternAndFinish()保存密碼,修改鎖屏方式。

LockPatternUtils.saveLockPattern(密碼,isFallback)

LockPatternUtils.setLockPatternEnabled(true);

其中用到了一些內部的API,例如com.android.internal.widget.LockPatternUtils,和@hide的API類似,都是僅系統應用可使用的API。

非系統應用使用則需要通過一些特殊方法才能使用,例如,反射,可參見:http://blog.csdn.net/linghu_java/article/details/8283042

2014-7-4/5------------------------

Settings的一級菜單:

1 Settings.java 

   com.android.settings.Settings這個PreferenceActivity在onCreate()中調用onBuildHeaders(),此方法是重點,用來加載設置的一級菜單的:加載資源子R.xml.settings_headers,然後調用updateHeaderList()進行一定的過濾,若設備不支持wifi則去除wifi的header,(使用packagemanger的hasSystemFeature()檢測是否支持某功能/特性---wifi,藍牙,NFC);開發者選項的顯示則根據它的sharedPreference的值來確定是否顯示。

內部的HeaderAdapter 是Settings的list的adapter,(Settings重寫了setListAdapter()設置了HeaderAdapter爲ListActivity的adapter),先看wifi項,HeaderAdapter成員mWifiEnabler是WifiEnabler的實例,

2 WifiEnabler 

com.android.settings.wifi.WifiEnabler主要用來開關wifi,並監視wifi狀態以更新switch組件。在其初始化時new一個 BroadcastReceiver mReceiver,並在onResume時註冊,在onPause時註銷。監聽3個action:

WIFI_STATE_CHANGED_ACTION, SUPPLICANT_STATE_CHANGED_ACTION, NETWORK_STATE_CHANGED_ACTION,在wifi狀態改變時,調用handleWifiStateChanged()來更新switch組件狀態;而另外2個action則調用了handleStateChanged()而此方法現在內容爲空。開關wifi:onCheckedChanged()中調用WifiManager.setWifiEnabled(boolean)進行開關

3 BluetoothEnabler

com.android.settings.bluetooth.BluetoothEnabler 和WiFiEnabler類似,用來開關藍牙,監視藍牙狀態並更新switch組件。同樣的 remuse時註冊了ACTION_STATE_CHANGED,pause時註銷;使用handleStateChanged()更新switch組件的狀態;開關藍牙:使用LocalBluetoothAdapter.setBluetoothEnabled(boolean),實際上是BluetoothAdapter.enable()和disable()

2014-7-7
wifi設置--二級菜單
設置的R.xml.settings_headers資源佈局了設置的內容,其中第一項爲wifi,其中指明 header的fragment :com.android.settings.wifi.WifiSettings,
Scanner 一個主線程的handler,在resume期間每個10s進行一次wifi掃描。
mReceiver 監聽wifi相關的8中action,並做相應的處理。調用handleEvent(context,intent),根據intent進行更新wifi狀態、刷新AP列表、更新連接狀態等操作。


mSetupWizardMode標示是否是第一次啓動,首次啓動設備連接wifi時亦在這裏
onActivityCreated()中獲取wifiManager等;初始化3種wifi操作的結果監聽,連接、保存、忘記,用來操作結果失敗時給用戶一個Toast提示操作失敗;在非mSetupWizardMode時,添加


Switch組件(右上角的切換開關)到actionbar,並和WifiEnabler(wifi開關和監視器)關聯,註冊長按事件registerForContextMenu()
onResume() fragment可見時,啓用WifiEnabler,註冊mReceiver,刷新wifi--AccessPoint(AP)列表;
onPause()  焦點不在此fragment時,禁用WifiEnable,註銷mReceiver,停止Scanner;
刷新wifi列表updateAccessPoints(),在wifi可用時,通過constructAccessPoints()獲取AccessPoint集合並依次add到preference中,而constructAccessPoints()是通過WifiManager的
getConfiguredNetworks()和getScanResults()的結果進行過濾排序後得到的可用wifi列表。
wifi連接---click某條AccessPoint時,執行onPreferenceTreeClick():若此AP以保存密碼則使用WIfiManager的隱藏接口connect()直接連接,若之前沒保存,則showDialog(WIFI_DIALOG_ID)
,顯示自定義的com.android.settings.wifi.WifiDialog,點擊對話框的按鈕後onClick()被調用,根據button的id進行不同操作(忘記AP或提交、保存密碼-之後刷新AP列表)。

長按某AP項時,調用onCreateContextMenu(),根據此AP是否已保存,顯示 連接網絡 或者 忘記、修改 網絡,選中菜單調用onContextItemSelected()進行連接、忘記或修改網絡操作。

2014-7-8
Bluetooth設置-- 二級菜單
主要的輔助類有
BluetoothEnabler 藍牙開關的控制,狀態監聽;
BluetoothDiscoverableEnabler 藍牙可見性的管理幫助類,控制可見性以及延遲若干時間後不可見;提供pause() resume()在fragment的pause
和resume時調用它們,就如同BluetoothEnabler,WifiEnabler一樣;
BluetoothDevicePreference 藍牙列表中一個條目(包括未配對,已配對,已連接),被點擊時根據自身狀態做不同處理,未配對的開始配對流程
pair(),已配對的開始連接流程 mCachedDevice.connect(),已連接的斷開連接askDisconnect();
LocalBluetoothAdapter (使用單例模式)提供一個訪問BluetoothAdapter的本地接口,中轉了如下的接口:
cancelDiscovery()  取消掃描附件藍牙設備
enable()/disable() 僅開關藍牙(不同步狀態)
getState(), 獲取藍牙開關的狀態
isDiscovering() 是否正在掃描附件藍牙
isEnabled() 藍牙是否開啓
setDiscoverableTimeout() 設置可見性時長
setName() 修改本設備藍牙名稱
setScanMode() 設置掃描模式(是否可見)
startScanning()/stopScanning()開始/停止掃描藍牙設備
syncBluetoothState() 使藍牙狀態和當前緩存的狀態一致
setBluetoothEnabled()開關藍牙
影響設備的連接和綁定狀態由CachedBluetoothDeviceManager,BluetoothEventManager,和LocalBluetoothProfileManager處理。
本fragment主要的邏輯如下:
mReceiver在resume狀態註冊藍牙名稱變動的action,有變動時更新UI上的名稱;
包括兩組Preference列表: 已配對的設備列表 和 可用(掃描到的)設備列表
從父類的onCreate可見:先通過addPreferencesForActivity填充preference列表(添加preferencescreen),然後在onResume()中調用
updateContent()進行刷新列表,updateContent()根據藍牙狀態和掃描狀態更新列表:
1 獲取PreferenceScreen ps.
2 藍牙開的狀態 STATE_ON:
2.1 清空ps  ps.removeAll()
2.2 初始化本設備的preference,然後添加到ps中
2.3 初始化已配對的preference並添加配對的列表到mPairedDevicesCategory,記錄其數量num1,並添加到ps中
2.4 初始化可用設備的preference並添加可用設備列表到mAvailableDevicesCategory,記錄其數量num2,並添加到ps中
   注意:2.3  2.4的添加都是使用addDeviceCategory(x,x,filter)添加符合filter的設備
2.5 若num2爲0, 則移除mAvailableDevicesCategory
2.6 若num1爲0, 則移除mPairedDevicesCategory,同時若掃描參數true則開始掃描附近設備startScanning();
2.7 重建options menu,然後 return 返回。
3 藍牙狀態爲 正在關閉、已關閉 和正在打開時,設置messageId(即設置消息字符id),移除preferences的所有條目,設置EmptyView的消息爲前面指定的message,重建options menu。



2014-7-9
設置 ---- 流量使用情況
流量使用的UI位於fragment:com.android.settings.DataUsageSummary,主要用來統計應用使用的移動數據信息。
ChartGridView 網格式的流量View,
它的加載流程如下
onCreate()中
1 獲取 網絡管理服務、網絡狀態服務、網絡策略管理以及網絡連接管理 的實例引用
2 通過StatsService.openSession()打開stateSession
3 獲取sharedPreference中的是否顯示wifi和以太網網絡的流量信息;若手機radio未就緒,則設置兩者爲ture
4 設置options menu可見
onCreateView()中
1 加載佈局R.layout.data_usage_summary
2 初始化UidDetailProvider ,然後尋找相關View:tabhost,tabs_container,tabs,list,header
3 設置tabhost,並監聽tab變化;設置listView的屬性,添加header
4 添加 移動數據開關的switch,並設置checked變動監聽 mDataEnabledListener;
  添加 數據限制的checkbox,並設置click監聽 mDisableAtLimitListener
5 設置ChartDataUsageView的Listener,並bindNetworkPolicy()
6 設置CycleView及其CycleAdapter,
7 初始化DataUsageAdapter,並設置爲listview的adapter,設置listview的item點擊監聽mListListener。
onResume()中
1 根據activity的intent計算應顯示那個tab,是wifi還是數據流量的
2 更新tabs, updateTabs():先clear所有tabs,再判斷應該加載哪個tab
3 在AsyncTask中,updateBody更新當前tab,重新加載圖標數據
數據流量應用列表的加載,即DataUsageAdapter的數據獲取和排序:
流量變化引起bindStats(stats,uids){ 根據uids,利用stats獲取AppItem,即一個應用的使用流量信息,最終add到mItems,並對其排序}
getView()中根據mItems生成對應的UidDetail(),然後根據UidDetail設置需要的itemView。
這裏涉及到不少內部API,需要根據framework層的隱藏API一起分析,才更清晰。


2014-7-10
設置 ---- 流量使用情況(2)
應用的流量統計獲取來源:
從前文知,com.android.settings.DatausageSummary$DataUsageAdapter.bindStats()用來獲取每個應用的瀏覽信息。
android.net.NetworkStats系統的一個隱藏API;它是網絡統計的集合,包括每個UID的統計信息,內部主要包括幾個數組:
int[] uid, long[] rxBytes, rxPackets, txBytes, txPackets;以及這些數組(size一樣)的size
NetworkStats.Entry從其字段看,表示一個UID的某次流量信息:uid,上下行字節/包數量,uid相同時疊加流量。
bindStats()是在mSummaryCallbacks這個loader中onLoadFinished()被回調的,
而此mSummaryCallbacks 是在updateDetailData()中restartLoader(id,Bundle,mSummaryCallbacks)的回調,LoaderCallbacks 在加載完成後回調。bundle中含有要統計的(從ChartDataUsageView中獲取的)起止時間,SummaryForAllUidLoaderloader的創建是通過SummaryForAllUidLoader建一個加載NetworkStats的Loader。從SummaryForAllUidLoader的loadInBackground()中可見統計數據是在work線程中用mStatsSession.getSummaryForAllUid()獲取的。
mStatsSession是通過mStatsService.openSession()得到的,mStatsService=INetworkStatsService.Stub.asInterface(ServiceManager.getService(Context.NETWORK_STATS_SERVICE));而這個service的實現則位於framework/base/services/下的com.android.server.net.NetworkStatsService;這個service這裏就不繼續分析了。
流量網格圖ChartDataUsageView 在DataUsageSummary中的mChart設置監聽mChartListener,當統計時間範圍變動時,onInspectRangeChanged()執行,即調用updateDetailData()進行重啓一個Loader,用來更新本fragment下面的應用流量統計列表ListView。


2014-7-11

更多/無線網絡設置--設置
com.android.settings.WirelessSettings
此設置項主要設置設備的無線網絡,主要包括 飛行模式,默認短信應用,NFC,androidBeam,移動網絡,***,手機網絡,手機套餐,WIMAX,nsd,代理和小區廣播。
onCreate中,獲取需要的服務如ConnectivityManager,TelephonyManager,加載資源R.xml.wireless_settings,設置相關的監聽,然後根據設備的具體配置特性移除不支持的條目,比如NFC,WIMAX,nsd等;初始化 AirplaneMode,NFC,NSD的監聽,它們和前面的wifiEnabler,bluetoothEnabler一樣。
其中短信應用的配置的初始化也在此處,主要是獲取短信應用的集合,並列出相關應用的名稱;而獲取來源是內部API即com.android.internal.telephony.SmsApplication,短信應用用SmsApplicationData表示,包括名稱,包名,接收短彩信的class,以及uid;最後將所有短信應用添加到SmsListPreference這個listPreference。
在onResume和onPause中,主要對Airplane,NFC,NSD的監聽等做了恢復和暫停;
在下一級的選項/目錄中,有NFC.AndroidBeam  移動網絡 *** 以及 代理。其中移動網絡項,即com.android.settings.TetherSettings。
onCreate中,加載資源R.xml.tether_prefs,包括四項:USB共享網絡,便攜式 WLAN 熱點,設置WLAN熱點,藍牙共享網絡;
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爲選中狀態。

修改默認Launcher的方法:由mHomeClickListener中可見,當click非默認Launcher的preference時,執行makeCurrentHome()來修改當前默認Launcher:

1 取消當前Launcher狀態,並設置新Launcher的狀態;2 通過PackageManager.replacePreferredActivity()來替換默認的activity即Launcher。

聲音設置

即com.android.settings.SoundSettings這個Fragment,

onCreate()中

1 獲取AudioManager, 加載資源 R.xml.sound_settings,

2 根據設備配置,移除若干preference; 例如:若非CDMA的Phone,則去掉emergency_tone;

3 查找相關preference,如震動,撥號鍵盤音效,觸摸提示音,觸摸時震動,鎖屏提示音,基座等;

onResume()中

4 起一個work線程,更新鈴聲名稱,和通知鈴聲的詳細信息 new Thread(mRingtoneLookupRunnable).start();註冊dock的BroadcastReceiver

音量的子條目如下 

a 音量 --控制鈴聲、通知、鬧鐘音量的特殊Fragment即 RingerVolumePreference

包括四個Seekbar的條目,調節其音量: 媒體,鈴聲,通知,鬧鐘;

這些設置的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後發一個broadcast以顯示亮度調節dialog;
2 壁紙 轉到com.android.settings.WallpaperTypeSettings處理
3 自動旋轉屏幕 key:accelerometer_title
4 休眠 key: screen_timeout,一個 ListPreference
5 互動屏保 轉到com.android.settings.DreamSettings
6 字體大小 即com.android.settings.WarnedListPreference,但在此修改字體
7 收到通知時指示燈閃爍 key:notification_pulse 一個checkbox
8 投射屏幕 轉到com.android.settings.wfd.WifiDisplaySettings
接下來,根據設備的特性/配置,移除不必要的Preference;再給相關preference設置監聽,即setOnPreferenceChangeListener()和setOnPreferenceClickListener(),以便在用戶操作preference時候做相應的相應,即執行 onPreferenceChange()和onPreferenceTreeClick();根據當前設置修改顯示條目,如更新當前的休眠超時time。
onResume中主要更新了當前的配置項目,自動旋轉屏幕,字體大小,互動屏保。
壁紙的設置- WallpaperTypeSettings 流程如下:
加載R.xml.wallpaper_settings,並查找PackageManager中可設置壁紙的app組件,然後設置每一個組件對應一個Preference,並設置preference對應的intent。即選中某個preference後,轉到對應的組件設置壁紙。



2014-7-16
存儲設置
即com.android.settings.deviceinfo.Memory主要用來(按類型)查看設備中的文件,列出每類所佔用設備的大小。
onCreate()中獲取 UsbManager,StorageManager, 添加內部存儲Category,然後列出StorageManager中包含的每個category,並addCategory()添加到此fragment;這裏使用StorageVolumePreferenceCategory來初始化每個category。
onResume()中註冊兩個intentFilter到mMediaScannerReceiver,並onResume每個category;
onPause() 中註銷mMediaScannerReceiver,並且onPause每個category。
category的click處理流程在onPreferenceTresClick(),主要如下:
對於cache項,顯示一個ConfirmClearCacheFragment的對話框後返回(清空應用的緩存的邏輯也在此,清空後的回調爲ClearCacheObserver);
其他的,通過StorageVolumePreferenceCategory.intentForClick()獲取一個intent,若intent不空,則啓動此intent指向的activity即可,若intent是空,則說明這個category是usb存儲,則執行掛載、卸載的過程(掛載的主要執行mountService.mountVolume()即可,卸載則是顯示一個AlertDialog,確認後執行卸載doUnmount(),同樣是由mountService.unmountVolume()完成的)。由此可見,大多數category的click處理還是它們本身的intent決定。
下面說明下StorageVolumePreferenceCategory,此類 表示 內部存儲器 和 外置SD卡 (有些設備稱 USB存儲)
內部存儲包括包括這幾個 Preference: (後跟click的intent)
1 總容量mItemTotal      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 下載內容mItemDownloads, action: DownloadManager.ACTION_VIEW_DOWNLOADS
7 緩存mItemCache,
8 雜項(其他)mItemMisc  指向 MiscFilesHandler
外置SD卡/USB存儲的preference:
1 總容量mItemTotal,可用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的返回列表中應用/服務的個數小於10則return
4 通過mStatsHelper獲取耗電量的列表  List<BatterySipper> usageList
5 依次遍歷usageList,生成對應的preference,添加到mAppListGroup;
BatteryStatsHelper說明:
在刷新時,即refreshStats() 中(重)啓一個Thread(最低優先級),(若Thread運行,先abort,再啓此線程),此線程主要是:依次從mRequestQueue中取出一個BatterySipper,BatterySipper.loadNameAndIcon(),直到mRequestQueue中爲空或者abort才終止Thread。
BatterySipper表示一個應用或服務的耗電量信息,包括 包名,圖標,耗電量,使用時間,cpu時間,GPS、WIFI、等時間;而此類主要的方法加載名字和圖標loadNameAndIcon(),從PackageManager中加載icon,name,packageName,併發送message到mHandler以便更新列表的顯示


2014-7-18
應用程序管理
com.android.settings.application.ManagerApplicationsActivity
onCreate中,獲取Intent,根據intent獲取默認的加載列表(TabInfo),添加tab包括: 已下載,(USB 存儲設備(若USB可)),正在運行,全部,已停用。
這裏綁定了服務com.android.defcontainer.DefaultContainerService,
onCreateView中初始化ViewPager,MyPagerAdapter,PagerTabString,並設置監聽,並設置當前Tab爲onCreate中的默認tab
onResume中,更新當前Tab,NumTabs,和菜單
onPause中,同樣pause每個Tab的列表
onDestoryView中 對每個Tab做detachView
當選中某一應用時,則執行startApplicationDetailsActivity()到此應用的詳情界面,即InstalledAppDetails,同時傳遞packageName給它,
InstalledAppDetails用來顯示一個應用的詳情信息,
mHandler中主要接收三個msg:清空數據,清空緩存,卸載。
onCreate中,通過retrieveAppEntry()接收Intent中的packageName,並根據包名得到一個AppEntry(AppEntry包括應用的id,label,佔據的內部、外部存儲空間,圖標等信息),並根據AppEntry獲取PackageInfo,並更新mAppEntry和mPackageInfo
onCreateView,加載R.layout.installed_app_details,並find到相關View(如TextView,CheckBox,CompoundButton),設置Button的初始狀態
onResume中,主要刷新UI,即refreshUI(),並返回是否成功刷新,主要流程是:
判斷一些初始狀態, 然後從PackageManager中獲取HomeActivity即桌面的activity,然後獲取默認的應用(主要判斷本應用是否爲默認應用),checkForceStop()中設置“停止運行”按鈕的啓用禁用,判斷依據爲:1 是否含有設備管理DevicePolicyManager.packageHasActivityAdmins(packageName)),2 標識mAppEntry.info.flags ;在enable時,監聽click,showDialogInner(),在AlertDialog中的確認按鈕click後,強制終止應用,即getOwner().forceStopPackage(packageName)。


2014-7-21
應用程序管理(2)
應用程序詳情界面InstalledAppDetails,如之前所述,這裏說明下它的幾種操作
初始化狀態在initUninstallButtons(),點擊處理即onClick()
1 卸載/卸載更新  即按鈕mUninstallButton
若是系統應用的升級版本,則show一個對話框,id爲DLG_FACTORY_RESET=2;
若是系統應用且狀態爲啓用,則show一個dialog,id DLG_DISABLE = 7;
若是系統應用但狀態爲禁用,則啓動異步任務DisableChanger()來啓用它;
若應用是爲當前用戶安裝的,則執行卸載uninstallPkg(pkgName,true,false);
若應用不爲當前用戶安裝,則執行卸載uninstallPkg(pkgName,false,false)。
其中卸載更新和卸載應用是通過uninstallPkg(){則使用Action="android.intent.action.UNINSTALL_PACKAGE",包名的URI實例一intent,啓動Activity來卸載此應用},啓用禁用應用是通過DisableChanger的AsyncTask{使用packageManager.setApplicationEnabledSetting()}。
2 清空默認設置 即按鈕mActivitiesButton
refreshUI()中更新其狀態以及click監聽,清除默認設置的方法如下:
通過PackageManager的clearPackagePreferredActivities()清除默認,然後通過UsbManager的clearDefaults()清除usb中的中的默認,最後更新mActivitiesButton的顯示狀態。
4 清除數據 mClearDataButton
啓動AppEntry.info中指定的activity來清除應用的數據,或者顯示id爲DLG_CLEAR_DATA的dialog來清除。實際爲使用ActivityManager的clearApplicationUserData()方法來清除應用的數據。
5 清除緩存 mClearCacheButton
即使用PackageManager的deleteApplicationCacheFiles()清除緩存。
權限管理部分 
refreshUI()中,刷新了權限的列表,其中AppSecurityPermissions asp爲本應用的權限,這裏對SMS短信做了單獨處理,應用是4.4系統多了的設置默認短信應用的功能引起的;然後在權限列表security_settings_list中添加了權限列表的View,通過asp.getPermissionsViewWithRevokeButtons()獲取的權限View。
2014-7-22
安全設置
SecuritySettings.java 
在onResume中加載資源R.xml.security_settings,並根據當前狀態顯示/移除一些項,在7月3號的閱讀已經說明鎖屏設置以及未知源的處理,這裏不再複述。
SIM卡的PIN碼設置:
1 若TelephonyManager.hasIccCard()爲false即設備沒有SIM卡,則移除此項;
2 若TelephonyManager.getSimState()是absent或未知,則禁用此項(可見但不可設置);
加密手機/平板
根據 android.app.admin.DevicePolicyManager.getStorageEncryptionStatus()的返回狀態加載 R.xml.security_settings_encrypted(已經加密)或者R.xml.security_settings_unencrypted(需要加密/可以加密),加密最終到CryptKeeperConfirm.java中的Blankz這個activity,在這裏加載它的佈局R.layout.crypt_keeper_blank後,就通過服務StatusBarManager禁用了狀態欄的下拉、通知、警告框、HOME按鍵、搜索鍵、返回鍵以及最近的任務列表鍵等,然後向handler發了一個延遲700ms的runnable,這個runnable就是上層應用最終進行加密調用的位置,如下:
1 通過ServiceManager利用binder機制獲取mount服務, mountService
2 調用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,即獲取系統支持的語言 Locale;當click時調用onListItemClick(),若listener不空,則執行listener的onLocaleSelected(),即 在com.android.settings.LocalePicker中的onLocaleSelected(),若是多用戶則在Dialog中提示,否則執行一個runnable來修改系統語言,runnable如下:移除dialog(若有),虛擬按下返回鍵,使用LocalePicker.updateLocale(mTargetLocale)更新系統語言。
獲取系統支持的語言主要在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添加到數組preprocess[],localeInfos[]
4) 對localeInfos排序,使用localeInfos填充ArrayAdapter,即設置item的每個TextView setText(label) setTextLocale(locale)
接下來的是 拼寫檢查,個人詞典, 輸入法, 物理鍵盤,語音識別,觸控板,遊戲控制器。
輸入法的設置
在onResume的最後,更新了輸入法的列表,即updateInputMethodPreferenceViews(),更新流程如下:
1) 首先,移除所有的輸入法preference,然後再清空輸入法的數組列表mInputMethodPreferenceList;
2) 從InputMethodSettingValuesWrapper中獲取最新的輸入法列表,遍歷列表,每個元素構造一個Preference並添加到mInputMethodPreferenceList列表,然後添加到視圖mKeyboardSettingsCategory中
3) 更新每個輸入法的狀態和名稱updatePreferenceViews() updateCurrentImeName()

2014-7-24

日期和時間

這裏註冊廣播mIntentReceiver,監聽action--ACTION_TIME_TICK,  ACTION_TIME_CHANGED,  ACTION_TIMEZONE_CHANGED.

當時間、日期或時區變化時,調用updateTimeAndDateDisplay()更是UI顯示。

當click時間/日期的Preference時,創建相應的對話框DatePickerDialog,TimePickerDialog來修改時間,設置的方法如下:

設置後回調到本class,OnTimeSetListener.onTimeSet()和OnDateSetListener.onDateSet(),然後 setTime或setDate後,更新UI的顯示,updateTimeAndDateDisplay(),而設置時間、日期的接口如下:

時間的設置在setTime(),主要是調用 Alarm服務的setTime(long )來設置;

日期的設置在setDate(),  方法和 時間設置一致,只是生成long的參數有差異。

12/24小時格式,通過設置Settings.System.TIME_12_24的值 修改settingProvider;

關於手機

首先在onCreate中加載資源R.xml.device_info_settings,包括如下選項:

1  系統更新   Intent, android.settings.SYSTEM_UPDATE_SETTINGS

2  其他系統更新  指向res/strings中指向的資源 地址 

3  狀態信息    轉到com.android.settings.deviceinfo.Status

4  法律信息

5  安全信息   Intent   android.settings.SAFETY

6  監管信息   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 內核版本   key  kernel_version           來源 getFormattedKernelVersion(),即文件 "/proc/version",並格式下string

12 版本號    key  build_number              來源 Build.DISPLAY

13  SELinux狀態  key  selinux_status      來源 SELinux的狀態  (未啓用/許可/執行中)

但上面的Preference需要根據設備的具體配置做改動,比如:

SELinux狀態,安全信息,設備ID需要根據SystemProperties中對於的key值來決定 移除or保留;基帶版本 則在 wifi-only的設備中移除。

連續點擊幾次android的版本號出現的彩蛋可在onPreferenceTreeClick()見其處理:

System.arraycopy(mHits, 1, mHits, 0, mHits.length-1);

mHits[mHits.length-1] = SystemClock.updateMillis();

if(mHits[0] >= (SystemClock.updateMillis() - 500)) 則轉到Activity:com.android.internal.app.PlatLogoActivity

開啓調試模式的處理也在這裏:

在 sharedPreference中存的mDevHitCountdown整數,當連續7次纔會開啓開發者選項的顯示。

在這裏使用了個 R.plurals.的資源,就是指的 單複數,源代碼中的使用方法是:

getResources().getQuantityString(R.plurals.show_dev_countdown, mDevHitCountdown, mDevHitCountdown)

對應的在res/values-zh-rCN/strings.xml中的內容如下:

  <plurals name="show_dev_countdown"> 

    <item quantity="one" msgid="5295687242294085452">"只需 <xliff:g id="STEP_COUNT">%1$d</xliff:g> 步操作即可進入開發者模式。"</item>

    <item quantity="other" msgid="6722953419953594148">"只需 <xliff:g id="STEP_COUNT">%1$d</xliff:g> 步操作即可進入開發者模式。"</item>

  </plurals>

當然主要是用來區分應用中的單複數 例如 引用資源 step 還是 steps。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章