扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
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
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中的内容如下:
当然主要是用来区分应用中的单复数 例如 引用资源 step 还是 steps。
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流