精华内容
下载资源
问答
  • systemui
    千次阅读
    2021-11-16 11:03:12

    .SystemUI概述 

    Android系统中SystemUI是以应用的形式运行的。即编译SystemUI会产生APK文件。但它和普通的APK不同,它是开机启动的A并且不可以退出,

       SystemUI顾名思义是系统用户界面。它为系统提供了基础的显示界面。比如:屏幕顶端 的状态栏、屏幕底部的导航栏、下拉界面的快速设置栏、

    通知栏、锁屏界面,音量调节对话框、截屏显示界面等功能。

    1.SystemUI路径

    Packages/apps/下许多模块不同的是,SystemUI属于Android FrameWork的一部分。这也意味着,SystemUI在正常情况下不可替代。

    (1)源码路径:framework/base/packages/systemui/

    (2)apk路径:system/pri-app/systemui/

    如:

    SystemUI   /media/longchengbin/LCBDisk/M10/frameworks/base/packages/SystemUI
    /media/longchengbin/LCBDisk/M10/out/target/product/lito/system/system_ext/priv-app/SystemUI

    2.SystemUI主要功能模块

    (1)Status状态栏:通知消息提示音和系统状态栏呈现

    (2)Navigation导航栏:返回,HomeRecent

    (3)QuickSettings快速设置:提供快速系统设置

    (4)Notification通知:展示系统或应用通知内容

    (5)Keyguard锁屏:锁屏模块可以看做单独的应用,提供基本的手机个人隐私保护

    (6)Recents最近任务:最近任务入口,P版本后再LauncherQuickStep实现界面

    (7)VolumeUI音量调节对话框:展示或控制音量的变化

    (8)StacKDivider分屏功能调节器:控制管理分屏的分割线

    (9)StorageNotification存储通知:USB存储通知

    (10)PowerUI电源事件:处理和电源相关事件

    (11)RingtonePlayer铃声播放器:提供播放铃声的服务

    (12)KeyguardUI键盘界面

    (13)PipUI画中画界面:提供对于画中画模式的管理

    (14)GlobalActions全局控制:长按电源出现的关机,重启截图等

    (15)ScreenShot截屏界面:用以展示截取的屏幕照片

    更多相关内容
  • systemui-overlay-sample 通过 systemui-overlay.apk 更改 homeButton PNG 在此示例中,我们仅将 systemUI 的 HomeButton 的一个 PNG 文件替换为纵向和横向模式的灰色文件! 查看 /res 文件夹和 AndroidManifest....
  • 上一篇文章AndroidQ SystemUI之插件化机制Plugin以SystemUI启动时加载的一个插件化接口分析了插件化的基本原理,这篇来看看插件的用法: 回顾上一篇文章,SystemUI启动加载了一个插件接口OverlayPlugin, Dependency...
  • SystemUI源码

    2019-02-18 10:32:27
    Android O 原生SystemUI代码,需要阅读得可以下载哦,仅供参考阅读!
  • 主要介绍了Android9.0 SystemUI 网络信号栏定制修改的流程,本文通过图文实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
  • Android系统定制-SystemUI-下拉状态栏快捷设置新增选项(自动亮度&静音)_Patch 文章链接:https://blog.csdn.net/qq_33750826/article/details/122829104
  • Android 9.0 10.0 SystemUI实现默认展开下拉列表,显示所有下拉快捷
  • 系统界面Android SystemUI源代码对SystemUI源码进行解析和注释,为了方便跟踪,每个函数都加了日志
  • NavigationBar流程梳理
  • SystemUI启动流程

    2022-01-19 17:17:25
    SystemUI启动流程
  • SystemUI.zip

    2021-01-27 15:31:39
    供下载
  • Android5.1_SystemUI详解

    2016-02-19 10:55:00
    Android5.1 SystemUI整体功能结构图, 代码结构,SystemUI类图; 执行流程: SystemUI启动; NavigationBar导航栏; RecentsActivity最近的APP; StatusBar加图标AddIcons;Icons排列规则; QuickSettingPanel快捷...
  • SystemUI学习笔记

    2015-09-15 10:48:17
    SystemUI:StatusBar,Notification,PowerUI,SettingsUI,Recents,RingtonePlayer..
  • android 7.0 SystemUI

    2017-11-08 11:43:42
    android 7.0 SystemUI 源代码。位置frameworks\base\packages目录。
  • 编译过程,手机开发systemui代码编译过程,主要有gradle编译,adb调试等,还有挂载相关参考,令还有相关linux 指令
  • Android SystemUI 架构详解

    千次阅读 2019-12-25 19:36:47
    Android SystemUI 架构详解 本文描述Android系统中一个核心应用SystemUI,详细赘述SystemUI中几大模块功能的实现过程。由于作者水平有限,如发现本文中错误的地方,欢迎指正。 1、SystemUI介绍 1.1、SystemUI...

    Android SystemUI 架构详解

     

    本文描述Android系统中一个核心应用SystemUI,详细赘述SystemUI中几大模块功能的实现过程。由于作者水平有限,如发现本文中错误的地方,欢迎指正。

    1、SystemUI介绍

    1.1、SystemUI摘要

    在Android系统中SystemUI是以应用的形式运行在Android系统当中,即编译SystemUI模块会生产APK文件,源代码路径在frameworks/base/packages/SystemUI/,安装路径system/priv-app/-SystemUI。

    1.2、什么是SystemUI

    在前文1.1章节中可知,SystemUI是一个普通的APK文件,即是一个普通的APP,但是,手机使用者看见的所有SystemUI的内容都不像是一个APP,为什么?既然是一个应用,就是完成特定的功能,SystemUI主要完成的功能有:
    (1)、Status bars
    (2)、Navigation bars
    (3)、Notification
    (4)、Lockscreen
    (5)、Quick settings
    (6)、Overview(recent task switcher)
    (7)、VolumeUI

     

    2、SystemUI的启动过程

    正如1.2中所述,SystemUI任何内容都不像一个APP,自然它的启动也不像大多APP一样启动一个Activity。SystemUI顾名思义就是全局UI,必须在开机过程中完成启动,并不可退出。
    回顾Android系统开机的过程,会创建server进程维护系统各种服务,当服务启动完成后调用systemReady方法(如果读者不了解这个过程自行学习Android Boot Flow),如下图:


    继续跟踪startSystemUi()方法的实现如下图:


    上图中可以看到通过熟悉的startServiceAsUser()方法启动SystemUI中的SystemUIService。由APP的启动过程可知(如果读者不了解这个过程可自行学习),Android系统会给应用创建独立的进程,并实例化Application对象,在SystemUI源码中的AndroidManifest.xml文件可以看到下图的配置:


    上图中在application标签中指定了SystemUIApplication对象,因此在启动SystemUI应用时会创建SystemUIApplication对象并回调onCreate()方法,如下图:


    onCreate()中注册ACTION_BOOT_COMPLETED广播,并调用mServices.onBootCompleted()方法,将在后面的内容中赘述该方法。应用成功启动后便可执行上文中提到的SystemUIService服务,并回调onCreate()方法,如下图:


    上图中通过获取应用的Application实例SystemUIApplication对象,调用startServiceIfNeeded(),如下图:

     


    上图中读者可能会问:mService的实质是什么?回顾1.2章节中的内容,SystemUI主要分几大模块,即在SystemUI中每个模块是一个Service,这样一来,各个模块就非常独立。上图中用Java映射机制把每个Service的对象实例化,并调用start()方法启动各个服务,start()方法的具体实现在分析各个服务时再赘述。先了解mService实质都包含哪些具体“对象”,如下图:


    如上图所示,SystemUI需要启动的Service包括KeyguardViewMediator、Recent、VolumeUI、SystemBars、StorageNotification、PowerUI、RingtongPlayer共7个,每个service的具体实现和功能将在下文中描述。在图6中可以看到,实例化每个对象是向上转型为SystemUI对象,即图7中的所有service统一继承了SystemUI类,如下图:


    SystemUI类提供start()、onConfigurationChanged()、dump()等重要方法,每个方法在各个service中实现不一样,下面将一一描述每个service在SystemUI类中的方法的实现。
    至此,SystemUI的启动基本完成,从上文可知,SystemUI是系统中非常核心的应用,在Android系统开机过程中Server进程直接发起SystemUI启动,SystemUI也是固化程序,在保证系统正常运行发挥了非常重要的作用。

     

    3、SystemUI的SERVICES

    3.1、音量控制

    3.1.1、音量控制简介

    如图章节1.2中的VolumeUI所示,当用户操作音量键时,会弹出相应的UI显示,并可以设置音量大小和情景模式。VolumeUI的主要代码在SystemUI/volume下。在不同模式下,音量键触发的UI显示样式不一样,分别是通话、铃声(通知)、音乐、闹铃、蓝牙输出等,如下图 9-13


    3.1.2、音量控制SERVICE的初始化

    在第二章节中SystemUI的启动过程提到,SystemUI的所有Service通过SystemUI类的start()方法启动,并且通过图7可以知道,volume service的VolumeUI继承了SystemUI类,所以start()实质是执行VolumeUI中的方法,如下图:


    如上图中的代码,首先读取VolumeUI的开关,如果mEnabled为true,则调用initPanel()方法实例化UI等控件元素(如图15),实例化VolumeController控制器(如图17),调用putComponent()保存对象实例,调用updateController()设置控制器(如图18)。


    上图中主要是new一个VolumePanel对象,VolumePanel是Handler的子类,且又是VolumeUI的Pannel,因此,VolumePanel负责绘制VolumeUI的内容和控制VolumeUI的显示。先看看VolumeUI的创建过程:

    从上图中的代码可见,VolumeUI是以Dialog的形式显示UI,VolumePanel的实例化过程创建Dialog实例和初始化ZenModePanel,到此VolumePanel将会待命。上文中提到VolumePanel同时是Handler的子类,一旦VolumePanel收到相关的Message时,将会处理UI的显示和关闭。


    上图是VolumeController的实现代码,主要实现对VolumeUI的Panel的控制,例如上图中的volumeChanged()控制Panel的显示和变化,dismissNow()控制Panel的关闭。那么VolumeController是被谁管控呢?如下图:

    图中可以看到先通过设置Provider读取是否允许systemui控制volume,如果允许,则设置通过AudioManager的实例设置VolumeController到AudioService(读者如果不了解这个过程,可以自行阅读Android Audio策略)。至此,VolumeUI的初始化全部完成。
    通过本节的学习,VolumeUI的架构如下图:


    3.1.3、控制音量过程

    当SystemUI的VolumeUI当前不是活动窗口时,一般情况下,音量的设置是通过音量键进行操作,当用户操作音量键时,如果用户不拦截音量键事件,那么默认音量键的事件将会在Window中被消化,Window将捕获到的音量键事件通过Binder机制将音量变化信息传送到MediaSessionService,MediaSessionService同样通过Binder机制接着传送到AudioService,最后AudioService也同样通过Binder机制把信息传送给SystemUI(VolumeUI),VolumeUI将会作出相应的变化。下面将详细了解这个过程:
    当手机设备当前活动窗口在Laucher桌面,Laucher没有对音量键事件作拦截操作,音量键事件将会在PhoneWindow中被消化。在Android的单次点击事件中,分down和up两种事件,分别被分发到PhoneWindow的onKeyUp()和onKeyDown()方法中,如下图20-21:


    图20是消化down事件,图21是消化up事件,但音量键还有上音量键(+)和下音量键(-),从这两张图可以看到,KEYCODE_VOLUME_UP没有作任何处理,上音量键(+)的事件会在下音量键中消化(-), 在down和up事件中都是调用sendAdjustVolumeBy()同一个方法,传递三个参数,第一个参数是指定音量类型,mVolumeControlStream为默认值,取值Integer.MIN_VALUE,图20和图21相同,第二个是delta,音量控制类型,即增加或减少,图20传递direction,图21传递0,direction取值1或-1,即1:增加、0:不变、-1:减少,第三个参数是flags,控制VolumeUI显示,每个参数具体的控制的实现代码将在下文中描述。继续跟踪流程,Laucher进程通过Binder机制把信息传送到MediaSessionService,如下图:


    上图中有获取MediaSessionRecord的对象来控制音量,这里的session变量的值是null,如果读者对此感兴趣可自行阅读相关资料。继续看dispatchAjustVolumeLocked()方法:

    图23中可以知道参数只是多了一个packageName,其它的都是图20或图21中的参数值。接着往下看:


    在图20或图21中有描述suggestedStreamType的值是Integer.MIN_VALUE,在上图中通过getActiveStreamType()方法对值进行转换,变成streamType,它的取值可能是0到10,分别控制不同类型的音量,如3.1.1章节中所以,本例子streamType的值是2,即调整的是铃声(通知)的音量。接着又调用了adjustStreamVolume()方法,如下:

    adjustStreamVolume()方法对direction和streamType的合法进行校验,direction取值-1到1,streamType取值0到10。之后通过mStreamState获取oldIndex、newIndex和index值,其中oldindex和index作为sendVolumeUpdate()方法的参数,将会影响音量变化的广播和AudioProfile,关于AudioProfile读者感兴趣可以自行学习。图中还可以看到这里还设置了HDMI接口输出。继续看sendVolumeUpdate()方法:


    在sendVolumeUpdate()方法中处理了几个事件,一个postVolumeChanged()方法,最终通知SystemUI,后面赘述。接着发送注册到AudioManager.VOLUME_CHANGED_ACTION的action的广播,通知音量改变并携带音量大小的原值oldIndex和新值index,最后通知AudioProfile。继续看postVolumeChanged()方法:

    这里写图片描述

    这里通过mControlle对象调用volumeChanged(),mController实质是一个什么类的实例,回顾3.1.2章节中的图18,updateController()方法设置了VolumeController的实例,因此mController正是VolumeController在AudioService中的句柄,通过Binder机制,把音量变化的信息从AudioService传输到SystemUI进程。转移到SystemUI,如下图:

    这里写图片描述
    从AudioService回调到volumeChanged()方法,接着调用mPanel的postVolumeChanged()方法,mPanel在前文3.1.2章节的图15中有描述,是VolumePanel的实例,前文中提到,VolumePanel是Handler的子类,也是VolumeUI的Panel,下面结合代码分析VolumePanel的具体功能:

    这里写图片描述
    上文提到VolumePanel是Handler的子类,图29中VolumePanel将发送MSG_VOLUME_CHANGED的Message到自身持有的线程,接着看MSG_VOLUME_CHANGED的代码:

    这里写图片描述

    上图中直接又调用了onShowVolumeChanged()方法,顾名思义是显示音量变化的UI,后面接着继续调用resetTimeout()方法,先跟踪onShowVolumeChanged()方法:

    这里写图片描述
    上图中首先调用getStreamVolume()方法获取对应streamType当前的音量值,通过StreamControl匹配streamType的UI,StreamControl是一个容器,在VolumeUI的初始化时被实例化,装载不同streamType的UI配置,并保存到mStreamControls数组对象中,因此streamType的值确定了StreamControl的类型,StreamControl确定了Dialog显示的UI类型。确定StreamControl的类型后,调用updateSliderProgress()方法更新界面控件,最后调用mDialog.show()方法绘制界面。至此,从按下音量键到调用mDialog.show(),设备对点击事件作出相应,并显示相应的UI到界面上。
    回顾图31,resetTimeout()方法的实现如下:

    这里写图片描述
    这里会延时发送一个空消息到VolumePanel,what为MSG_TIMEOUT,mTimeoutDelay的值为3000,跟踪MSG_TIMEOUT的处理过程:

    这里写图片描述
    很简单,实现的功能就是在VolumeUI显示后,延时3秒自动把VolumeUI关闭。
    到此SystemUI的VolumeUI service分析完毕,VolumeUI的流程简单清晰,代码简洁,阅读方便。回顾VolumeUI整个控制流程,可用下图总结:

    这里写图片描述


    上图中PhoneWindow是当前活动窗口的进程的PhoneWindow实例捕获音量键事件,当前活动窗口的可以通过自身的PhoneWindow对象实例设置streamType,即控制音量键事件触发的VolumeUI类型。当应用程序拦截音量键事件,那么PhoneWindow将无法捕获到音量键事件,此时音量键事件将不遵行上图的流程。如果当前活动窗口时SystemUI,则直接由SystemUI所在进程的活动窗口的PhoneWindow对象实例获取到音量键事件,这时音量键事件的转发和处理和在其它进程(如Laucher)中略有不同,读者感兴趣可以自行比较,本文不再论述。

     

    3.2、RingtonePlayer

    RingtonePlayer在SystemUI中扮演播放者的角色,代码在SystemUI/media/目录下,RingtonePlayer的代码很少,功能很简单,同VolumeUI,RingtonePlayer继承SystemUI类,SystemUI应用启动时调用start()方法:

    这里写图片描述
    Start()方法很简洁,通过AudioService的句柄mAudioService的setRingtonePlayer()方法设置mCallback,mCallback实质是IRingtonePlayer对象的实例,如下图:

    这里写图片描述
    IRingtonePlayer有play()、stop()等方法,分别是播放音乐和停止音乐。关于RingtonePlayer的作用,读者可以参考下图:

    这里写图片描述


    SystemUI启动后通过Binder机制把IRingtonePlayer的句柄设置到AudioServie,其它应用便可通过AudioService获取IRingtonePlayer的句柄,在通过Binder机制操作RingtonePlayerService去播放声音文件。如果读者感兴趣可自行深入学习Ringtone策略和架构。

    3.3、电源管理

    电源管理即PowerUI,负责监控电源的变化和通知,源码路径在SystemUI/power。同样PowerUI继承SystemUI类,start()方法如下:

    这里写图片描述
    上图可以知道,start()方法注册鉴定Setting.Global.LOW_POWER_MODE_TRIGGER_LEVEL的变化,接着调用mReceiver.init()方法,如下:

    这里写图片描述
    图 39注册一个action包含Intent.ACTION_BATTERY_CHANGED的广播接收器,监听电量的变化。然后调用updateSaverMode()方法:

    这里写图片描述
    如上图,updateSaverMode()的最终实现也是很简单,根据不同状态显示不同的notification。这就是PowerUI主要的功能,关于PowerUI本文就描述到这里,如果读者对PowerUI的更多细节感兴趣,可参考相关资料。

    3.4、任务管理

    任务管理即Recents,代码路径在SystemUI/recents。Recents是手机设备基本和常用的功能,主要功能表现为:展示所有任务,可以进行任务切换,可以进行任务的清除。同样Recents是SystemUI类的子类,同样启动时从start()方法开始启动。

    这里写图片描述
    Recents的start()方法很简洁,主要是sAlternateRecents.onStart()方法,sAlternateRecent是AlternateRecentsComponent的实例,AlternateRecentsComponent作为一个组件服务,担负着管理Recents的变化过程,AlternateRecentsComponent是单例设计模式,但一般sAlternateRecent只创建一次,过程如下:

    这里写图片描述

    这里写图片描述
    图 42通过getRecentsComponent()方法new一个AlternateRecentsComponent的对象实例,forceInitialize值是false,AlternateRecentsComponent实例化是会执行图43中的RecentsTaskLoader.initialize()方法实例化RecentsTaskLoader,RecentsTaskLoader是Recents读取器。接着又new一个SystemServicesProxy的实例,mSystemServicesProxy具有ActivityManage和PackageManage的功能,在读取Recents发挥了很重要的作用。回头看RecentsTaskLoader.initialize()的方法:

    这里写图片描述

    在RecentsTaskLoader.initialize()的方法中,除了实例化RecentsTaskLoader自己的同时,在RecentsTaskLoader的构造函数中同时实例化比较重要的两个变量,一个是TaskResourceLoadQueue,Recents资源队列,另外一个是TaskResourceLoader,Recents的资源读取器。下面根据SystemUI(Recents)的启动过程了解这些类的作用。
    在大多设备当中,通过长按HOME键打开任务管理器,HOME长按事件触发由输入输出事件派发者派发到系统进程(system_process)后被WindowManagerService拦截派发到PhoneWindowManager,如图:

    这里写图片描述
    上图中handleLongPressOnHome()将事件进一步发送到StatusBarManagerService,如图:

    这里写图片描述


    StatusBarManagerService通过CommandQueue发送到SystemUI进程,关于StatusBarManagerService和CommandQueue在StatusBar service中论述。最后发送到AlternateRecentsComponent,如图:

    这里写图片描述
    到图47,事件经过了几个进程,终于到准备启动任务管理器的界面了,topTask是ActivityManager.RunningTaskInfo的实例,即正在系统运行的Activity,第二参数值为true。RecentsActivity启动回调onCreate()方法:

    这里写图片描述
    onCreate()方法完成了实例化RecentsTaskLoader、SystemServicesProxy、RecentsConfiguration,在前面的内容已提到,RecentsTaskLoader.initialize()方法同时实例化TaskResourceLoader和TaskResourceLoadQueue,然后注册一个监听Intent.ACTION_SCREEN_OFF action的广播接收器,即当屏幕熄灭后关闭RecentsActivity。RecentsActivity还复写了onStart()方法:

    这里写图片描述
    上图AlternateRecentsComponent.notifyVisibilityChanged(this, ssp, true)通知StatusBar RecentsActivity已经起来,StatusBar需要配合做相应的调整,之后调用updateRecentsTasks(),由于篇幅问题,下文将重点描述Tasks的管理,不再跟随代码的执行流程。
    RecentsTasks的管理过程主要包括读取task,读取task资源,显示在RecentsActivity上,清除task。主要包括下面这些类:
    SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
    SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.ActivityInfoHandle
    SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader. TaskResourceLoadQueue
    SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader. TaskResourceLoader
    SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
    SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.Options
    RecentsTaskLoader是一个管理者,RecentsTaskLoader持有TaskResourceLoader,TaskResourceLoadQueue等实例,可以创建RecentsTaskLoadPlan实例,所以RecentsTaskLoader实质并没有去取读取task和task资源,只是负责发起读取task任务。ActivityInfoHandle 唯一持有一个AcitivityInfo的对象,保存Activity的信息,Activity的信息会在RecentsTaskLoadPlan中被查询。TaskResourceLoader 负责task的资源读取,和RecentsTaskLoader一样,它是一个管理者,实质实现读取task资源的是TaskResourceLoadQueue 。RecentsTaskLoadPlan对象实例也是被RecentsTaskLoader持有,实质上RecentsTaskLoadPlan是task读取的参与者和实现者,Options 是RecentsTaskLoadPlan的内部类,主要功能是控制RecentsTaskLoadPlan的读取task的条件。RecentsTaskLoadPlan读取task主要分两个阶段,第一个阶段是

    上图中loader是RecentsTaskLoader的实例,调用preloadTasks()方法,即task读取的第一阶段,plan是RecentsTaskLoadPlan的实例,第二个参数mConfig.launchedFromHome是boolean值,作用是isTopTaskHome,在启动RecentsActivity之前被赋值。这个阶段主要完成对task的读取。第二个阶段是:

    这里写图片描述

    上图中loadTasks()方法就是启动RecentsTaskLoadPlan的第二个阶段,同上图50,loader是RecentsTaskLoader的实例,第一个参数this是Context的实例,plan是RecentsTaskLoadPlan的实例,loadOpts是Options的实例,loadOpts在这里的作用是控制RecentsTaskLoadPlan读取task的规则,第二个阶段必须基于第一个阶段,也就是说在调用loadTasks()方法前,必须先执行preloadTasks()方法,loadTasks()基于preloadTasks()中读取到的task,从task中读取task的资源。
    这两个阶段紧密连连,有先有后,完成不同的功能,下文将具体描述这两个阶段的过程。Loader. preloadTasks()实质调用RecentsTaskLoadPlan的如下方法:

    这里写图片描述

    在这里会实例化一个TaskStack的对象实例,TaskStack封装了包含List类型的类,TaskStack包含两种类型的List,一种是存储所有的task,一种是filter task list,同时提供一个TaskFilter工具类接口,过滤主要通过PakcageName作为匹配。然后调用preloadRawTasks()方法实例化mRawTasks,mRawTasks是一个ListActivityManager.RecentTaskInfo>实例,mRawTasks存储了RecentTaskInfo类型的实例,所以mRawTasks是读取task的关键,看mRawTasks的实例化过程:

    这里写图片描述

    上图中mSystemServicesProxy是SystemServicesProxy的实例,调用图中的方法,再往下看:

    这里写图片描述

    上图中mAm是ActivityManager的实例,getRecentTasksForUser()方法实质是通过binder调用了远程的ActivityManagerService的方法,关于getRecentTasksForUser()这个方法在ActivityManagerService中的实现,读者可以自行阅读。在这里得到一个ListActivityManager.RecentTaskInfo>的对象实例tasks,RecentTaskInfo实质包含什么数据呢?如图:

    这里写图片描述

    上图中是RecentTaskInfo的变量,得到这些数据,回到前面图52的地方,看下图:

    这里写图片描述


    上图中获取到RecentTaskInfo后,把信息重新打包封装到TaskKey中,然后读取Activity的名字,Acitivity的图标,和thumbnail,然后把数据保存到TaskStack中。到此,第一个阶段就完成了,在这个阶段完成了读取task的基本信息RecentTaskInfo,然后读取Activity的基本信息ActivityInfo,把数据保存到TaskStack中。
    回到图50,第一阶段完成后,接着就行图51中的第二阶段loader.loadTasks(),如下图:

    这里写图片描述


    上图可以看到,这里获取icon和thumbnail都是在第一个阶段就已经完成了动作,在这里在根据inRunningTask等条件再次刷新数据罢了。
    到这里task和task资源读取完成,上上文中提到TaskResourceLoadQueue和TaskResourceLoader,这两个类在RecentsTaskLoadPlan的两个阶段都有使用,用于异步读取Activity Icon,TaskResourceLoadQueue会管理这些任务。
    所有的Task数据到这里已准备就绪,接下下就是把数据显示在Activity上(屏幕上),对于数据怎样绑定到View,本文不再论述。

    3.5、存储通知

    存储通知即StorageNotification service,在SystemUI中主要完成对存储器变化的通知,即USB连接的变化,存储器的变化SystemUI发送相应的Notification。StorageNotification的启动如下:


    StorageNotification的启动很简单,创建一个StorageNotification-EventListener的实例,把StorageNotificationEventListener通过StorageManager注册到到MountService。当USB连接或存储器发生变化是远程回调到StorageNotificationEventListener的方法,如下图:

    这里写图片描述


    USB变化回调到onUsbMassStorageConnectionChangedAsync()进行处理,存储器发生变化回调到onStorageStateChangedAsync()处理,就是在发送notification通知USB和存储器的变化。这个模块本文就论述到这里,在SystemUI中StorageNotification结构清晰,功能简单,读者感兴趣可以自行了解。

    3.6、锁屏

                  锁屏(Keyguard)service在SystemUI是一个比较特殊的模块,特殊在于SystemUI启动的service只是一个信息传递者,也就是KeyguardViewMediator,并没有做锁屏或解屏的实质操作。在这里,涉及到三个比较关键的类是:
    /SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
    /SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
    Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
    KeyguardViewMediator和KeyguardService在源码中位于同一个GIT库(SystemUI)中,而KeyguardUpdateMonitor则位于KeyGuard库中。在KeyguardViewMediator的初始化中主要做了三件事,如图

    这里写图片描述
    实例化KeyguardUpdateMonitor的实例mUpdateMonitor,KeyguardUpdateMonitor负责更新已经锁屏界面上的内容,如时间,当然,KeyguardUpdateMonitor只是一个信息传递着,实际去刷新界面的是StatusBar模块。Keyguard模块通知StatusBar刷新解密那通过KeyguardUpdateMonitorCallback这个类就行远程回调,该类的实例在StatusBar模块启动时通过KeyguardService获取到IKeyguardService的远端实例,通过IKeyguardService远程调用IKeyguardService的addStateMonitorCallback()方法实例化KeyguardUpdateMonitorCallback对象,如下图

    这里写图片描述
    SystemUI启动的Keyguard模块并没有真正的去操作锁屏界面,而是作为一个信息传递着把信息传递给StatusBar模块。这个模块本文就介绍到这里。

    3.7、通知栏

            通知栏(SystemBars)service是SystemUI中最重要的service,代码量最多,最复杂的,界面结构也复杂。根据前面的内容可知,启动SystemBars是通过调用start()方法,如下图:

    这里写图片描述
    这里实质是回调到到SystemBars的onNoService()方法(这里涉及到安全设置启动的模式不一样,本文只讨论正常模式),最后是调用SystemBars的createStatusBarFromConfig()方法:

    这里写图片描述


    上图可以看到,从string资源文件里面读取class name,通过java的映射机制实例化对象,然后调用start()方法启动,class name的值如下图:

    这里写图片描述

    该配置文件在SystemUI/res/values/config.xml中。所以实质是PhoneStatusBar调用了start()方法。
    SystemBars模块本文分两个阶段论述,第一阶段是SystemBars的初始化过程,第二阶段是Notification的显示过程。第一阶段主要涉及的类是:
    SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
    SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
    SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
    PhoneStatusBar的父类是BaseStatusBar继承于SystemUI,上文提到,SystemBars调用PhoneStatusBar中的start()方法,下面跟随代码看看这个过程。

    这里写图片描述


    如上图,调用父类中的start()方法,即BaseStatsuBar中的start()方法。然后调用addNavigationBar()方法实例化导航条,这里不再赘述此功能。继续看BaseStatsuBar中的方法。

    这里写图片描述
    如上图BaseStatsuBar中的start()方法,实例化一个StatusBarIconList的对象,此处iconList对象是“空值”,然后通过IStatusBarService的实例mBarService对象注册到StatusBarManager¬Service。mCommandQueue是CommandQueue的实例,在Status¬Bar-ManagerService的远程回调,实现StatusBarManagerService和SystemUI的通信。然后调用createAndAddWindows()方法,方法初始化status bar,notification,quick settings等的View控件。在这里,还需要注意NotificationListenerService的实例mNotificationListener的registerAsSystemService()方法,该方法主要实现StatusBarManagerService和SystemUI的notification的控制通道,也就是说,StatusBarManagerService收到notification变化时,通过此通道通知SystemUI显示notification的变化。下文将介绍notification从StatusBarManagerService到SystemUI的过程。
    一个APP需要显示notification首先需要实例化一个NotificationManager的对象,然后调用NotificationManager的方法notify()方法把创建好的Notification对象作为参数传进去。

    这里写图片描述
    上图中可以看到一个service的对象调用了enqueueNotification-WithTag()方法,该方法实质是远程调用NotificationManagerService中的enqueueNotificationWithTag()方法,该方法如下:

    这里写图片描述
    这里会把NotificationManager传递过来的Notification对象进行很多处理,比如变换成NotificationRecord,实质就是把Notification缓存下来。在上图的这个过程,还有一些其它的处理逻辑,在这里就不详细说明了,读者可以自行了解。上图中在代码的末尾调用了buzzBeepBlinkLocked()方法,该方法主要处理Notification的声音和震动的逻辑,本文也不再详述。接着看mListeners调用了notifyPostedLocked()方法,此方法最终会执行到如下图的代码

    这里写图片描述
    首先留意上图中final INotificationListener listener = (INotificationListener)info.service;这句代码,info.service返回一个INotificationListener的实例对象,该对象在上文中图66中的mNotificationListener.registerAsSystemService()方法进行设置,所以listener.onNotificationPosted()方法实质是远程回调SystemUI中的方法,如下图:

    这里写图片描述


    如上图,这里又调用了Notification.Builder.rebuild()方法,该方法主要把通过Binder机制传递过来的数据重新组装一些显示View所需要的数据,如notification的布局文件等等。重新组装notification数据后,调用NotificationListenerService.this.onNotificationPosted()方法,然后代码会执行到BaseStatusBar中的如下代码:

    这里写图片描述
    上图中,代码运行又回到熟悉的BaseStatusBar.java类中,从APP调用NotificationManager的notify()方法到BaseStatusBar的addNotification()或updateNotification()方法,经历了一个复杂的过程,涉及的模块多,模块交互复杂。到此,本文就不再往下详情说明Notification到达SystemUI的处理过程了,读者感兴趣可自行阅读代码。

    4、总结

           本文详细描述了SystemUI中KeyguardViewMediator、Recents、VolumeUI、SystemBars、StorageNotification、PowerUI、RingtonePlayer 7个模块(SERVICE),其中SystemBars是SystemUI中起到中枢作用的一个模块,因为这个模块和其他模块交互最紧密,而且SystemUI中大多数UI的View都是在SystemBars中初始化和控制显示。不过,SystemUI的功能不止本文中说论述到的,SystemUI还有例如情景模式控制、流量警告和常用的屏幕截屏等功能,本文不再去说明它们,读者可自行去研究SystemUI中的每个功能。
     

    展开全文
  • SystemUI-信号图标类型

    2018-07-21 14:34:35
    https://blog.csdn.net/gjy_it/article/details/81132713 根据博客进行 systemui 信号槽 信号强度 信号图标 定制更改方法
  • SystemUI深度裁剪

    千次阅读 2022-04-29 16:23:02
    SystemUI深度裁剪 前言 SystemUI AOSP包含了很多组件, Status bars,Navigation bars,Notification,Lockscreen,Quick settings,Overview(recent task switcher),VolumeUI,PowerUI 等等,但是我们在某些...

    SystemUI深度裁剪


    前言

    SystemUI AOSP包含了很多组件,
    Status bars,Navigation bars,Notification,Lockscreen,Quick settings,Overview(recent task switcher),VolumeUI,PowerUI 等等,但是我们在某些Andriod设备上不会用到手机上面这么多服务,有可能只会用到Systembar(StatusBar,NavigationBar),例如车载,点餐机等等,为了让我们SystemUI更轻量,性能更优,初始化完成时间更优,那么我们最好对它进程深度裁剪.


    一、裁剪思路是什么?

    拿车机来说吧,一般没有powerUI,分屏,overview,截屏这些功能。很多车载项目只有状态栏,导航栏,wallpaper,通知中心,VolumeUI。那我们只保留项目中需要的服务。

    二、行动吧

    代码如下(示例):

    <string-array name="config_systemUIServiceComponents" translatable="false">
        <item>com.android.systemui.util.NotificationChannels</item>
        <item>com.android.systemui.statusbar.CommandQueue$CommandQueueStart</item>
        <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
        <item>com.android.systemui.recents.Recents</item>
        <item>com.android.systemui.volume.VolumeUI</item>
        <item>com.android.systemui.stackdivider.Divider</item>
        <item>com.android.systemui.SystemBars</item>
        <item>com.android.systemui.usb.StorageNotification</item>
        <item>com.android.systemui.power.PowerUI</item>
        <item>com.android.systemui.media.RingtonePlayer</item>
        <item>com.android.systemui.keyboard.KeyboardUI</item>
        <item>com.android.systemui.pip.PipUI</item>
        <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
        <item>@string/config_systemUIVendorServiceComponent</item>
        <item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
        <item>com.android.systemui.LatencyTester</item>
        <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
        <item>com.android.systemui.ScreenDecorations</item>
        <item>com.android.systemui.biometrics.BiometricDialogImpl</item>
        <item>com.android.systemui.SliceBroadcastRelayHandler</item>
        <item>com.android.systemui.SizeCompatModeActivityController</item>
        <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
        <item>com.android.systemui.theme.ThemeOverlayController</item>
    </string-array>
    

    SystemUI核心组件都在这里声明的,在SystemUIService启动的,那么是不是在这里把组件注释了就能达到裁剪效果了呢。如果这么简单的话,那我就没必要写这边文章了。因为SystemUI各个组件耦合太多,如果简单的注释掉,运行会报很多错误让你一脸懵逼。这个时候有人就会说了,那我在组件代码里面再去裁剪掉,那么你真的太棒了。SystemUI组件的逻辑很多也比较复杂,这条路就算是大佬来,估计也得做很多逻辑梳理删除的工作,也要不停的调试,显然这是个笨方法。

    如果对SystemUI比较了解的,其实知道所有的视图都是Window,所有的功能都是服务。既然这样那么为什么不能全都自己定义呢,一些属性逻辑参考AOSP就可以了,对的就是这个思路。

    1:屏蔽掉不用的服务,只保留CommandQueue$CommandQueueStart,SystemBars

    <string-array name="config_systemUIServiceComponents" translatable="false">
        <!--<item>com.android.systemui.util.NotificationChannels</item>-->
        <item>com.android.systemui.statusbar.CommandQueue$CommandQueueStart</item>
        <!--<item>com.android.systemui.keyguard.KeyguardViewMediator</item>
        <item>com.android.systemui.recents.Recents</item>
        <item>com.android.systemui.volume.VolumeUI</item>
        <item>com.android.systemui.stackdivider.Divider</item>-->
        <item>com.android.systemui.SystemBars</item>
        <!--<item>com.android.systemui.usb.StorageNotification</item>
        <item>com.android.systemui.power.PowerUI</item>
        <item>com.android.systemui.media.RingtonePlayer</item>
        <item>com.android.systemui.keyboard.KeyboardUI</item>
        <item>com.android.systemui.pip.PipUI</item>
        <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
        <item>@string/config_systemUIVendorServiceComponent</item>
        <item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
        <item>com.android.systemui.LatencyTester</item>
        <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
        <item>com.android.systemui.ScreenDecorations</item>
        <item>com.android.systemui.biometrics.BiometricDialogImpl</item>
        <item>com.android.systemui.SliceBroadcastRelayHandler</item>
        <item>com.android.systemui.SizeCompatModeActivityController</item>
        <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
        <item>com.android.systemui.theme.ThemeOverlayController</item>-->
    </string-array>
    

    2:AndroidManifest.xml 屏蔽掉服务注册,不然要运行时异常.


        <!-- Broadcast receiver that gets the broadcast at boot time and starts
             up everything else.
             TODO: Should have an android:permission attribute
             -->
        <service
            android:name="SystemUIService"
            android:exported="true" />
    
        <!--//        &lt;!&ndash; On user switch, this service is started to ensure that the associated SystemUI
                     process for the current user is started. See the resource
                     "config_systemUIServiceComponentsPerUser".
                     &ndash;&gt;
                <service android:name="SystemUISecondaryUserService"
                    android:exported="false"
                    android:permission="com.android.systemui.permission.SELF" />
    
                &lt;!&ndash; started from PhoneWindowManager
                     TODO: Should have an android:permission attribute &ndash;&gt;
                <service android:name=".screenshot.TakeScreenshotService"
                    android:process=":screenshot"
                    android:exported="false" />
    
                &lt;!&ndash; Called from PhoneWindowManager &ndash;&gt;
                <receiver android:name=".screenshot.ScreenshotServiceErrorReceiver"
                    android:process=":screenshot"
                    android:exported="false">
                    <intent-filter>
                        <action android:name="com.android.systemui.screenshot.SHOW_ERROR" />
                    </intent-filter>
                </receiver>
    
                <activity android:name=".screenrecord.ScreenRecordDialog"
                    android:theme="@style/ScreenRecord" />
                <service android:name=".screenrecord.RecordingService" />
    
                <receiver android:name=".SysuiRestartReceiver"
                    android:exported="false">
                    <intent-filter>
                        <action android:name="com.android.systemui.action.RESTART" />
    
                        <data android:scheme="package" />
                    </intent-filter>
                </receiver>-->
    
        <service
            android:name=".ImageWallpaper"
            android:exported="true"
            android:permission="android.permission.BIND_WALLPAPER" />
    
        <!-- <activity android:name=".tuner.TunerActivity"
                   android:enabled="false"
                   android:icon="@drawable/tuner"
                   android:theme="@style/TunerSettings"
                   android:label="@string/system_ui_tuner"
                   android:process=":tuner"
                   android:exported="true">
             <intent-filter>
                 <action android:name="com.android.settings.action.EXTRA_SETTINGS" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
             <meta-data android:name="com.android.settings.category"
                     android:value="com.android.settings.category.ia.system" />
             <meta-data android:name="com.android.settings.summary"
                     android:resource="@string/summary_empty"/>
         </activity>
    
         <activity-alias android:name=".DemoMode"
                   android:targetActivity=".tuner.TunerActivity"
                   android:icon="@drawable/tuner"
                   android:theme="@style/TunerSettings"
                   android:label="@string/demo_mode"
                   android:process=":tuner"
                   android:exported="true">
             <intent-filter>
                 <action android:name="com.android.settings.action.DEMO_MODE" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity-alias>
    
         <activity
             android:name=".stackdivider.ForcedResizableInfoActivity"
             android:theme="@style/ForcedResizableTheme"
             android:excludeFromRecents="true"
             android:stateNotNeeded="true"
             android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
             android:exported="false">
         </activity>
    
         &lt;!&ndash; Springboard for launching the share and edit activity. This needs to be in the main
              system ui process since we need to notify the status bar to dismiss the keyguard &ndash;&gt;
         <receiver android:name=".screenshot.GlobalScreenshot$ActionProxyReceiver"
             android:exported="false" />
    
         &lt;!&ndash; Callback for dismissing screenshot notification after a share target is picked &ndash;&gt;
         <receiver android:name=".screenshot.GlobalScreenshot$TargetChosenReceiver"
             android:exported="false" />
    
         &lt;!&ndash; Callback for deleting screenshot notification &ndash;&gt;
         <receiver android:name=".screenshot.GlobalScreenshot$DeleteScreenshotReceiver"
             android:exported="false" />
    
         &lt;!&ndash; Callback for invoking a smart action from the screenshot notification. &ndash;&gt;
         <receiver android:name=".screenshot.GlobalScreenshot$SmartActionsReceiver"
                   android:exported="false"/>
    
         &lt;!&ndash; started from UsbDeviceSettingsManager &ndash;&gt;
         <activity android:name=".usb.UsbConfirmActivity"
             android:exported="true"
             android:permission="android.permission.MANAGE_USB"
             android:theme="@style/Theme.SystemUI.Dialog.Alert"
             android:finishOnCloseSystemDialogs="true"
             android:excludeFromRecents="true">
         </activity>
    
         &lt;!&ndash; started from UsbDeviceSettingsManager &ndash;&gt;
         <activity android:name=".usb.UsbPermissionActivity"
             android:exported="true"
             android:permission="android.permission.MANAGE_USB"
             android:theme="@style/Theme.SystemUI.Dialog.Alert"
             android:finishOnCloseSystemDialogs="true"
             android:excludeFromRecents="true">
         </activity>
    
         &lt;!&ndash; started from UsbDeviceSettingsManager &ndash;&gt;
         <activity android:name=".usb.UsbResolverActivity"
             android:exported="true"
             android:permission="android.permission.MANAGE_USB"
             android:theme="@style/Theme.SystemUI.Dialog.Alert"
             android:finishOnCloseSystemDialogs="true"
             android:excludeFromRecents="true">
         </activity>
    
         &lt;!&ndash; started from UsbDeviceSettingsManager &ndash;&gt;
         <activity android:name=".usb.UsbAccessoryUriActivity"
             android:exported="true"
             android:permission="android.permission.MANAGE_USB"
             android:theme="@style/Theme.SystemUI.Dialog.Alert"
             android:finishOnCloseSystemDialogs="true"
             android:excludeFromRecents="true">
         </activity>
    
         &lt;!&ndash; started from UsbPortManager &ndash;&gt;
         <activity android:name=".usb.UsbContaminantActivity"
             android:exported="true"
             android:permission="android.permission.MANAGE_USB"
             android:theme="@style/Theme.SystemUI.Dialog.Alert"
             android:finishOnCloseSystemDialogs="true"
             android:excludeFromRecents="true">
         </activity>
    
         &lt;!&ndash; started from AdbDebuggingManager &ndash;&gt;
         <activity android:name=".usb.UsbDebuggingActivity"
             android:permission="android.permission.MANAGE_DEBUGGING"
             android:theme="@style/Theme.SystemUI.Dialog.Alert"
             android:finishOnCloseSystemDialogs="true"
             android:excludeFromRecents="true">
         </activity>
         <activity-alias
             android:name=".UsbDebuggingActivityAlias"
             android:permission="android.permission.DUMP"
             android:targetActivity=".usb.UsbDebuggingActivity"
             android:exported="true">
         </activity-alias>
         <activity android:name=".usb.UsbDebuggingSecondaryUserActivity"
             android:theme="@style/Theme.SystemUI.Dialog.Alert"
             android:finishOnCloseSystemDialogs="true"
             android:excludeFromRecents="true">
         </activity>
    
         &lt;!&ndash; started from NetworkPolicyManagerService &ndash;&gt;
         <activity
             android:name=".net.NetworkOverLimitActivity"
             android:exported="true"
             android:permission="android.permission.MANAGE_NETWORK_POLICY"
             android:theme="@android:style/Theme.DeviceDefault.Light.Panel"
             android:finishOnCloseSystemDialogs="true"
             android:launchMode="singleTop"
             android:taskAffinity="com.android.systemui.net"
             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
             android:excludeFromRecents="true" />
    
         &lt;!&ndash; started from MediaProjectionManager &ndash;&gt;
         <activity
             android:name=".media.MediaProjectionPermissionActivity"
             android:exported="true"
             android:theme="@style/Theme.SystemUI.MediaProjectionAlertDialog"
             android:finishOnCloseSystemDialogs="true"
             android:launchMode="singleTop"
             android:excludeFromRecents="true"
             android:visibleToInstantApps="true"/>
    
         &lt;!&ndash; started from PipUI &ndash;&gt;
         <activity
             android:name=".pip.tv.PipMenuActivity"
             android:permission="com.android.systemui.permission.SELF"
             android:exported="false"
             android:theme="@style/PipTheme"
             android:launchMode="singleTop"
             android:taskAffinity=""
             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|locale|layoutDirection"
             android:resizeableActivity="true"
             android:supportsPictureInPicture="true"
             androidprv:alwaysFocusable="true"
             android:excludeFromRecents="true" />
    
         <activity
             android:name=".pip.phone.PipMenuActivity"
             android:permission="com.android.systemui.permission.SELF"
             android:theme="@style/PipPhoneOverlayControlTheme"
             android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
             android:excludeFromRecents="true"
             android:exported="false"
             android:resizeableActivity="true"
             android:supportsPictureInPicture="true"
             android:stateNotNeeded="true"
             android:taskAffinity=""
             android:launchMode="singleTop"
             androidprv:alwaysFocusable="true" />
    
         &lt;!&ndash; started from SliceProvider &ndash;&gt;
         <activity android:name=".SlicePermissionActivity"
             android:theme="@style/Theme.SystemUI.Dialog.Alert"
             android:finishOnCloseSystemDialogs="true"
             android:excludeFromRecents="true">
             <intent-filter>
                 <action android:name="com.android.intent.action.REQUEST_SLICE_PERMISSION" />
             </intent-filter>
         </activity>
    
         &lt;!&ndash; platform logo easter egg activity &ndash;&gt;
         <activity
             android:name=".DessertCase"
             android:exported="true"
             android:label="@string/dessert_case"
             android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
             android:launchMode="singleInstance"
             android:screenOrientation="locked"
             android:process=":sweetsweetdesserts"
             android:excludeFromRecents="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
    
         <activity android:name=".egg.MLandActivity"
                   android:theme="@android:style/Theme.Material.NoActionBar"
                   android:exported="true"
                   android:icon="@drawable/icon"
                   android:label="@string/mland"
                   android:launchMode="singleInstance"
                   android:screenOrientation="locked"
                   android:process=":sweetsweetdesserts"
                   android:excludeFromRecents="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
    
         &lt;!&ndash; a gallery of delicious treats &ndash;&gt;
         <service
             android:name=".DessertCaseDream"
             android:exported="true"
             android:label="@string/dessert_case"
             android:permission="android.permission.BIND_DREAM_SERVICE"
             android:enabled="false"
             android:process=":sweetsweetdesserts"
             >
             <intent-filter>
                 <action android:name="android.service.dreams.DreamService" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </service>
    
         <service
             android:name=".keyguard.KeyguardService"
             android:exported="true"
             android:enabled="@bool/config_enableKeyguardService" />
    
         <activity android:name=".keyguard.WorkLockActivity"
                   android:label="@string/accessibility_desc_work_lock"
                   android:permission="android.permission.MANAGE_USERS"
                   android:exported="false"
                   android:excludeFromRecents="true"
                   android:stateNotNeeded="true"
                   android:resumeWhilePausing="true"
                   android:theme="@android:style/Theme.Black.NoTitleBar">
             <intent-filter>
                 <action android:name="android.app.action.CONFIRM_DEVICE_CREDENTIAL_WITH_USER" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
    
         <activity android:name=".Somnambulator"
             android:label="@string/start_dreams"
             android:icon="@mipmap/ic_launcher_dreams"
             android:theme="@android:style/Theme.Wallpaper.NoTitleBar"
             android:exported="true"
             android:excludeFromRecents="true"
             >
             &lt;!&ndash;
             <intent-filter>
                 <action android:name="android.intent.action.CREATE_SHORTCUT" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
             &ndash;&gt;
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.DESK_DOCK" />
             </intent-filter>
         </activity>
    
         <activity
             android:name=".settings.BrightnessDialog"
             android:label="@string/quick_settings_brightness_dialog_title"
             android:theme="@*android:style/Theme.DeviceDefault.QuickSettings.Dialog"
             android:finishOnCloseSystemDialogs="true"
             android:launchMode="singleInstance"
             android:excludeFromRecents="true"
             android:exported="true">
             <intent-filter>
                 <action android:name="com.android.intent.action.SHOW_BRIGHTNESS_DIALOG" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
    
         <activity android:name=".ForegroundServicesDialog"
             android:process=":fgservices"
             android:excludeFromRecents="true"
             android:launchMode="singleTop"
             android:theme="@*android:style/Theme.DeviceDefault.Settings.Dialog">
             <intent-filter android:priority="1">
                 <action android:name="android.settings.FOREGROUND_SERVICES_SETTINGS" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
    
         <activity android:name=".chooser.ChooserActivity"
                 android:theme="@*android:style/Theme.NoDisplay"
                 android:finishOnCloseSystemDialogs="true"
                 android:excludeFromRecents="true"
                 android:documentLaunchMode="never"
                 android:relinquishTaskIdentity="true"
                 android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
                 android:process=":ui"
                 android:visibleToInstantApps="true">
             <intent-filter>
                 <action android:name="android.intent.action.CHOOSER" />
                 <category android:name="android.intent.category.VOICE" />
             </intent-filter>
         </activity>
    
         &lt;!&ndash; Doze with notifications, run in main sysui process for every user  &ndash;&gt;
         <service
             android:name=".doze.DozeService"
             android:exported="true"
             android:singleUser="true"
             android:permission="android.permission.BIND_DREAM_SERVICE" />
    
         <receiver
             android:name=".tuner.TunerService$ClearReceiver"
             android:exported="false">
             <intent-filter>
                 <action android:name="com.android.systemui.action.CLEAR_TUNER" />
             </intent-filter>
         </receiver>
    
         <provider
             android:name="androidx.core.content.FileProvider"
             android:authorities="com.android.systemui.fileprovider"
             android:exported="false"
             android:grantUriPermissions="true">
             <meta-data
                 android:name="android.support.FILE_PROVIDER_PATHS"
                 android:resource="@xml/fileprovider" />
         </provider>
    
         <provider android:name=".keyguard.KeyguardSliceProvider"
                   android:authorities="com.android.systemui.keyguard"
                   android:grantUriPermissions="true"
                   android:exported="true">
         </provider>
    
         &lt;!&ndash; Provides list and realistic previews of clock faces for the picker app. &ndash;&gt;
         <provider
             android:name="com.android.keyguard.clock.ClockOptionsProvider"
             android:authorities="com.android.keyguard.clock"
             android:enabled="false"
             android:exported="false"
             android:grantUriPermissions="true">
         </provider>
    
         <receiver
             android:name=".statusbar.KeyboardShortcutsReceiver">
             <intent-filter>
                 <action android:name="com.android.intent.action.DISMISS_KEYBOARD_SHORTCUTS" />
                 <action android:name="com.android.intent.action.SHOW_KEYBOARD_SHORTCUTS" />
             </intent-filter>
         </receiver>-->
    
    
        <service
            android:name="com.android.XX.notification.XXNotificationListener"
            android:exported="true"
            android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
            tools:ignore="Instantiatable">
            <intent-filter>
                <action android:name="android.service.notification.NotificationListenerService"></action>
            </intent-filter>
        </service>
    </application>
    

    3:然后自定义StatusBar

    com.android.XX.CustomStatusBar
    public class XXXStatusBar extends SystemUI {
    private WindowManager mWinddowManager;

    @Inject
    InjectionInflationController mInjectionInflater;
    private XXXStatusBarWindowView mStatusBarView;
    private XXXNotificationPanelView mPanelView;
    private WindowManager.LayoutParams mStatusBarParams;
    private ViewGroup mNavigationBarView;
    private WindowManager.LayoutParams mNavigationBarParams;
    private int mStatusBarHeight;
    
    @Override
    public void start() {
        putComponent(XXXStatusBar.class, this);
        mWinddowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        addStatusBarToWindows();
        addNavigationBarToWindows();
        startNotificationService();
    }
    }
        private void addStatusBarToWindows() {
        mStatusBarHeight = getStatusBarHeight();
        mStatusBarParams = new WindowManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, mStatusBarHeight,
                WindowManager.LayoutParams.TYPE_STATUS_BAR,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                        | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                PixelFormat.TRANSLUCENT);
        mStatusBarParams.token = new Binder();
        mStatusBarParams.gravity = Gravity.TOP;
        mStatusBarParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
        mStatusBarParams.setTitle("StatusBar");
        mStatusBarParams.packageName = mContext.getPackageName();
        mStatusBarParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
        //mInjectionInflater.injectable(LayoutInflater.from(mContext)).inflate(R.layout.XXX_status_bar, null);
        //Log.i("gary","--mStatusBarView--:"+mInjectionInflater.injectable(LayoutInflater.from(mContext)).inflate(R.layout.XXX_status_bar, null));
        mStatusBarView = (XXXStatusBarWindowView) View.inflate(mContext, R.layout.XXX_status_bar, null);
    
        mPanelView = mStatusBarView.findViewById(R.id.dropdown_panel);
        mStatusBarView.setPanel(mPanelView);
        mPanelView.setBar(this);
        mStatusBarView.setBar(this);
    
        mWinddowManager.addView(mStatusBarView, mStatusBarParams);
    
    }
    
    private void addNavigationBarToWindows() {
        mNavigationBarParams = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
                WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                        | WindowManager.LayoutParams.FLAG_SLIPPERY,
                PixelFormat.TRANSLUCENT);
        mNavigationBarParams.token = new Binder();
        mNavigationBarParams.setTitle("NavigationBar" + mContext.getDisplayId());
        mNavigationBarParams.accessibilityTitle = mContext.getString(R.string.nav_bar);
        mNavigationBarParams.windowAnimations = 0;
        mNavigationBarParams.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
        mNavigationBarView = (ViewGroup) View.inflate(mContext, R.layout.XXX_navigation_bar, null);
        mWinddowManager.addView(mNavigationBarView, mNavigationBarParams);
        });
    }
    

    这样自定义的状态栏,导航栏就定义出来了,具体的一些自定义功能就可以参考原生的功能实现,其实百度搜系统api支持大都可以是实现了。

    2.自定义下拉面板,VolumeBar,通知中心.

    1:自定义下拉面板:可以添加一个window,然后开始默认layout到负一屏的位置,用户滑动状态栏时,根据手势移动这个widow就可以了。

    2:自定义VolumeBar:可以参考原生的实现方式监听volumechanged然后弹Window。

    3:通知中心:自定义一个Service集成系统的NotificationListenerService 在onNotificationPosted和onNotificationRemoved处理通知。

    总结

    屏蔽掉原生Service,然后参考原生Service实现逻辑,实现自定义,这样自己更好控制,也能达到深度裁剪,性能优化的效果,这样会让你的SystemUI很轻量。

    展开全文
  • SystemUI新增图标demo

    2017-11-06 21:14:42
    SystemUI新增图标demo,模拟源码添加一个BatterySaver图标
  • Android 8.0 系统自带 SystemUI Android 8.0 系统自带 SystemUI
  • SystemUI简介

    千次阅读 2022-01-19 16:57:11
    SystemUI简介 简介 SystemUI应用是一个持久化进程,它为用户提供系统级别的信息显示与交互的一套UI组件,其 UID 是 SYSTEM_UID,值为1000,是系统核心应用,能够使用系统级权限,能够访问系统隐藏的API(@hide方法...

    SystemUI简介

    • 简介

    SystemUI应用是一个持久化进程,它为用户提供系统级别的信息显示与交互的一套UI组件,其 UID SYSTEM_UID,值为1000,是系统核心应用,能够使用系统级权限,能够访问系统隐藏的API@hide方法)和internal资源,在开机时由 SystemServer 启动 SystemUIService 实现应用启动。

    SystemUI

    普通应用

    UID

    1000

    应用安装时分配,>10000

    编译方式

    基于Android源码编译

    基于Android SDK编译

    安装方式

    adb push SystemUI.apk /system/priv-app/SystemUI

    adb install App.apk

    安装位置

    /system/priv-app/

    /data/app/

    数据位置

    /data/user_de/

    /data/data/

    启动方式

    系统启动

    点击桌面应用图标

    代码位置

    Framework/base/package

    • 功能介绍

    SystemU包含功能有:导航栏,状态栏,通知栏,近期列表等

     

    组件

    功能

    NotificationChannels

    创建SystemUI的通知Channel

    KeyguardViewMediator

    Recents

    最近任务

    VolumeUI

    音量面板

    Divider

    分屏

    StatusBar

    顶部状态栏+快捷开关+通知面板+底部导航键

    StorageNotification

    存储设备相关通知

    PowerUI

    低电量提醒

    RingtonePlayer

    播放铃声(包括通知铃声)

    KeyboardUI

    键盘

    PipUI

    画中画

    ShortcutKeyDispatcher

    GarbageMonitor$Service

    定期检查SystemUI堆内存并报告

    LatencyTester

    DEBUGGABLE版本运行,用于测试系统中的延迟

    GlobalActionsComponent

    关机菜单

    ScreenDecorations

    手机屏幕屏切圆角,模拟刘海屏

    AuthController

    显示生物识别UI(指纹认证,人脸认证)

    SliceBroadcastRelayHandler

    SizeCompatModeActivityController

    InstantAppNotifier

    显示Instant Apps(用户设备不需要安装的应用)的通知

    ThemeOverlayController

    WindowMagnification

    管理窗口放大镜

    ToastUI

    SystemUI进程显示其他应用的Toast

    SystemActions

    services组件启动时配置列表 : (R.array.config_systemUIServiceComponents)

    所有 SystemUIService 都是继承自 SystemUI.class , SystemUI.class 是一个抽象类

    1. <item>com.android.systemui.util.NotificationChannels</item> 通知信息 
    2. <item>com.android.systemui.keyguard.KeyguardViewMediator</item> 锁屏 
    3. <item>com.android.systemui.recents.Recents</item> 近期列表
    4. Android 10之后近期列表的显示被移到Launcher里面了。在Launcher3的一个 类中TouchInteractionService.java   IBinder mMyBinder = new IOverviewProxy.Stub() 通过AIDL的方法与systemUI通信
    5. ————————————————
    6. <item>com.android.systemui.volume.VolumeUI</item> 声音UI显示 
    7. <item>com.android.systemui.statusbar.phone.StatusBar</item> 状态栏及下拉面板
    8. <item>com.android.systemui.usb.StorageNotification</item> usb通知管理 
    9. <item>com.android.systemui.power.PowerUI</item>  电源UI显示管理
    10. <item>com.android.systemui.media.RingtonePlayer</item> 播放铃声 
    11. <item>com.android.systemui.keyboard.KeyboardUI</item>键盘UI 
    12. <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>快捷方式  
    13. <item>@string/config_systemUIVendorServiceComponent</item>厂商相关定制 
    14. <item>com.android.systemui.util.leak.GarbageMonitor$Service</item>垃圾监测器  
    15. <item>com.android.systemui.LatencyTester</item> 延迟测试仪 
    16. <item>com.android.systemui.globalactions.GlobalActionsComponent</item>  关机界面的显示、全局控制
    17. <item>com.android.systemui.ScreenDecorations</item>屏幕装饰  
    18. <item>com.android.systemui.biometrics.AuthController</item>生物识别  
    19. <item>com.android.systemui.SliceBroadcastRelayHandler</item> 切片广播 
    20. <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>  
    21. <item>com.android.systemui.theme.ThemeOverlayController</item>  
    22. <item>com.android.systemui.accessibility.WindowMagnification</item>  
    23. <item>com.android.systemui.accessibility.SystemActions</item>  
    24. <item>com.android.systemui.toast.ToastUI</item>  Toast
    25. <item>com.android.systemui.wmshell.WMShell</item> 

    展开全文
  • SystemUi通知栏

    千次阅读 2021-12-01 15:13:07
    视图 通知图标显示分析: 如上所述,所有的通知信息保存在了自定义view ...在SystemUI进程中对notification的处理流程如下: 源码分析 关键信息类 2. 获取Notificati...
  • android9 SystemUI启动流程

    千次阅读 2022-01-24 16:52:03
    一.SystemUI概述 SystemUI 是一个系统应用,apk路径位于/system/priv-app 源码路径位于:/framework/base/packages/SystemUI 主要负责功能: StatusBar:状态栏 NavigationBar:导航栏(返回、home、近期任务) ...
  • 什么是SystemUI?简单分析

    千次阅读 2021-02-23 21:06:37
    SystemUI概览 SystemUI属于系统级的apk,位置在frameworks\base\packages\SystemUI,主要功能有: 状态栏信息显示,比如电池,wifi信号,3G/4G等icon显示 通知面板,比如系统消息,第三方应用消息 近期任务栏...
  • 系统用户界面_com.android.systemui.apk

    热门讨论 2013-05-17 04:19:35
    系统用户界面_com.android.systemui,当您误删此文件,您的安卓手机会提示:com.android.systemui已经停止工作,此时您就需要下载此文件,重新安装即可。
  • Android SystemUI之启动流程(一)

    千次阅读 2020-07-09 15:50:37
    SystemUI是系统最重要的一个APK,它属于persistent app,什么是persistent app呢?简单的来说就是,具有系统签名,并且在AndroidMainfest中声明persistent=true,如果是使用flag来匹配查找的话:ApplicationInfo....
  • SystemUI启动,及其SystemUIService启动

    千次阅读 2022-01-22 20:29:43
    SystemUI启动,及其SystemUIService启动 android12-release SystemServer.run() - startOtherServices - startSystemUi - context.startServiceAsUser - windowManager.onSystemUiStarted() frameworks/base/core...
  • Android10 SystemUI系统手势导航

    千次阅读 2021-10-26 13:48:31
    从Android9开始,android系统就... 对于系统导航手势的实现,android10还是在SystemUI中实现的,在以后的版本中可能就是在Launcher3中,SystemUI是一个系统应用,在SystemServer中启动,先来看下是如何启动的: ...
  • 众所周知Android framework中的SystemUI包含基本的StatusBar、VolumeBar、NavigationBar等部分,在手机开机时就已经为我们加载好,但是有时候会出现对StatusBar,DropList等进行定制化的任务,那么就需要了解System...
  • 安卓SystemUI.apk文件的修改教程

    千次阅读 2021-06-06 05:16:04
    位于安卓/system/app目录下的SystemUI.apk文件中包含着安卓界面中的图标资源文件,我们可以通过修改替换其中的图片文件来达到美化系统界面的目的。下面是安卓后院(www.top139.com)为大家整理的SystemUI.apk文件的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 405,950
精华内容 162,380
关键字:

systemui