本文先解决以下疑问,然后给出分屏的总体结构
a. 分屏task 哪里来
b. 分屏task 信息如何同步到Systemui
c. 如何进入分屏并显示分屏的操作view

  1. 首先当然是分屏task 启动了,解决分屏task 哪里来的问题
    要讲清楚这个问题,首先要明白虽然分屏task 看起来由systemui 控制,但是实际上task依旧是system_server(中WM管理模块)创建,而systemui只是拿到创建后的控制句柄(我暂且叫他控制句柄,只是是啥后面在看)。
    为了提供上面功能,Wm-shell 提供了一个创建以及监听wmtask 信息的aidl接口。
    ITaskOrganizerController 为AIDL接口,
    看他接口函数就知道这提供一个进程间创建task的途径 ,在system这边会有ITaskOrganizerController 的一个BN实例,作为创建task的服务端(也即为wm 服务端)。
    syetemui获取到BP去创建task
    主要接口:
    Java
    ParceledListSlice registerTaskOrganizer(ITaskOrganizer organizer);
    /**
    • Unregisters a previously registered task organizer.
      /
      void unregisterTaskOrganizer(ITaskOrganizer organizer);
      /
      * Creates a persistent root task in WM for a particular windowing-mode. /
      void createRootTask(int displayId, int windowingMode, IBinder launchCookie);
      /
      * Deletes a persistent root task in WM */
      boolean deleteRootTask(in WindowContainerToken task);
      看一下Systemserver(e, Systemserver 这里主要是WMS管理模块部分)的BN
      TaskOrganizerController.java
      TaskOrganizerController extends ITaskOrganizerController.Stub
      我们先不看TaskOrganizerController 内部结构,先看一下wm里面如何嵌入组织管理TaskOrganizerController 的。
      Java
      WindowOrganizerController(ActivityTaskManagerService atm) {
      mService = atm;
      mGlobalLock = atm.mGlobalLock;
      mTaskOrganizerController = new TaskOrganizerController(mService);
      mDisplayAreaOrganizerController = new DisplayAreaOrganizerController(mService);
      mTaskFragmentOrganizerController = new TaskFragmentOrganizerController(atm);
      }
      Wms 对OrganizerController 又增设置了一层管理者WindowOrganizerController里面就会有一个TaskOrganizerController 对象,作为wm的task 操作管理者。
      我们可以看到 还有DisplayAreaOrganizerController 和 TaskFragmentOrganizerController
      DisplayAreaOrganizerController 后面可能涉及到,暂时还没看(我现在处理笔记状态写的,不是很确定)。TaskFragmentOrganizerController 这个应该是平行视窗控制BN。
      然后AMS里有这么一句
      ActivityTaskManagerService.java
      Java
      @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
      public ActivityTaskManagerService(Context context) {
      mContext = context;
      mFactoryTest = FactoryTest.getMode();
      mSystemThread = ActivityThread.currentActivityThread();
      mUiContext = mSystemThread.getSystemUiContext();
      mLifecycleManager = new ClientLifecycleManager();
      mVisibleActivityProcessTracker = new VisibleActivityProcessTracker(this);
      mInternal = new LocalService();
      GL_ES_VERSION = SystemProperties.getInt(“ro.opengles.version”, GL_ES_VERSION_UNDEFINED);
      mWindowOrganizerController = new WindowOrganizerController(this);
      mTaskOrganizerController = mWindowOrganizerController.mTaskOrganizerController;
      mTaskFragmentOrganizerController =
      mWindowOrganizerController.mTaskFragmentOrganizerController;
      mBackNavigationController = BackNavigationController.isEnabled()
      ? new BackNavigationController() : null;
      }
      所以也比较简单就这下面这种结构
      在这里插入图片描述
      至于具体怎么创建移除我就不多讲了,有兴趣自己看,本文只想摸清task 主要流程和整体框架。
      好了 到这里system提供创建task 的能力算是有了
      那systemui怎么去创建呢
      来看看systemui这边逻辑
      由于SystemUI这边有一部分逻辑无代码,但是systemui这边创建Task无疑要拿到systemserver提供的TaskOrganizerController BP并创建task,
      这个TaskOrganizerController BP获取接口在TaskOrganizer
      我在pixl 4上打印systemui创建的TaskOrganizer
      实际上创建的是ShellTaskOrganizer 子类 ShellTaskOrganizer 继承至TaskOrganizer
      然后通过ShellTaskOrganizer 创建task
      Java
      11-12 08:27:40.037 2408 3213 E DEBUGTASKOR: android.window.TaskOrganizer 1@b54dd50 ce = com.android.wm.shell.ShellTaskOrganizer.<init>:2 com.android.wm.shell.ShellTaskOrganizer.<init>:1 com.android.systemui.media.MediaSessionBasedFilter_Factory.get:116 dagger.internal.DoubleCheck.get:13 dagger.internal.DelegateFactory.get:4 com.android.wm.shell.dagger.WMShellBaseModule_ProvideShellInitImplFactory.get:40 dagger.internal.DoubleCheck.get:13 com.android.systemui.doze.DozeAuthRemover_Factory.get:150 dagger.internal.DoubleCheck.get:13 com.android.systemui.dagger.DaggerGlobalRootComponent 1 @ b 5 4 d d 5 0 c e = c o m . a n d r o i d . w m . s h e l l . S h e l l T a s k O r g a n i z e r . < i n i t > : 2 c o m . a n d r o i d . w m . s h e l l . S h e l l T a s k O r g a n i z e r . < i n i t > : 1 c o m . a n d r o i d . s y s t e m u i . m e d i a . M e d i a S e s s i o n B a s e d F i l t e r F a c t o r y . g e t : 1 1 6 d a g g e r . i n t e r n a l . D o u b l e C h e c k . g e t : 1 3 d a g g e r . i n t e r n a l . D e l e g a t e F a c t o r y . g e t : 4 c o m . a n d r o i d . w m . s h e l l . d a g g e r . W M S h e l l B a s e M o d u l e P r o v i d e S h e l l I n i t I m p l F a c t o r y . g e t : 4 0 d a g g e r . i n t e r n a l . D o u b l e C h e c k . g e t : 1 3 c o m . a n d r o i d . s y s t e m u i . d o z e . D o z e A u t h R e m o v e r F a c t o r y . g e t : 1 5 0 d a g g e r . i n t e r n a l . D o u b l e C h e c k . g e t : 1 3 c o m . a n d r o i d . s y s t e m u i . d a g g e r . D a g g e r G l o b a l R o o t C o m p o n e n t WMComponentImpl.getShellInit:2
      com.android.systemui.dagger.WMComponent.init:0
      com.android.systemui.dagger.DaggerGlobalRootComponent WMComponentImpl.init:0 com.android.systemui.SystemUIFactory.init:15 com.android.systemui.SystemUIFactory.createFromConfig:36 com.android.systemui.media.MediaControlPanel W M C o m p o n e n t I m p l . i n i t : 0 c o m . a n d r o i d . s y s t e m u i . S y s t e m U I F a c t o r y . i n i t : 1 5 c o m . a n d r o i d . s y s t e m u i . S y s t e m U I F a c t o r y . c r e a t e F r o m C o n f i g : 3 6 c o m . a n d r o i d . s y s t e m u i . m e d i a . M e d i a C o n t r o l P a n e l ExternalSyntheticLambda7.onContextAvailable:7 com.android.systemui.keyguard.KeyguardSliceProvider.onCreateSliceProvider:6 androidx.slice.SliceProvider.onCreate:0 android.content.ContentProvider.attachInfo:2451 android.content.ContentProvider.attachInfo:2421 androidx.slice.SliceProvider.attachInfo:0 应用使用千奇百怪不用管,我们只需要知道 由wmshell ShellTaskOrganizer 提供task操作接口,后续都是基于ShellTaskOrganizer 这套逻辑。 然后为支持分屏systemui 分别创建了三个task 第一个: 11-12 08:27:40.037 2408 3213 E DEBUGTASKOR: Createtask 1 windowingMode = 1com.android.wm.shell.ShellTaskOrganizer.createRootTask:58 com.android.wm.shell.splitscreen.StageCoordinator.<init>:18 com.android.wm.shell.ShellInitImpl E x t e r n a l S y n t h e t i c L a m b d a 7 . o n C o n t e x t A v a i l a b l e : 7 c o m . a n d r o i d . s y s t e m u i . k e y g u a r d . K e y g u a r d S l i c e P r o v i d e r . o n C r e a t e S l i c e P r o v i d e r : 6 a n d r o i d x . s l i c e . S l i c e P r o v i d e r . o n C r e a t e : 0 a n d r o i d . c o n t e n t . C o n t e n t P r o v i d e r . a t t a c h I n f o : 2 4 5 1 a n d r o i d . c o n t e n t . C o n t e n t P r o v i d e r . a t t a c h I n f o : 2 4 2 1 a n d r o i d x . s l i c e . S l i c e P r o v i d e r . a t t a c h I n f o : 0 使 w m s h e l l S h e l l T a s k O r g a n i z e r t a s k S h e l l T a s k O r g a n i z e r s y s t e m u i t a s k 1 1 1 2 0 8 : 2 7 : 4 0 . 0 3 7 2 4 0 8 3 2 1 3 E D E B U G T A S K O R : C r e a t e t a s k 1 w i n d o w i n g M o d e = 1 c o m . a n d r o i d . w m . s h e l l . S h e l l T a s k O r g a n i z e r . c r e a t e R o o t T a s k : 5 8 c o m . a n d r o i d . w m . s h e l l . s p l i t s c r e e n . S t a g e C o o r d i n a t o r . < i n i t > : 1 8 c o m . a n d r o i d . w m . s h e l l . S h e l l I n i t I m p l ExternalSyntheticLambda1.accept:41 java.util.Optional.ifPresent:179 com.android.wm.shell.ShellInitImpl E x t e r n a l S y n t h e t i c L a m b d a 1 . a c c e p t : 4 1 j a v a . u t i l . O p t i o n a l . i f P r e s e n t : 1 7 9 c o m . a n d r o i d . w m . s h e l l . S h e l l I n i t I m p l InitImpl E x t e r n a l S y n t h e t i c L a m b d a 0 . r u n : 8 3 c o m . a n d r o i d . s y s t e m u i . S y s t e m U I A p p l i c a t i o n ExternalSyntheticLambda2.run:130 com.android.wm.shell.common.HandlerExecutor.execute:12 com.android.wm.shell.common.ShellExecutor.executeBlocking:2 com.android.wm.shell.common.ShellExecutor.executeBlocking:4 com.android.wm.shell.ShellInitImpl InitImpl.init:9 com.android.systemui.dagger.WMComponent.init:4 com.android.systemui.dagger.DaggerGlobalRootComponent I n i t I m p l . i n i t : 9 c o m . a n d r o i d . s y s t e m u i . d a g g e r . W M C o m p o n e n t . i n i t : 4 c o m . a n d r o i d . s y s t e m u i . d a g g e r . D a g g e r G l o b a l R o o t C o m p o n e n t WMComponentImpl.init:0 com.android.systemui.SystemUIFactory.init:15 com.android.systemui.SystemUIFactory.createFromConfig:36 com.android.systemui.media.MediaControlPanel ExternalSyntheticLambda7.onContextAvailable:7 com.android.systemui.keyguard.KeyguardSliceProvider.onCreateSliceProvider:6 androidx.slice.SliceProvider.onCreate:0 android.content.ContentProvider.attachInfo:2451 android.content.ContentProvider.attachInfo:2421 androidx.slice.SliceProvider.attachInfo:0 第二个: 11-12 08:27:40.037 2408 3213 E DEBUGTASKOR: Createtask 2 windowingMode = 6com.android.wm.shell.ShellTaskOrganizer.createRootTask:58 com.android.wm.shell.splitscreen.StageTaskListener.<init>:30 com.android.wm.shell.splitscreen.MainStage.<init>:0 com.android.wm.shell.splitscreen.StageCoordinator.<init>:19 com.android.wm.shell.ShellInitImpl E x t e r n a l S y n t h e t i c L a m b d a 7 . o n C o n t e x t A v a i l a b l e : 7 c o m . a n d r o i d . s y s t e m u i . k e y g u a r d . K e y g u a r d S l i c e P r o v i d e r . o n C r e a t e S l i c e P r o v i d e r : 6 a n d r o i d x . s l i c e . S l i c e P r o v i d e r . o n C r e a t e : 0 a n d r o i d . c o n t e n t . C o n t e n t P r o v i d e r . a t t a c h I n f o : 2 4 5 1 a n d r o i d . c o n t e n t . C o n t e n t P r o v i d e r . a t t a c h I n f o : 2 4 2 1 a n d r o i d x . s l i c e . S l i c e P r o v i d e r . a t t a c h I n f o : 0 1 1 1 2 0 8 : 2 7 : 4 0 . 0 3 7 2 4 0 8 3 2 1 3 E D E B U G T A S K O R : C r e a t e t a s k 2 w i n d o w i n g M o d e = 6 c o m . a n d r o i d . w m . s h e l l . S h e l l T a s k O r g a n i z e r . c r e a t e R o o t T a s k : 5 8 c o m . a n d r o i d . w m . s h e l l . s p l i t s c r e e n . S t a g e T a s k L i s t e n e r . < i n i t > : 3 0 c o m . a n d r o i d . w m . s h e l l . s p l i t s c r e e n . M a i n S t a g e . < i n i t > : 0 c o m . a n d r o i d . w m . s h e l l . s p l i t s c r e e n . S t a g e C o o r d i n a t o r . < i n i t > : 1 9 c o m . a n d r o i d . w m . s h e l l . S h e l l I n i t I m p l ExternalSyntheticLambda1.accept:41 java.util.Optional.ifPresent:179 com.android.wm.shell.ShellInitImpl ExternalSyntheticLambda2.run:130 com.android.wm.shell.common.HandlerExecutor.execute:12 com.android.wm.shell.common.ShellExecutor.executeBlocking:2 com.android.wm.shell.common.ShellExecutor.executeBlocking:4 com.android.wm.shell.ShellInitImpl E x t e r n a l S y n t h e t i c L a m b d a 2 . r u n : 1 3 0 c o m . a n d r o i d . w m . s h e l l . c o m m o n . H a n d l e r E x e c u t o r . e x e c u t e : 1 2 c o m . a n d r o i d . w m . s h e l l . c o m m o n . S h e l l E x e c u t o r . e x e c u t e B l o c k i n g : 2 c o m . a n d r o i d . w m . s h e l l . c o m m o n . S h e l l E x e c u t o r . e x e c u t e B l o c k i n g : 4 c o m . a n d r o i d . w m . s h e l l . S h e l l I n i t I m p l InitImpl.ini

第三个:
11-12 08:27:40.037 2408 3213 E DEBUGTASKOR: Createtask 3 windowingMode = 6com.android.wm.shell.ShellTaskOrganizer.createRootTask:58 com.android.wm.shell.splitscreen.StageTaskListener.:30 com.android.wm.shell.splitscreen.SideStage.:0 com.android.wm.shell.splitscreen.StageCoordinator.:20 com.android.wm.shell.ShellInitImpl KaTeX parse error: Can't use function '$' in math mode at position 103: …l.ShellInitImpl$̲InitImpl ExternalSyntheticLambda0.run:83 com.android.systemui.SystemUIApplication KaTeX parse error: Can't use function '$' in math mode at position 243: …l.ShellInitImpl$̲InitImpl.init:9… ExternalSyntheticLambda7.onContextAvailable:7 com.android.systemui.keyguard.KeyguardSliceProvider.onCreateSliceProvider:6 androidx.slice.SliceProvider.onCreate:0 android.content.ContentProvider.attachInfo:2451
从堆栈我们就能看出一个简单的结构:
Systemui 初始化shell的时候会创建StageCoordinator
以及内部有两个SideStage 和MainStage
虽然还没看,但可以大胆猜想一下,其实这里StageCoordinator常见的是分屏的根SideStage 和MainStage分别创建了两个容纳两个应用的task,那么我猜测StageCoordinator 从名字以及创建的位置可以确定他是决定分屏两个task的位置大小层级的。
SideStage 和 MainStage不用说 就是分屏的主次task app状态维护的了。

好我们现在主角出现了四个(顺便提一句 StageCoordinator依附SplitScreenController ,SplitScreenController 有wmshell中WMShellModule.java 对sysmeui提供)

ShellTaskOrganizer StageCoordinator SideStage MainStage

ShellTaskOrganizer 没啥好说的BP的封装,以及APP 注入信息回调等,可以理解为 两进城的信息传递桥梁。 当然我们这里只是关注BP部分,这里面还有个BN其实 主要是systemui这边为了监听system测task信息变化,属于下一个问题,一会再说。

来看看 StageCoordinator, 他的创建在SplitScreenController
Java
public void onOrganizerRegistered() {
if (mStageCoordinator == null) {
// TODO: Multi-display
mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
mTaskOrganizer, mDisplayController, mDisplayImeController,
mDisplayInsetsController, mTransitions, mTransactionPool, mLogger,
mIconProvider, mMainExecutor, mRecentTasksOptional, mUnfoldControllerProvider);
}
}
SplitScreenController 属于ShellInitImpl 一部分,并跟随ShellInitImpl 初始化

看一下StageCoordinator 初始化的时候做了啥

Java
StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
ShellTaskOrganizer taskOrganizer, DisplayController displayController,
DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController, Transitions transitions,
TransactionPool transactionPool, SplitscreenEventLogger logger,
IconProvider iconProvider, ShellExecutor mainExecutor,
Optional recentTasks,
Provider<Optional> unfoldControllerProvider) {
mContext = context;
mDisplayId = displayId;
mSyncQueue = syncQueue;
mTaskOrganizer = taskOrganizer;
mLogger = logger;
mMainExecutor = mainExecutor;
mRecentTasks = recentTasks;
mMainUnfoldController = unfoldControllerProvider.get().orElse(null);
mSideUnfoldController = unfoldControllerProvider.get().orElse(null);
创建分屏的主task
taskOrganizer.createRootTask(displayId, WINDOWING_MODE_FULLSCREEN, this /* listener */);

    mMainStage = new MainStage(
            mContext,
            mTaskOrganizer,
            mDisplayId,
            mMainStageListener,
            mSyncQueue,
            mSurfaceSession,
            iconProvider,
            mMainUnfoldController);
    mSideStage = new SideStage(
            mContext,
            mTaskOrganizer,
            mDisplayId,
            mSideStageListener,
            mSyncQueue,
            mSurfaceSession,
            iconProvider,
            mSideUnfoldController);
    mDisplayController = displayController;
    mDisplayImeController = displayImeController;
    mDisplayInsetsController = displayInsetsController;
    mTransactionPool = transactionPool;
    final DeviceStateManager deviceStateManager =
            mContext.getSystemService(DeviceStateManager.class);
    deviceSt

可以看到 主要创建了一个分屏的主task,这下面会挂两个主次分屏应用
另外这里还有个private SplitLayout mSplitLayout; 这个可能和分屏bar有关,后面看分屏view 操作的时候看。

主次分屏主要处理类为这里创建的mMainStage 和 mSideStage
再分别看看mMainStage 和 mSideStage
这两个类构造函数都是创建了各自装自己app的task
Java
StageTaskListener(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
SurfaceSession surfaceSession, IconProvider iconProvider,
@Nullable StageTaskUnfoldController stageTaskUnfoldController) {
mContext = context;
mCallbacks = callbacks;
mSyncQueue = syncQueue;
mSurfaceSession = surfaceSession;
mIconProvider = iconProvider;
mStageTaskUnfoldController = stageTaskUnfoldController;
taskOrganizer.createRootTask(displayId, WINDOWING_MODE_MULTI_WINDOW, this);
}

现在分屏的主体结构有了。看一下到目前为止systemui这边 或者说wmshell的整体结构吧
在这里插入图片描述
到此view 出现了。
后续view 至于怎么加入的,有兴趣自己看就不看了。

不知道你注意到没,要想走到这里还有一至关重要的条件就是mMainStage.isActive()

好再看一下mMainStage 的状态。
这个是在startTasks 时候将mMainStage设置为active的。
如果走的系统直接reparent 就直接走onStageHasChildrenChanged 这条路径。有兴趣自己跟一下流程。
好了就完事了。

我这个也是第一次看,但是我基本觉得我可以搞分屏开发了,就看各位看了了解了几分吧

目前已经成功用此框架完成新功能开发

里面也许有些许错误 毕竟第一次看 只看了不到两天哈 见谅。

这里只给出TaskView的代码,相关联的源码,请看源码,如果想要使用TaskView需要自己去编译frameWork的源码,打包一个aar,或者jar出来使用,否则无法直接使用。1.如果分屏的应用如启动两个应用按照权重占比,互相不叠加在一起,点触摸击事件都可响应,例如左边启动QQ了,右边启动的是微信,二者窗口都可操作。TaskView是谷歌整合安卓多任务多窗口下交互重新重构的独立出来的module,本身继承自ServiceView,TaskView的相关概念性的东西参考。//创建的taskview。 2.main activity启动并压入back stack中,默认为这个back statck的root activity; 3.新的activity启动,压入back stack; 4.点击Back按键,弹出back statck; 这里是为啥阿,因为高版本StartingWindow已经移殖到了Systemui进程,让Systemui来负责窗口创建相关,所以自然就wms端处理不了,要跨进程让systemui处理。这里注意,明显用wm开启时候,和正常wm相关的打印输出也是不一样的,明显显示是No IProtoLogGroup named WM_SHELL_STARTING_WINDOW。这个时候logcat -s WindowManager是没有这个shell相关打印,必须要。才可以打印出相关的Proto日志。 首先设备得越狱 众所周知,在Xcode上开发的程序只能在模拟器中运行,如果要放到真机上则要花费99美金购买开发者证书iDP。这严重阻碍了我等草根开发者探索的脚步。写个小程序,同学间分享一下这个小小的愿望都不能满足,自然不能善罢甘休。 在没有iDP的情况下,要想将程序放到iPhone上调试,并最终发布IPA用于分享,需要以下几个步骤: 1.自己为自己颁发一个证书用于为生成的程序签... Swift是一种通用的编译编程语言,由Apple为macOS,iOS,watchOS,tvOS和Linux开发。Swift提供更好的安全性,性能和安全性,并允许我们编写安全但严格的代码。截至目前,Swift仅适用**Ubuntu**于Linux平台的安装。因此,在本教程中,我们将讨论如何在Linux上安装Swift,或者更准确地说如何在Ubuntu上安装Swift。从终端检查您的Ubuntu版本这... 分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #IDTitleSol ,yNNNNNNNNo ,mMMMMMMMMd, _/', `; `; `\ -Mm oMd `NM: , _..,-'' ' ` ` `\ :Mm mM oMN mM: