Android系统设置settings应用学习(二)--源代码解析

来源:互联网 发布:java comp env jdbc 编辑:程序博客网 时间:2024/05/21 07:53

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,移动网络,VPN,手机网络,手机套餐,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  移动网络 VPN 以及 代理。其中移动网络项,即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。

 文章参考:http://orient33.blog.51cto.com/8137794/1580213

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 积目头像未通过审核怎么办 电压不稳空调带不动怎么办 孩子吃了塑料珠怎么办 美的电压力锅打不开盖子怎么办 瓶盖打不开怎么办 瓶子是玻璃的 杯子口关错位了怎么办 大玻璃瓶的玻璃瓶盖拧不开怎么办 按压式洗发水瓶盖打不开怎么办 向下按压的瓶盖打不开怎么办 玻璃罐头开过了打不开怎么办 玻璃瓶的塑料盖子打不开怎么办 泡酒玻璃瓶盖子打不开怎么办 罐头的塑料瓶盖打不开怎么办 塑料水杯盖紧了怎么办 拧不开矿泉水瓶盖怎么办 新暖壶盖吸住了怎么办 暖瓶盖被吸住了怎么办 做面包和面粘手怎么办 面包面和稀了怎么办 鱼缸氧气泵声音大怎么办 中班安全遇到火灾怎么办反思 汤洒了怎么办活动反思 下水道被塑料盖堵了怎么办 卫生间地漏盖子掉到下水道怎么办 洗手池下水道翻盖打不开了怎么办 培乐多彩泥吃了怎么办 超轻橡皮泥干了怎么办 脑梗脾气大怎么办好啊 牙齿喝饮料烂了怎么办 大门牙缝里黑了怎么办 椰汁拧不开瓶盖怎么办 装蜂蜜的玻璃罐打不开怎么办 蚂蚱没有草吃了怎么办 笔记本电源已接通未充电怎么办 电源已接通未充电怎么办 遮盖纹身好了颜色淡了怎么办 致炫方向盘变重怎么办 xp音频图标没了怎么办 狙击精英3没子弹怎么办 干活干的手腕疼怎么办 干了活不给钱怎么办