赞
踩
目录
SystemUI(本文基于android10),顾名思义是系统为用户提供的系统级别的信息显示与交互的一套UI组件,所以其功能包罗万象。比如锁屏、状态栏、底部导航栏、最近使用App列表等,大部分功能相互独立,按需启动,后文会继续列出更多功能。在系统源码中,其位置为:frameworks/base/package/SystemUI。尽管从表现形式上看,SystemUI和普通的Android APP有较大的差别,但其本质和普通APP并没有什么差别,也是以apk的形式存在。下面通过图片的方式展示SystemUI有哪些东西。
SystemUI的每一个子类,代表一个功能模块,下面简单的介绍几个,更详细的介绍,需要专门写文章来介绍。
1、Status bars(状态栏)
2、NotificationChannels(通知)
3、KeyguardViewMediator(锁屏)
4、Recents(最近任务面板)
5、VolumeUI(音量UI)
6、PowerUI(电量UI)
7、RingtonePlayer(铃声播放器)
8、PipUI(画中画UI)
9、BiometricDialogImpl(生物识别解锁功能,如指纹解锁、人脸解锁、虹膜解锁等)
在android系统的启动流程中,会启动一个Zygote孵化器进程,用来孵化出新的进程,其中SystemService进程就是 被它孵化出来的,之后调用SystemService的run()方法初始化SystemService,初始化调用startOtherServices() ,接着调用startSystmeUI(),startSystmeUI()中会创建启动SystemUIService的intent,然后调用Context的startServiceAsUser(),这个方法里面会使用意图的方式开启 SystemUIService,在SystemUIService的onCreate()方法中调用SystemUIApplication的startServicesIfNeeded(),这个方加载实现SystemUI的模块的字符串列表,通过反射的方式创建这些模块,并调用它们的start()初始化数据,从而完成SystemUI的加载。
在StatusBar的start()方法中,会通过Dependency获取NotificationListener注册监听。调用NotificationListener的registerAsSystemService(),会调用NotificationListenerWithPlugins的registerAsSystemService(),会调用父类NotificationListenerService的registerAsSystemService(),在这个方法中,首先会创建NotificationListenerWrapper,然后获取NotificationManagerService这个系统服务,接着,调用它的registerListener()将NotificationListenerWrapper注册。这样当NotificationManagerService有通知的时候,会调用NotificationListenerWrapper的onNotificationPosted()方法将通知穿的给SystemUI。
APP通过notify()方法将通知发送给NotificationManager,然后NotificationManager通过AIDL的方式会调用NotificationManagerService的enqueueNotificationWithTag(),收到通知后,NotificationManagerService会对通知做一些兼容处理,比如通知图片的缩放,通知的排序,其中有一个方法需要注意的是在接下来调用的enqueueNotificationInternal(),在这个方法中会打印发送消息是的APP的包名、消息的id、消息。这样我们就可以判断消息是否成功发送到framework。接着会调用NotificationListeners的notifyPostedLocked()方法中遍历所有ManagedServiceInfo,将对象传入notifyPosted(),在这个方法中,会从ManagedServiceInfo上获取INotificationListener,就是注册到NotificationManagerService的NotificationListenerWrapper,然后调用NotificationListenerWrapper的onNotificationPosted()将通知信息和通知的排序快照发送到SystemUI中。
NotificationManagerService的内部类NotificationListeners调用NotificationListenerWrapper的onNotificationPosted()方法将通知发送给SystemUI,会通过MyHandler发出一个消息MSG_ON_NOTIFICATION_POSTED,接着NotificationListenerService的onNotificationPosted()被调用,其实调用的是NotificationListener,它在SystemUI中,是NotificationListenerService的子类。在这个方法中,会根据情况调用NotificationEntryManager的相关方法,实现删除、排序、更新、添加通知,拿添加来说,会调用NotificationEntryListener的实现类去添加通知
通知的添加是通过NotificationEntryManager的addNotification方法实现的,在这个方法中,会调用addNotificationInternal()实现通知的排序和视图填充,在这个方法中调用abortExistingInflation()方法判断这个通知的视图是否填充过,如果填充就终止填充任务。调用updateRanking()方法更新排名排序和过滤不需要显示的通知,里面的updateRankingAndSort()负责了更新排名排序,它排序的步骤是: 1.遍历mEntries消息列表,通过entry的key在mRankingMap中的mRankings查找有没有对应的Ranking, 如果有把它的数据复制给mTmpRanking,如果没有就跳过。 2.拷贝entry中之前的notification 3.获取Ranking的系统指定的组密钥(mOverrideGroupKey) 4.overrideGroupKey不相同,设置notification的overrideGroupKey,更新新旧NotificationEntry 5.更新排名信息 6.判断通知应是否在高优先级通知部分中,然后把结果设置给entry. updateRanking()方法中通filterAndSort()实现过滤排序: 1.过滤掉不需要显示的通知 2.将需要排序的通知添加到已经过的排序集合 3.排序。 排完序后,在addNotificationInternal()方法中会调用NotificationRowBinderImpl的inflateViews()对通知的视图进行填充,首先会会判断这个通知的视图是否存在,存在就更新,不存在就填充,填充是通过RowInflaterTask的inflate()方法实现的。接着在addNotificationInternal()方法中会调用abortExistingInflation()方法,在这个方法中,通过通知的key在mPendingNotifications(待处理的通知列表)和mNotificationData (当前需要显示的通知列表)中查找,如果有证明这个消息的布局填充过了,就会调用RowInflaterTask的abort方法取消填充任务。接着在addNotificationInternal()方法中会遍历所有的NotificationEntryListener调用onPendingEntryAdded()方法将通知分发出去。
SystemUI在初始化的时候,通过反射的方式创建SystemBars,在它的start()方法中,会调用createStatusBarFromConfig(),会读取一个字符串,这个字符串是可以配置的,原生系统配置的是StatusBar,通过反射的方式加载stautsBar,并调用start()初始化,start()里面会createAndAddWindows()接着调用makeStatusBarView(),获取StatusBarWindowController,将mStatusBarWindow添加到WindowMananger中,实现窗口添加。在makeStatusBarView()创建一个SystemUI顶级布局,这个布局是super_status_bar,并且赋值给mStatusBarWindow,接下来在makeStatusBarView()方法中,会通过FragmentHostManager以事物方式将CollapsedStatusBarFragment填充到status_bar_container布局中,在CollapsedStatusBarFragment的onCreateView()方法中会填充一个status_bar的布局,它就是状态栏的布局,在onViewCreated()中,会陆续加载系统图标、电池、紧急密文和操作者名称等等。
在CollapsedStatusBarFragment的initEmergencyCryptkeeperText(),判断有没有紧急密文信息(NetworkController.hasEmergencyCryptKeeperText()),如果有,加载紧急密文信息布局,添加信号回调,如果没有移除载紧急密文信息布局。调用NetworkControllerImpl的addCallback()方法来添加回调,这个方法中,添加的Callback会设置观察者,设置飞行模式,设置是否有sim卡,然后WiFi信号控制器、以太网控信号制器、移动信号控制器会将Callback传入到它们的notifyListeners()方法中,notifyListeners()方法中会调用信号回调的setMobileDataIndicators()方法。是用来修改了状态,更新自己的图标,比如CollapsedStatusBarFragment实现了这个回调,会更新飞行模式的显示状态。
在StatusBar的makeStatusBarView方法中调用createNavigationBar();里面会调用NavigationBarFragment.create(),填充一个navigation_bar_window的布局它是一个帧布局,被windowManager添加,这个被填充的View会添加一个附加在windows上的监听,当监听方法被回调的时候,通过FragmentHostManager以事物的方式,将NavigationBarFragment添加到这个帧布局中。在onCreateView()中会填充navigation_bar布局,里面有一个NavigationBarInflaterView,其实所有界面初始工作是这个里面进行的。NavigationBarInflaterView的构造方法中,会创建两个布局填充器,一个是横布局填充器,一个是竖布局填充器。在onFinishInflate()调用inflateChildren()创建横竖两个布局,调用clearViews() 清除mButtonDispatchers数据,横竖两个布局的子View。调用getDefaultLayout()获取默认的配置字符串,这个字符串是配置NavigationBar的按钮信息。调用inflateLayout()把字符串切割分成三类,然后调用inflateButtons(),inflateButton(),createView()根据字符串加载不同布局,这样NavigationBar加载完成。
在StatusBar的makeStatusBarView()方法中调用createDefaultQSFragment(),使用fragmentHostManager以注入的方式创建QSFragment,填充帧布局qs_frame,在QSFragment的构造函数中,会传到一个初始化的QSTileHost,将它设置给QSFragment。QSTileHost的构造方法中会使用mainHandler post 一个 Runnable,run()方法中会TunerService的addTunable(),这个方法会回调QSTileHost的onTuningChanged(),这里面会调用loadTileSpecs读取配置字符串列表quick_settings_tiles_default,这里面配置的是默认显示tile。接着调用createTile(),它里面会调用QSFactoryImpl的createTile()根据字符串生成不同的Tile
WakeLock计数机制(setReferenceCounted): 在创建了PowerManager.WakeLock 后,有两种机制,第一种是不计数锁机制,另一种是计数锁机制。这可以通过setReferenceCounted( boolean value) 来指定,默认为计数机制。这两种机制的区别在于,前者无论acquire() 了多少次,只要通过一次release() 即可解锁。而后者正真解锁是在(--count == 0 )的时候,同样当(count == 0) 的时候才会去申请加锁,其他情况下isHeld 状态是不会改变的。所以PowerManager.WakeLock 的计数机制并不是正真意义上的对每次请求进行申请/释放每一把锁,它只是对同一把锁被申请/释放的次数进行了统计。
SystemUI在初始化的时候,会通过SystemUIApplication的startServicesIfNeeded()创建KeyguardViewMediator实例,调用start()初始化。在start()中,setupLocked()方法中会注册开机广播和延时锁屏广播。获取锁屏声音和解锁声音,通过config_lockSoundVolumeDb来获取配置的锁屏/解锁的声音大小。
锁屏的显示流程是从PhoneWindowManager调用systemBooted()方法开始的,它里面会调用bindKeyguard()方法,bindKeyguard()里面会调用KeyguardServiceDelegate的bindService()去绑定KeyguardService,KeyguardService的onCreate()中会调用SystemUIApplication的startServicesIfNeeded()初始化SystemUI,接着获取初始化的KeyguardViewMediator。当KeyguardServiceDelegate绑定KeyguardService成功后,会在onServiceConnected()方法中调用onSystemReady()告诉KeyguardService系统已经准备好了,然后KeyguardService会检查有没有控制锁屏的权限,如果没有报异常,如果有则会调用KeyguardViewMediator的onSystemReady()方法。发送SYSTEM_READY消息,调用handleSystemReady(),在这个方法中会调用WakeLock的acquire(),让上手机保持亮屏,直到显示锁屏界面为止。发送SHOW消息,调用handleShow()方法通知系统显示锁屏界面了,调用StatusBarKeyguardViewManager的show()根据实际情况,来显示锁屏页面还是锁屏密码页面。
如果大家觉得看网页不够方法,可以下载源文件,标题下面的PPTX文档
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。