Android 12系统源码_多窗口模式(二)系统实现分屏的功能原理 ...

打印 上一主题 下一主题

主题 867|帖子 867|积分 2611

媒介

上一篇我们具体分析了系统处于多窗口模式下,Android应用和多窗口模式相干方法的调用次序,对于应用如何适配多窗口模式有了一个开端的熟悉,本篇文章我们将会联合Android12系统源码,具体来梳理一下系统是如何触发多窗口分屏模式,以及实现多窗口分屏模式功能的原理。
一、Launcher3触发分屏

1、Android12的分屏模式触发入口,默认是在最近任务列表中的,而最近任务列表是包含在Launcher3内里的,当我们在最近任务列表中点击分屏按钮后,会先触发Launcher进入分屏的一系列悬浮动画以及初始的图标分屏。



以上步骤都属于Launcher的业务逻辑。
2、接下来我们联合系统源码来简朴看下Launcher3模块是如何触发分屏功能的。
   packages/apps/Launcher3/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
  1. public class QuickstepLauncher extends BaseQuickstepLauncher {
  2.     @Override
  3.     public void onStateSetEnd(LauncherState state) {
  4.         super.onStateSetEnd(state);
  5.         switch (state.ordinal) {
  6.                         ...代码省略...
  7.             case QUICK_SWITCH_STATE_ORDINAL: {
  8.                 RecentsView rv = getOverviewPanel();
  9.                 TaskView tasktolaunch = rv.getTaskViewAt(0);
  10.                 if (tasktolaunch != null) {
  11.                         //调用TaskView的launchTask方法
  12.                     tasktolaunch.launchTask(success -> {
  13.                         if (!success) {
  14.                             getStateManager().goToState(OVERVIEW);
  15.                         } else {
  16.                             getStateManager().moveToRestState();
  17.                         }
  18.                     });
  19.                 } else {
  20.                     getStateManager().goToState(NORMAL);
  21.                 }
  22.                 break;
  23.             }
  24.         }
  25.     }
  26. }
复制代码
  package/apps/Launcher3/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
  1. public class GroupedTaskView extends TaskView {
  2.     @Nullable
  3.     @Override
  4.     public RunnableList launchTaskAnimated() {
  5.         if (mTask == null || mSecondaryTask == null) {
  6.             return null;
  7.         }
  8.         RunnableList endCallback = new RunnableList();
  9.         RecentsView recentsView = getRecentsView();
  10.         // Callbacks run from remote animation when recents animation not currently running
  11.         //调用RecentsView的getSplitPlaceholder方法,获取SplitSelectStateController对象实例,调用launchTasks方法
  12.         recentsView.getSplitPlaceholder().launchTasks(this /*groupedTaskView*/,
  13.                 success -> endCallback.executeAllAndDestroy(),
  14.                 false /* freezeTaskList */);
  15.         // Callbacks get run from recentsView for case when recents animation already running
  16.         recentsView.addSideTaskLaunchCallback(endCallback);
  17.         return endCallback;
  18.     }
  19.     @Override
  20.     public void launchTask(@NonNull Consumer<Boolean> callback, boolean freezeTaskList) {
  21.          //调用RecentsView的getSplitPlaceholder方法,获取SplitSelectStateController对象实例,调用launchTasks方法
  22.         getRecentsView().getSplitPlaceholder().launchTasks(mTask, mSecondaryTask,
  23.                 STAGE_POSITION_TOP_OR_LEFT, callback, freezeTaskList,
  24.                 getSplitRatio());
  25.     }
  26. }
复制代码
  package/apps/Launcher3/quickstep/src/com/android/quickstep/views/RecentsView.java
  1. public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_TYPE>,
  2.         STATE_TYPE extends BaseState<STATE_TYPE>> extends PagedView implements Insettable,
  3.         TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,
  4.         TaskVisualsChangeListener, SplitScreenBounds.OnChangeListener {
  5.     public SplitSelectStateController getSplitPlaceholder() {
  6.         return mSplitSelectStateController;
  7.     }
  8. }
复制代码
  package/apps/Launcher3/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
  1. public class SplitSelectStateController {
  2.     public void launchTasks(Task task1, Task task2, @StagePosition int stagePosition,
  3.             Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) {
  4.         // Assume initial task is for top/left part of screen
  5.         final int[] taskIds = stagePosition == STAGE_POSITION_TOP_OR_LEFT
  6.                 ? new int[]{task1.key.id, task2.key.id}
  7.                 : new int[]{task2.key.id, task1.key.id};
  8.         if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
  9.             RemoteSplitLaunchTransitionRunner animationRunner =
  10.                     new RemoteSplitLaunchTransitionRunner(task1, task2);
  11.             mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1],
  12.                     null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, splitRatio,
  13.                     new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR,
  14.                             ActivityThread.currentActivityThread().getApplicationThread()));
  15.         } else {
  16.             RemoteSplitLaunchAnimationRunner animationRunner =
  17.                     new RemoteSplitLaunchAnimationRunner(task1, task2, callback);
  18.             //转场动画
  19.             final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
  20.                     RemoteAnimationAdapterCompat.wrapRemoteAnimationRunner(animationRunner),
  21.                     300, 150,
  22.                     ActivityThread.currentActivityThread().getApplicationThread());
  23.             ActivityOptions mainOpts = ActivityOptions.makeBasic();
  24.             if (freezeTaskList) {
  25.                 mainOpts.setFreezeRecentTasksReordering();
  26.             }
  27.             //调用SystemUiProxy的startTasksWithLegacyTransition方法
  28.             mSystemUiProxy.startTasksWithLegacyTransition(taskIds[0], mainOpts.toBundle(),
  29.                     taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
  30.                     splitRatio, adapter);
  31.         }
  32.     }
  33. }
复制代码
  packages/apps/Launcher3/quickstep/src/com/android/quickstep/SystemUiProxy.java
  1. public class SystemUiProxy implements ISystemUiProxy,
  2.         SysUINavigationMode.NavigationModeChangeListener {
  3.       
  4.     public static final MainThreadInitializedObject<SystemUiProxy> INSTANCE =new MainThreadInitializedObject<>(SystemUiProxy::new);
  5.    
  6.     private ISplitScreen mSplitScreen;
  7.    
  8.     public void setProxy(ISystemUiProxy proxy, IPip pip, ISplitScreen splitScreen,
  9.             IOneHanded oneHanded, IShellTransitions shellTransitions,
  10.             IStartingWindow startingWindow, IRecentTasks recentTasks,
  11.             ISmartspaceTransitionController smartSpaceTransitionController) {
  12.         ...代码省略...
  13.         mSplitScreen = splitScreen;
  14.         ...代码省略...
  15.     }
  16.     /**
  17.      * 分屏模式同时打开多个任务
  18.      */
  19.     public void startTasksWithLegacyTransition(int mainTaskId, Bundle mainOptions, int sideTaskId,
  20.             Bundle sideOptions, @SplitConfigurationOptions.StagePosition int sidePosition,
  21.             float splitRatio, RemoteAnimationAdapter adapter) {
  22.         if (mSystemUiProxy != null) {
  23.             try {
  24.                  //调用ISplitScreen的startTasksWithLegacyTransition方法触发分屏
  25.                 mSplitScreen.startTasksWithLegacyTransition(mainTaskId, mainOptions, sideTaskId,
  26.                         sideOptions, sidePosition, splitRatio, adapter);
  27.             } catch (RemoteException e) {
  28.                 Log.w(TAG, "Failed call startTasksWithLegacyTransition");
  29.             }
  30.         }
  31.     }
  32.         
  33. }
复制代码
通过梳理以上代码,可以发现Launche3终极是通过调用SystemUiProxy的startTasksWithLegacyTransition方法触发分屏的,而该方法内部又进一步调用了范例为ISplitScreen的mSplitScreen对象的startTasksWithLegacyTransition方法。
3、SystemUiProxy的内部属性对象mSplitScreen最初是在TouchInteractionService的内部类TISBinder的onInitialize方法中被赋值的。
   packages/apps/Launcher3/quickstep/src/com/android/quickstep/TouchInteractionService.java
  1. public class TouchInteractionService extends Service
  2.         implements ProtoTraceable<LauncherTraceProto.Builder> {
  3.   
  4.     private final TISBinder mTISBinder = new TISBinder();
  5.             
  6.     public class TISBinder extends IOverviewProxy.Stub {
  7.         @BinderThread
  8.         public void onInitialize(Bundle bundle) {
  9.             ISystemUiProxy proxy = ISystemUiProxy.Stub.asInterface(
  10.                     bundle.getBinder(KEY_EXTRA_SYSUI_PROXY));
  11.             IPip pip = IPip.Stub.asInterface(bundle.getBinder(KEY_EXTRA_SHELL_PIP));
  12.             //触发分屏就是调用的这个对象的方法
  13.             ISplitScreen splitscreen = ISplitScreen.Stub.asInterface(bundle.getBinder(
  14.                     KEY_EXTRA_SHELL_SPLIT_SCREEN));
  15.             IOneHanded onehanded = IOneHanded.Stub.asInterface(
  16.                     bundle.getBinder(KEY_EXTRA_SHELL_ONE_HANDED));
  17.             IShellTransitions shellTransitions = IShellTransitions.Stub.asInterface(
  18.                     bundle.getBinder(KEY_EXTRA_SHELL_SHELL_TRANSITIONS));
  19.             IStartingWindow startingWindow = IStartingWindow.Stub.asInterface(
  20.                     bundle.getBinder(KEY_EXTRA_SHELL_STARTING_WINDOW));
  21.             ISmartspaceTransitionController smartspaceTransitionController =
  22.                     ISmartspaceTransitionController.Stub.asInterface(
  23.                             bundle.getBinder(KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER));
  24.             IRecentTasks recentTasks = IRecentTasks.Stub.asInterface(
  25.                     bundle.getBinder(KEY_EXTRA_RECENT_TASKS));
  26.             MAIN_EXECUTOR.execute(() -> {
  27.                     //调用SystemUiProxy的setProxy方法
  28.                 SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy, pip,
  29.                         splitscreen, onehanded, shellTransitions, startingWindow, recentTasks,
  30.                         smartspaceTransitionController);
  31.                 TouchInteractionService.this.initInputMonitor();
  32.                 preloadOverview(true /* fromInit */);
  33.             });
  34.             sIsInitialized = true;
  35.         }
  36.      }
  37.      
  38.      @Override
  39.     public IBinder onBind(Intent intent) {
  40.         Log.d(TAG, "Touch service connected: user=" + getUserId());
  41.         return mTISBinder;
  42.     }
  43. }      
复制代码
  packages/apps/Launcher3/quickstep/AndroidManifest.xml
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3.      xmlns:tools="http://schemas.android.com/tools"
  4.      package="com.android.launcher3">
  5.    
  6.     <application android:backupAgent="com.android.launcher3.LauncherBackupAgent">
  7.         <service android:name="com.android.quickstep.TouchInteractionService"
  8.              android:permission="android.permission.STATUS_BAR_SERVICE"
  9.              android:directBootAware="true"
  10.              android:exported="true">
  11.             <intent-filter>
  12.                 <action android:name="android.intent.action.QUICKSTEP_SERVICE"/>
  13.             </intent-filter>
  14.         </service>
  15.         
  16.     </application>
  17. </manifest>
复制代码
TouchInteractionService是Launcher的一个服务,内部类TISBinder就是其他模块绑定TouchInteractionService服务时间所返回的IBinder范例的实例对象。
二、SystemUI触发分屏

1、默认情况下,SystemUI模块对Launcher3模块的TouchInteractionService服务举行了绑定。
   frameworks/base/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
  1. public class OverviewProxyService extends CurrentUserTracker implements
  2.         CallbackController<OverviewProxyListener>, NavigationModeController.ModeChangedListener,
  3.         Dumpable {
  4.    
  5.         private final Optional<SplitScreen> mSplitScreenOptional;//触发分屏模式的关键对象
  6.         //唤起Launcher3模块TouchInteractionService的Action
  7.         private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
  8.         //唤起Launcher3模块TouchInteractionService的Intent
  9.         private final Intent mQuickStepIntent;
  10.         //远程IPC通信是实现类
  11.         private IOverviewProxy mOverviewProxy;
  12.         private boolean mBound;
  13.         
  14.         public OverviewProxyService(Context context, CommandQueue commandQueue,
  15.                                     Lazy<NavigationBarController> navBarControllerLazy,
  16.                                     Lazy<Optional<StatusBar>> statusBarOptionalLazy,
  17.                                     NavigationModeController navModeController,
  18.                                     NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
  19.                                     Optional<Pip> pipOptional,
  20.                                     Optional<LegacySplitScreen> legacySplitScreenOptional,
  21.                                     Optional<SplitScreen> splitScreenOptional,
  22.                                     Optional<OneHanded> oneHandedOptional,
  23.                                     Optional<RecentTasks> recentTasks,
  24.                                     Optional<StartingSurface> startingSurface,
  25.                                     BroadcastDispatcher broadcastDispatcher,
  26.                                     ShellTransitions shellTransitions,
  27.                                     ScreenLifecycle screenLifecycle,
  28.                                     SmartspaceTransitionController smartspaceTransitionController,
  29.                                     UiEventLogger uiEventLogger,
  30.                                     DumpManager dumpManager) {
  31.             super(broadcastDispatcher);
  32.             ...代码省略...
  33.             //获取最近应用列表组件名称,其实就是Launcher3的包名
  34.             mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
  35.                     com.android.internal.R.string.config_recentsComponentName));
  36.             //创建最近应用列表Activity的意图对象
  37.             mQuickStepIntent = new Intent(ACTION_QUICKSTEP).setPackage(mRecentsComponentName.getPackageName());
  38.             ...代码省略...
  39.             startConnectionToCurrentUser();
  40.             ...代码省略...
  41.         }
  42.         
  43.         //成功绑定服务所返回的ServiceConnection对象
  44.         private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
  45.             @Override
  46.             public void onServiceConnected(ComponentName name, IBinder service) {
  47.                            ...代码省略...
  48.                     mCurrentBoundedUserId = getCurrentUserId();
  49.                     //为mOverviewProxy赋值
  50.                     mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
  51.        
  52.                     Bundle params = new Bundle();
  53.                     params.putBinder(KEY_EXTRA_SYSUI_PROXY, mSysUiProxy.asBinder());
  54.                     params.putFloat(KEY_EXTRA_WINDOW_CORNER_RADIUS, mWindowCornerRadius);
  55.                     params.putBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, mSupportsRoundedCornersOnWindows);
  56.        
  57.                     mPipOptional.ifPresent((pip) -> params.putBinder(
  58.                             KEY_EXTRA_SHELL_PIP,
  59.                             pip.createExternalInterface().asBinder()));
  60.                     //关键对象,Optional对象的的ifPresent方法会判断该对象内部的SplitScreen实例对象是否为空,
  61.                     //不为空则执行回调方法,也就是把splitscreen对象实例存放到params里面。
  62.                     mSplitScreenOptional.ifPresent((splitscreen) -> params.putBinder(
  63.                             KEY_EXTRA_SHELL_SPLIT_SCREEN,
  64.                             splitscreen.createExternalInterface().asBinder()));
  65.                     mOneHandedOptional.ifPresent((onehanded) -> params.putBinder(
  66.                             KEY_EXTRA_SHELL_ONE_HANDED,
  67.                             onehanded.createExternalInterface().asBinder()));
  68.                     params.putBinder(KEY_EXTRA_SHELL_SHELL_TRANSITIONS,
  69.                             mShellTransitions.createExternalInterface().asBinder());
  70.                     mStartingSurface.ifPresent((startingwindow) -> params.putBinder(
  71.                             KEY_EXTRA_SHELL_STARTING_WINDOW,
  72.                             startingwindow.createExternalInterface().asBinder()));
  73.                     params.putBinder(
  74.                             KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER,
  75.                             mSmartspaceTransitionController.createExternalInterface().asBinder());
  76.                     mRecentTasks.ifPresent(recentTasks -> params.putBinder(
  77.                             KEY_EXTRA_RECENT_TASKS,
  78.                             recentTasks.createExternalInterface().asBinder()));
  79.        
  80.                     try {
  81.                             //调用mOverviewProxy的onInitialize,为相关参数进行服务
  82.                         mOverviewProxy.onInitialize(params);
  83.                     } catch (RemoteException e) {
  84.                         mCurrentBoundedUserId = -1;
  85.                         Log.e(TAG_OPS, "ServiceConnection Failed to call onInitialize()", e);
  86.                     }
  87.                     dispatchNavButtonBounds();
  88.                     // Force-update the systemui state flags
  89.                     updateSystemUiStateFlags();
  90.                     notifySystemUiStateFlags(mSysUiState.getFlags());
  91.        
  92.                     notifyConnectionChanged();
  93.             }
  94.             
  95.         };
  96.    
  97.             public void startConnectionToCurrentUser() {
  98.                 if (mHandler.getLooper() != Looper.myLooper()) {
  99.                     mHandler.post(mConnectionRunnable);
  100.                 } else {
  101.                     internalConnectToCurrentUser();
  102.                 }
  103.             }
  104.         private void internalConnectToCurrentUser() {
  105.             ...代码省略...      
  106.             Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
  107.                     .setPackage(mRecentsComponentName.getPackageName());
  108.             try {
  109.                 //绑定服务
  110.                 mBound = mContext.bindServiceAsUser(launcherServiceIntent,
  111.                         mOverviewServiceConnection,
  112.                         Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
  113.                         UserHandle.of(getCurrentUserId()));
  114.             } catch (SecurityException e) {
  115.                 Log.e(TAG_OPS, "Unable to bind because of security error", e);
  116.             }
  117.             ...代码省略...
  118.         }
  119.    
  120.         public IOverviewProxy getProxy() {
  121.             return mOverviewProxy;
  122.         }        
  123.                            
  124.     }
复制代码
SystemUI模块的OverviewProxyService类的构造方法会对Launche3模块的TouchInteractionService服务举行绑定,并把调用该服务返回的Binder对象的onInitialize,将Launcher3模块必要的相干参数传了过去,这样Launch3模块才能拿到ISplitScreen的实例对象,通过调用该实例对象的startTasksWithLegacyTransition方法,终极触发分屏模式。那么问题有来了,OverviewProxyService内里的ISplitScreen对象实例是如何被赋值的?
2、重新再来看下OverviewProxyService的构造方法,这次我们重点关注一下mSplitScreenOptional这个对象。
  1. public class OverviewProxyService extends CurrentUserTracker implements
  2.         CallbackController<OverviewProxyListener>, NavigationModeController.ModeChangedListener,
  3.         Dumpable {
  4.    
  5.     private final Optional<SplitScreen> mSplitScreenOptional;//触发分屏模式的关键对象
  6.    
  7.     @Inject//Dagger2框架注解
  8.     public OverviewProxyService(Context context, CommandQueue commandQueue,
  9.             Lazy<NavigationBarController> navBarControllerLazy,
  10.             Lazy<Optional<StatusBar>> statusBarOptionalLazy,
  11.             NavigationModeController navModeController,
  12.             NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
  13.             Optional<Pip> pipOptional,
  14.             Optional<LegacySplitScreen> legacySplitScreenOptional,
  15.             Optional<SplitScreen> splitScreenOptional,
  16.             Optional<OneHanded> oneHandedOptional,
  17.             Optional<RecentTasks> recentTasks,
  18.             Optional<StartingSurface> startingSurface,
  19.             BroadcastDispatcher broadcastDispatcher,
  20.             ShellTransitions shellTransitions,
  21.             ScreenLifecycle screenLifecycle,
  22.             SmartspaceTransitionController smartspaceTransitionController,
  23.             UiEventLogger uiEventLogger,
  24.             DumpManager dumpManager) {
  25.         super(broadcastDispatcher);
  26.         ...代码省略...
  27.         mSplitScreenOptional = splitScreenOptional;//为mSplitScreenOptional赋值
  28.         ...代码省略...
  29.     }
  30.     private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
  31.             @Override
  32.             public void onServiceConnected(ComponentName name, IBinder service) {
  33.                            ...代码省略...
  34.                     mSplitScreenOptional.ifPresent((splitscreen) -> params.putBinder(
  35.                             KEY_EXTRA_SHELL_SPLIT_SCREEN,
  36.                             //这里调用splitscreen的createExternalInterface方法
  37.                             splitscreen.createExternalInterface().asBinder()));
  38.                   ...代码省略...
  39.                     }
  40.             }
  41. }
复制代码
OverviewProxyService的构造方法有一个关键注解 @Inject,这个注解是Dagger2的框架注解,该框架会根据我们的配置,当我们必要在某个对象的构造方法中传入特定参数对象的时间,只要添加@Inject注解,该框架会自动帮我们创建参数对象并传入。关于这个框架的原理,我在Android 12系统源码_SystemUI(一)SystemUI的启动流程这篇博客具体分析过,这里不做过多解释。
3、由于后续会多次提到Optional这种范例的数据范例,这里我们必要先简朴看下这个类的相干代码。
  1. public final class Optional<T> {
  2.     private static final Optional<?> EMPTY = new Optional<>();
  3.         //内部包含的真正对象
  4.     private final T value;
  5.    
  6.     private Optional(T value) {
  7.         this.value = Objects.requireNonNull(value);
  8.     }
  9.    
  10.     //如果内部对象不为空,则执行consumer方法
  11.     public void ifPresent(Consumer<? super T> consumer) {
  12.         if (value != null)
  13.             consumer.accept(value);
  14.     }
  15.         //如果内部对象为空,则返回空对象,执行mapper方法,并将该方法返回的对象封装成Optional<T>类型返回。
  16.     public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
  17.         Objects.requireNonNull(mapper);
  18.         if (!isPresent())
  19.             return empty();
  20.         else {
  21.             return Optional.ofNullable(mapper.apply(value));
  22.         }
  23.     }
  24. }
复制代码
4、关于Optional这个对象的dagger2框架的配置信息,SystemUI配置在WMComponent这个接口内里的。
   frameworks/base/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
  1. import com.android.wm.shell.dagger.WMShellModule;
  2. @WMSingleton//单例
  3. @Subcomponent(modules = {WMShellModule.class})//需要进一步结合WMShellModule做分析
  4. public interface WMComponent {
  5.     /**
  6.      * Initializes all the WMShell components before starting any of the SystemUI components.
  7.      * 在初始化SystemUI组件之前,优先初始化WMShell模块的所有组件
  8.      */
  9.     default void init() {
  10.             //调用ShellInit的init,这个方法需要额外关注一下,后续我们会再次提到
  11.         getShellInit().init();
  12.     }
  13.         //获取ShellInit对象实例
  14.     @WMSingleton
  15.     ShellInit getShellInit();
  16.         //获取Optional<SplitScreen>对象实例
  17.     @WMSingleton
  18.     Optional<SplitScreen> getSplitScreen();
  19. }
复制代码


  • 有了以上配置信息,SystemUI模块的任何类的构造方法只要加上 @Inject注解,我们就可以在该对象的构造方法中拿到WMComponent 中返回的对象实例了。
  • 联合getShellInit方法和init方法我们可以知道,SystemUI模块在初始化该模块的SystemUI组件之前,会先初始化WMShell模块的组件,这就意味着SystemUI模块的组件都能拿到WMShell模块的组件,并调用对应的组件所提供的功能。
  • 而Optional到底是如何被创建出来的,这就必要我们进一步查看WMComponent的类注解@Subcomponent指向的WMShellModule这个类的相干代码了。
三、WMShell模块触发分屏

1、SystemUI模块终极是通过WindowManager模块下的Shell模块触发分屏功能的,来看下前面SystemUI模块中dagger2注解框架引用到的WMShellModule这个类。
   frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
  1. import com.android.wm.shell.splitscreen.SplitScreenController;
  2. @Module(includes = WMShellBaseModule.class)//需要进一步结合WMShellBaseModule做分析
  3. public class WMShellModule {
  4.     @WMSingleton
  5.     @Provides
  6.     @DynamicOverride
  7.     static SplitScreenController provideSplitScreenController(
  8.             ShellTaskOrganizer shellTaskOrganizer,
  9.             SyncTransactionQueue syncQueue, Context context,
  10.             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
  11.             @ShellMainThread ShellExecutor mainExecutor,
  12.             DisplayImeController displayImeController,
  13.             DisplayInsetsController displayInsetsController, Transitions transitions,
  14.             TransactionPool transactionPool, IconProvider iconProvider,
  15.             Optional<RecentTasksController> recentTasks,
  16.             Provider<Optional<StageTaskUnfoldController>> stageTaskUnfoldControllerProvider) {
  17.         //创建SplitScreenController对象实例
  18.         return new SplitScreenController(shellTaskOrganizer, syncQueue, context,
  19.                 rootTaskDisplayAreaOrganizer, mainExecutor, displayImeController,
  20.                 displayInsetsController, transitions, transactionPool, iconProvider,
  21.                 recentTasks, stageTaskUnfoldControllerProvider);
  22.     }
  23.    
  24.     //这个方法我们需要关注一下,后面会提到
  25.     @WMSingleton
  26.     @Provides
  27.     static ShellInit provideShellInit(ShellInitImpl impl) {
  28.             //调用ShellInitImpl的asShellInit方法返回ShellInit对象实例
  29.         return impl.asShellInit();
  30.     }
  31.     @WMSingleton
  32.     @Provides
  33.     static ShellInitImpl provideShellInitImpl(DisplayController displayController,
  34.             DisplayImeController displayImeController,
  35.             DisplayInsetsController displayInsetsController,
  36.             DragAndDropController dragAndDropController,
  37.             ShellTaskOrganizer shellTaskOrganizer,
  38.             Optional<BubbleController> bubblesOptional,
  39.             Optional<SplitScreenController> splitScreenOptional,
  40.             Optional<AppPairsController> appPairsOptional,
  41.             Optional<PipTouchHandler> pipTouchHandlerOptional,
  42.             FullscreenTaskListener fullscreenTaskListener,
  43.             Optional<FullscreenUnfoldController> appUnfoldTransitionController,
  44.             Optional<FreeformTaskListener> freeformTaskListener,
  45.             Optional<RecentTasksController> recentTasksOptional,
  46.             Transitions transitions,
  47.             StartingWindowController startingWindow,
  48.             @ShellMainThread ShellExecutor mainExecutor) {
  49.         //创建ShellInitImpl的对象实例
  50.         return new ShellInitImpl(displayController,
  51.                 displayImeController,
  52.                 displayInsetsController,
  53.                 dragAndDropController,
  54.                 shellTaskOrganizer,
  55.                 bubblesOptional,
  56.                 splitScreenOptional,
  57.                 appPairsOptional,
  58.                 pipTouchHandlerOptional,
  59.                 fullscreenTaskListener,
  60.                 appUnfoldTransitionController,
  61.                 freeformTaskListener,
  62.                 recentTasksOptional,
  63.                 transitions,
  64.                 startingWindow,
  65.                 mainExecutor);
  66.     }
  67. }
复制代码
由于WMShellModule的类注解有依赖@Module(includes = WMShellBaseModule.class),要想完全搞明确Optional对象实例是如何被创建的,我们必要进一步联合WMShellBaseModule做分析。
2、WMShellBaseModule的关键代码如下所示。
   frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
  1. @Module(includes = WMShellConcurrencyModule.class)
  2. public abstract class WMShellBaseModule {
  3.     @WMSingleton
  4.     @Provides
  5.     static Optional<SplitScreen> provideSplitScreen(
  6.             Optional<SplitScreenController> splitScreenController) {
  7.             //结合前面Optional<T>这个类的代码可以知道,调用splitScreenController对象的asSplitScreen方法,并将该方法返回的SplitScreen对                        象实例封装成Optional<SplitScreen>类型的对象再返回。
  8.         return splitScreenController.map((controller) -> controller.asSplitScreen());
  9.     }
  10.     @WMSingleton
  11.     @Provides
  12.     static Optional<SplitScreenController> providesSplitScreenController(
  13.             @DynamicOverride Optional<SplitScreenController> splitscreenController,
  14.             Context context) {
  15.          //AMS是否支持多窗口模式,支持才返回SplitScreenController对象实例,否则返回空
  16.         if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) {
  17.             return splitscreenController;
  18.         }
  19.         return Optional.empty();
  20.     }
  21. }
复制代码


  • WMShellBaseModule的provideSplitScreen方法先是获取SplitScreenController对象实例,该对象是通过WMShellModule的provideSplitScreenController方法创建,但是会经过providesSplitScreenController做一层封装,只有当系统开启了支持多窗口模式的开关,也就是AMS支持多窗口模式的时间,才能拿到该对象实例,否则拿到的都是空
  • provideSplitScreen方法在得到该对象实例后,通过调用该对象的asSplitScreen方法,得到了SplitScreen对象实例,但是终极返回的是封装成Optional范例的对象实例返回的。
    到这里我们终于可以确定是SplitScreenController的asSplitScreen方法创建了SplitScreen对象实例。
3、接下来我们继续来梳理一下ISplitScreen和SplitScreenController类相干的代码。
   frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
  1. interface ISplitScreen {
  2.     oneway void registerSplitScreenListener(in ISplitScreenListener listener) = 1;
  3.    
  4.     oneway void unregisterSplitScreenListener(in ISplitScreenListener listener) = 2;
  5.     oneway void setSideStageVisibility(boolean visible) = 3;
  6.     oneway void removeFromSideStage(int taskId) = 4;
  7.     oneway void exitSplitScreen(int toTopTaskId) = 5;
  8.     oneway void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) = 6;
  9.    
  10.     oneway void startTask(int taskId, int position, in Bundle options) = 7;
  11.    
  12.     oneway void startShortcut(String packageName, String shortcutId, int position,
  13.             in Bundle options, in UserHandle user) = 8;
  14.     oneway void startIntent(in PendingIntent intent, in Intent fillInIntent, int position,
  15.             in Bundle options) = 9;
  16.             
  17.     oneway void startTasks(int mainTaskId, in Bundle mainOptions, int sideTaskId,
  18.             in Bundle sideOptions, int sidePosition, float splitRatio,
  19.             in RemoteTransition remoteTransition) = 10;
  20.             
  21.      oneway void startTasksWithLegacyTransition(int mainTaskId, in Bundle mainOptions,
  22.                             int sideTaskId, in Bundle sideOptions, int sidePosition,
  23.                             float splitRatio, in RemoteAnimationAdapter adapter) = 11;
  24. }
复制代码
  frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
  1. public class SplitScreenController implements DragAndDropPolicy.Starter, RemoteCallable<SplitScreenController> {
  2.         private final SplitScreenImpl mImpl = new SplitScreenImpl();
  3.    
  4.     private StageCoordinator mStageCoordinator;
  5.    
  6.         public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer,
  7.             SyncTransactionQueue syncQueue, Context context,
  8.             RootTaskDisplayAreaOrganizer rootTDAOrganizer,
  9.             ShellExecutor mainExecutor, DisplayImeController displayImeController,
  10.             DisplayInsetsController displayInsetsController,
  11.             Transitions transitions, TransactionPool transactionPool, IconProvider iconProvider,
  12.             Optional<RecentTasksController> recentTasks,
  13.             Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) {
  14.                 ...代码省略...
  15.     }
  16.    
  17.     public SplitScreen asSplitScreen() {
  18.         return mImpl;
  19.     }
  20.        
  21.         //这个方法最初是被ShellInitImpl调用的
  22.     public void onOrganizerRegistered() {
  23.         if (mStageCoordinator == null) {
  24.             //创建触发分屏功能的重要对象StageCoordinator的实例。
  25.             mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
  26.                     mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController,
  27.                     mDisplayInsetsController, mTransitions, mTransactionPool, mLogger,
  28.                     mIconProvider, mRecentTasksOptional, mUnfoldControllerProvider);
  29.         }
  30.     }   
  31.     //SplitScreen是一个接口,具体实现是内部类SplitScreenImpl
  32.     @ExternalThread
  33.     private class SplitScreenImpl implements SplitScreen {
  34.         private ISplitScreenImpl mISplitScreen;
  35.         private final ArrayMap<SplitScreenListener, Executor> mExecutors = new ArrayMap<>();
  36.         private final SplitScreen.SplitScreenListener mListener = new SplitScreenListener() {
  37.       
  38.             @Override
  39.             public void onStagePositionChanged(int stage, int position) {
  40.                               ...代码省略...
  41.             }
  42.             @Override
  43.             public void onTaskStageChanged(int taskId, int stage, boolean visible) {
  44.                               ...代码省略...
  45.             }
  46.             @Override
  47.             public void onSplitVisibilityChanged(boolean visible) {
  48.                               ...代码省略...
  49.             }
  50.         };
  51.         @Override
  52.         public ISplitScreen createExternalInterface() {
  53.             if (mISplitScreen != null) {
  54.                 mISplitScreen.invalidate();
  55.             }
  56.             mISplitScreen = new ISplitScreenImpl(SplitScreenController.this);
  57.                    //返回实现了ISplitScreen接口的对象实例
  58.             return mISplitScreen;
  59.         }
  60.     }
  61.         //ISplitScreen是一个aidl,内部类ISplitScreenImpl实现了ISplitScreen的接口方法。
  62.     @BinderThread
  63.     private static class ISplitScreenImpl extends ISplitScreen.Stub {
  64.         private SplitScreenController mController;
  65.         private final SingleInstanceRemoteListener<SplitScreenController,
  66.                 ISplitScreenListener> mListener;
  67.         private final SplitScreen.SplitScreenListener mSplitScreenListener =
  68.                 new SplitScreen.SplitScreenListener() {
  69.                     @Override
  70.                     public void onStagePositionChanged(int stage, int position) {
  71.                         mListener.call(l -> l.onStagePositionChanged(stage, position));
  72.                     }
  73.                     @Override
  74.                     public void onTaskStageChanged(int taskId, int stage, boolean visible) {
  75.                         mListener.call(l -> l.onTaskStageChanged(taskId, stage, visible));
  76.                     }
  77.                 };
  78.         public ISplitScreenImpl(SplitScreenController controller) {
  79.             mController = controller;
  80.             mListener = new SingleInstanceRemoteListener<>(controller,
  81.                     c -> c.registerSplitScreenListener(mSplitScreenListener),
  82.                     c -> c.unregisterSplitScreenListener(mSplitScreenListener));
  83.         }
  84.         void invalidate() {
  85.             mController = null;
  86.         }
  87.         @Override
  88.         public void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions,
  89.                 int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
  90.                 float splitRatio, RemoteAnimationAdapter adapter) {
  91.             //这里显示进行权限确认,然后会调用StageCoordinator的startTasksWithLegacyTransition方法。
  92.             executeRemoteCallWithTaskPermission(mController, "startTasks",
  93.                     (controller) -> controller.mStageCoordinator.startTasksWithLegacyTransition(
  94.                             mainTaskId, mainOptions, sideTaskId, sideOptions, sidePosition,
  95.                             splitRatio, adapter));
  96.         }
  97.     }
  98. }
复制代码


  • SplitScreenController的asSplitScreen方法返回了该类的一个内部对象SplitScreenImpl,SplitScreenImpl实现了SplitScreen这个接口的相干方法。
  • 前面第二节第1步OverviewProxyService类中我们有提到,SystemUI在成功绑定Launcher3模块的TouchInteractionService服务的时间,调用了SplitScreen 的createExternalInterface方法,联合这里我们可以知道此方法返回ISplitScreenImpl对象实例,此对象实现了ISplitScreen.aidl文件中声明的接口方法,Launcher3终极得以跨进程调用ISplitScreenImpl的startTasksWithLegacyTransition方法,终极触发分屏模式。
  • ISplitScreenImpl的startTasksWithLegacyTransition方法内部先是做了个权限判断,终极是调用了SplitScreenController的范例为StageCoordinator的内部对象mStageCoordinator的startTasksWithLegacyTransition方法。
  • SplitScreenController的内部属性对象mStageCoordinator是在onOrganizerRegistered方法中被赋值的,该方法最初是被ShellInitImpl对象触发的。
4、来看下ShellInitImpl的相干代码。
   frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
  1. public class ShellInitImpl {
  2.     private static final String TAG = ShellInitImpl.class.getSimpleName();
  3.     private final Optional<SplitScreenController> mSplitScreenOptional;
  4.     private final InitImpl mImpl = new InitImpl();
  5.     public ShellInitImpl(
  6.             DisplayController displayController,
  7.             DisplayImeController displayImeController,
  8.             DisplayInsetsController displayInsetsController,
  9.             DragAndDropController dragAndDropController,
  10.             ShellTaskOrganizer shellTaskOrganizer,
  11.             Optional<BubbleController> bubblesOptional,
  12.             Optional<SplitScreenController> splitScreenOptional,
  13.             Optional<AppPairsController> appPairsOptional,
  14.             Optional<PipTouchHandler> pipTouchHandlerOptional,
  15.             FullscreenTaskListener fullscreenTaskListener,
  16.             Optional<FullscreenUnfoldController> fullscreenUnfoldTransitionController,
  17.             Optional<FreeformTaskListener> freeformTaskListenerOptional,
  18.             Optional<RecentTasksController> recentTasks,
  19.             Transitions transitions,
  20.             StartingWindowController startingWindow,
  21.             ShellExecutor mainExecutor) {
  22.                 ...代码省略...
  23.         mSplitScreenOptional = splitScreenOptional;
  24.                 ...代码省略...
  25.     }
  26.     public ShellInit asShellInit() {
  27.         return mImpl;
  28.     }
  29.     private void init() {
  30.                 ...代码省略...
  31.         mSplitScreenOptional.ifPresent(SplitScreenController::onOrganizerRegistered);
  32.                 ...代码省略...
  33.     }
  34.     @ExternalThread
  35.     private class InitImpl implements ShellInit {
  36.         @Override
  37.         public void init() {
  38.             try {
  39.                     //进一步调用ShellInitImpl的Init方法。
  40.                 mMainExecutor.executeBlocking(() -> ShellInitImpl.this.init());
  41.             } catch (InterruptedException e) {
  42.                 throw new RuntimeException("Failed to initialize the Shell in 2s", e);
  43.             }
  44.         }
  45.     }
  46. }
复制代码
四、SystemUI模块初始化分屏组件

1、前面第三节第1步WMShellModule类中,我们有提到过和ShellInitImpl对象创建有关的代码。
  1. import com.android.wm.shell.splitscreen.SplitScreenController;
  2. @Module(includes = WMShellBaseModule.class)
  3. public class WMShellModule {
  4.    
  5.     @WMSingleton
  6.     @Provides
  7.     static ShellInit provideShellInit(ShellInitImpl impl) {
  8.             //调用ShellInitImpl的asShellInit方法返回ShellInit对象实例
  9.         return impl.asShellInit();
  10.     }
  11.    
  12.     @WMSingleton
  13.     @Provides
  14.     static ShellInitImpl provideShellInitImpl(DisplayController displayController,
  15.             DisplayImeController displayImeController,
  16.             DisplayInsetsController displayInsetsController,
  17.             DragAndDropController dragAndDropController,
  18.             ShellTaskOrganizer shellTaskOrganizer,
  19.             Optional<BubbleController> bubblesOptional,
  20.             Optional<SplitScreenController> splitScreenOptional,
  21.             Optional<AppPairsController> appPairsOptional,
  22.             Optional<PipTouchHandler> pipTouchHandlerOptional,
  23.             FullscreenTaskListener fullscreenTaskListener,
  24.             Optional<FullscreenUnfoldController> appUnfoldTransitionController,
  25.             Optional<FreeformTaskListener> freeformTaskListener,
  26.             Optional<RecentTasksController> recentTasksOptional,
  27.             Transitions transitions,
  28.             StartingWindowController startingWindow,
  29.             @ShellMainThread ShellExecutor mainExecutor) {
  30.         //创建ShellInitImpl的对象实例
  31.         return new ShellInitImpl(displayController,
  32.                 displayImeController,
  33.                 displayInsetsController,
  34.                 dragAndDropController,
  35.                 shellTaskOrganizer,
  36.                 bubblesOptional,
  37.                 splitScreenOptional,
  38.                 appPairsOptional,
  39.                 pipTouchHandlerOptional,
  40.                 fullscreenTaskListener,
  41.                 appUnfoldTransitionController,
  42.                 freeformTaskListener,
  43.                 recentTasksOptional,
  44.                 transitions,
  45.                 startingWindow,
  46.                 mainExecutor);
  47.     }
  48. }
复制代码
2、前面第二节第4步WMComponent类中,我们有提到SystemUI模块在初始化SystemUI模块的组件之前,会先初始化WMShell模块的所有组件,这自然也包罗分屏组件。
  1. @WMSingleton//单例
  2. @Subcomponent(modules = {WMShellModule.class})
  3. public interface WMComponent {
  4.     /**
  5.      * Initializes all the WMShell components before starting any of the SystemUI components.
  6.      * 在初始化SystemUI组件之前,优先初始化WMShell模块的所有组件
  7.      */
  8.     default void init() {
  9.             //调用ShellInit的init
  10.         getShellInit().init();
  11.     }
  12.         //获取ShellInit对象实例
  13.     @WMSingleton
  14.     ShellInit getShellInit();
  15. }
复制代码
WMComponent的init方法先是通过getShellInit方法获取到ShellInit对象实例,InitImpl实现了ShellInit这个接口,
并实现了init方法,该方法会进一步调用ShellInitImpl的init方法,终极会触发SplitScreenController的onOrganizerRegistered方法。
3、SplitScreenController的onOrganizerRegistered方法会创建控制分屏功能的分屏组件StageCoordinator的对象实例。
  1. public class SplitScreenController implements DragAndDropPolicy.Starter, RemoteCallable<SplitScreenController> {
  2.     private StageCoordinator mStageCoordinator;
  3.    
  4.         //这个方法最初是被ShellInitImpl调用的
  5.     public void onOrganizerRegistered() {
  6.         if (mStageCoordinator == null) {
  7.             //创建触发分屏功能的重要对象StageCoordinator的实例。
  8.             mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
  9.                     mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController,
  10.                     mDisplayInsetsController, mTransitions, mTransactionPool, mLogger,
  11.                     mIconProvider, mRecentTasksOptional, mUnfoldControllerProvider);
  12.         }
  13.     }   
  14. }
复制代码
4、StageCoordinator的构造方法如下所示。
  1. class StageCoordinator implements SplitLayout.SplitLayoutHandler,
  2.         RootTaskDisplayAreaOrganizer.RootTaskDisplayAreaListener, Transitions.TransitionHandler {
  3.     StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
  4.             RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
  5.             DisplayImeController displayImeController,
  6.             DisplayInsetsController displayInsetsController, Transitions transitions,
  7.             TransactionPool transactionPool, SplitscreenEventLogger logger,
  8.             Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) {
  9.         mContext = context;
  10.         mDisplayId = displayId;
  11.         mSyncQueue = syncQueue;
  12.         mRootTDAOrganizer = rootTDAOrganizer;
  13.         mTaskOrganizer = taskOrganizer;
  14.         mLogger = logger;
  15.         mMainUnfoldController = unfoldControllerProvider.get().orElse(null);
  16.         mSideUnfoldController = unfoldControllerProvider.get().orElse(null);
  17.                 //分屏对象
  18.         mMainStage = new MainStage(
  19.                 mTaskOrganizer,
  20.                 mDisplayId,
  21.                 mMainStageListener,
  22.                 mSyncQueue,
  23.                 mSurfaceSession,
  24.                 mMainUnfoldController);
  25.          //分屏对象
  26.         mSideStage = new SideStage(
  27.                 mContext,
  28.                 mTaskOrganizer,
  29.                 mDisplayId,
  30.                 mSideStageListener,
  31.                 mSyncQueue,
  32.                 mSurfaceSession,
  33.                 mSideUnfoldController);
  34.         mDisplayImeController = displayImeController;
  35.         mDisplayInsetsController = displayInsetsController;
  36.         mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSideStage);
  37.         mRootTDAOrganizer.registerListener(displayId, this);
  38.         final DeviceStateManager deviceStateManager =
  39.                 mContext.getSystemService(DeviceStateManager.class);
  40.         deviceStateManager.registerCallback(taskOrganizer.getExecutor(),
  41.                 new DeviceStateManager.FoldStateListener(mContext, this::onFoldedStateChanged));
  42.         mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
  43.                 mOnTransitionAnimationComplete);
  44.         transitions.addHandler(this);
  45.     }
  46. }
复制代码
由此可知,SystemUI在进程初始化阶段就已经准备好分屏所必要的 MainStage和SideStage 对象,这两个对象很紧张,分别负责分屏的一边,对象内部会创建一个 RootTask 节点了(这里利用了WindowOrganizer框架的能力),这个RootTask就是分屏的关键,通过把应用的Task节点挂载到RootTask下,然后修改RootTask节点的Bounds来改变应用显示的巨细。
五、WMShell模块触发分屏

1、前面第三步第4节我们有做过分析,Launcher3经过层层调用,终极是调用StageCoordinator的startTasksWithLegacyTransition方法触发分屏功能的,继续来看下StageCoordinator的startTasksWithLegacyTransition方法。
  1. class StageCoordinator implements SplitLayout.SplitLayoutHandler,
  2.         RootTaskDisplayAreaOrganizer.RootTaskDisplayAreaListener, Transitions.TransitionHandler {
  3.    
  4.     private final ShellTaskOrganizer mTaskOrganizer;
  5.      
  6.     StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
  7.             RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
  8.             DisplayImeController displayImeController,
  9.             DisplayInsetsController displayInsetsController, Transitions transitions,
  10.             TransactionPool transactionPool, SplitscreenEventLogger logger,
  11.             IconProvider iconProvider,
  12.             Optional<RecentTasksController> recentTasks,
  13.             Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) {
  14.         mContext = context;
  15.         mDisplayId = displayId;
  16.         mSyncQueue = syncQueue;
  17.         mRootTDAOrganizer = rootTDAOrganizer;
  18.         mTaskOrganizer = taskOrganizer;//为mTaskOrganizer赋值
  19.              ...代码省略...
  20.     }
  21.     //Launcher3其实是调用了这个方法触发分屏模式的
  22.     void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions,
  23.             int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
  24.             float splitRatio, RemoteAnimationAdapter adapter) {
  25.         // Init divider first to make divider leash for remote animation target.
  26.         setDividerVisibility(true /* visible */);//设置分屏中间的分割线View可见
  27.         // Set false to avoid record new bounds with old task still on top;
  28.         mShouldUpdateRecents = false;
  29.         final WindowContainerTransaction wct = new WindowContainerTransaction();
  30.         final WindowContainerTransaction evictWct = new WindowContainerTransaction();
  31.         prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
  32.         prepareEvictChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, evictWct);
  33.         // Need to add another wrapper here in shell so that we can inject the divider bar
  34.         // and also manage the process elevation via setRunningRemote
  35.         IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
  36.             @Override
  37.             public void onAnimationStart(@WindowManager.TransitionOldType int transit,
  38.                     RemoteAnimationTarget[] apps,
  39.                     RemoteAnimationTarget[] wallpapers,
  40.                     RemoteAnimationTarget[] nonApps,
  41.                     final IRemoteAnimationFinishedCallback finishedCallback) {
  42.                 mIsDividerRemoteAnimating = true;
  43.                 RemoteAnimationTarget[] augmentedNonApps =
  44.                         new RemoteAnimationTarget[nonApps.length + 1];
  45.                 for (int i = 0; i < nonApps.length; ++i) {
  46.                     augmentedNonApps[i] = nonApps[i];
  47.                 }
  48.                 augmentedNonApps[augmentedNonApps.length - 1] = getDividerBarLegacyTarget();
  49.                 IRemoteAnimationFinishedCallback wrapCallback =
  50.                         new IRemoteAnimationFinishedCallback.Stub() {
  51.                             @Override
  52.                             public void onAnimationFinished() throws RemoteException {
  53.                                 mIsDividerRemoteAnimating = false;
  54.                                 mShouldUpdateRecents = true;
  55.                                 mSyncQueue.queue(evictWct);
  56.                                 mSyncQueue.runInSync(t -> applyDividerVisibility(t));
  57.                                 finishedCallback.onAnimationFinished();
  58.                             }
  59.                         };
  60.                 try {
  61.                     try {
  62.                         ActivityTaskManager.getService().setRunningRemoteTransitionDelegate(
  63.                                 adapter.getCallingApplication());
  64.                     } catch (SecurityException e) {
  65.                         Slog.e(TAG, "Unable to boost animation thread. This should only happen"
  66.                                 + " during unit tests");
  67.                     }
  68.                     adapter.getRunner().onAnimationStart(transit, apps, wallpapers,
  69.                             augmentedNonApps, wrapCallback);
  70.                 } catch (RemoteException e) {
  71.                     Slog.e(TAG, "Error starting remote animation", e);
  72.                 }
  73.             }
  74.             @Override
  75.             public void onAnimationCancelled() {
  76.                 mIsDividerRemoteAnimating = false;
  77.                 mShouldUpdateRecents = true;
  78.                 mSyncQueue.queue(evictWct);
  79.                 mSyncQueue.runInSync(t -> applyDividerVisibility(t));
  80.                 try {
  81.                     adapter.getRunner().onAnimationCancelled();
  82.                 } catch (RemoteException e) {
  83.                     Slog.e(TAG, "Error starting remote animation", e);
  84.                 }
  85.             }
  86.         };
  87.         RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter(
  88.                 wrapper, adapter.getDuration(), adapter.getStatusBarTransitionDelay());
  89.         if (mainOptions == null) {
  90.             mainOptions = ActivityOptions.makeRemoteAnimation(wrappedAdapter).toBundle();
  91.         } else {
  92.             ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions);
  93.             mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));
  94.             mainOptions = mainActivityOptions.toBundle();
  95.         }
  96.         sideOptions = sideOptions != null ? sideOptions : new Bundle();
  97.         setSideStagePosition(sidePosition, wct);
  98.         mSplitLayout.setDivideRatio(splitRatio);
  99.         if (mMainStage.isActive()) {
  100.             mMainStage.moveToTop(getMainStageBounds(), wct);
  101.         } else {
  102.             // Build a request WCT that will launch both apps such that task 0 is on the main stage
  103.             // while task 1 is on the side stage.
  104.             // 设置mMainStage对应的RootTask的Bounds,并将其移动到最前面
  105.             mMainStage.activate(getMainStageBounds(), wct, false /* reparent */);
  106.         }
  107.         // 设置mSideStage对应的RootTask的Bounds,并将其移动到最前面
  108.         mSideStage.moveToTop(getSideStageBounds(), wct);
  109.         // Make sure the launch options will put tasks in the corresponding split roots
  110.         // 配置launch task的option,让分屏应用的task启动到RootTask节点之下
  111.         addActivityOptions(mainOptions, mMainStage);
  112.         addActivityOptions(sideOptions, mSideStage);
  113.         // Add task launch requests
  114.         // 启动分屏应用,启动方式和从任务管理器启动是一样的,startActivityFromRecents
  115.         wct.startTask(mainTaskId, mainOptions);
  116.         wct.startTask(sideTaskId, sideOptions);
  117.         // Using legacy transitions, so we can't use blast sync since it conflicts.
  118.         // 所有修改封装到WindowContainerTransaction中然后通过WindowOrganizer框架完成上面的变化
  119.         mTaskOrganizer.applyTransaction(wct);
  120.     }
  121. }
复制代码


  • 显示分屏中间的View
  • 设置mMainStage对应的RootTask的Bounds并移动到最前面
  • 设置mSideStage对应的RootTask的Bounds并移动到最前面
  • 启动分屏应用,让分屏应用的task启动到RootTask节点之下,启动方式和从任务管理器启动是一样的,Framework侧对应的就是startActivityFromRecents方法
2、继续来看下ShellTaskOrganizer的applyTransaction方法。
   frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
  1. public class ShellTaskOrganizer extends TaskOrganizer implements
  2.         CompatUIController.CompatUICallback {
  3. }
复制代码
  frameworks/base/core/java/android/window/TaskOrganizer.java
  1. public class TaskOrganizer extends WindowOrganizer {
  2. }
复制代码
  frameworks/base/core/java/android/window/TaskOrganizer.java
  1. public class WindowOrganizer {
  2.         //applyTransaction是ShellTaskOrganizer的父类方法
  3.     public void applyTransaction(@NonNull WindowContainerTransaction t) {
  4.         try {
  5.             if (!t.isEmpty()) {
  6.                     //调用IWindowOrganizerController的applyTransaction方法
  7.                 getWindowOrganizerController().applyTransaction(t);
  8.             }
  9.         } catch (RemoteException e) {
  10.             throw e.rethrowFromSystemServer();
  11.         }
  12.     }
  13.    
  14.     static IWindowOrganizerController getWindowOrganizerController() {
  15.         return IWindowOrganizerControllerSingleton.get();
  16.     }
  17.    
  18.     private static final Singleton<IWindowOrganizerController> IWindowOrganizerControllerSingleton =
  19.         new Singleton<IWindowOrganizerController>() {
  20.             @Override
  21.             protected IWindowOrganizerController create() {
  22.                 try {
  23.                     return ActivityTaskManager.getService().getWindowOrganizerController();
  24.                 } catch (RemoteException e) {
  25.                     return null;
  26.                 }
  27.             }
  28.         };
  29. }
复制代码
applyTransaction方法终极是其父类WindowOrganizer的方法,该方法先是获取到WindowOrganizerController的实例对象,然后调用该对象的applySyncTransaction方法。
3、IWindowOrganizerController是一个aidl,该接口的具体实现类是WindowOrganizerController。
   frameworks/base/core/java/android/window/IWindowOrganizerController.aidl
  1. interface IWindowOrganizerController {
  2.     int applySyncTransaction(in WindowContainerTransaction t,
  3.             in IWindowContainerTransactionCallback callback);
  4. }
复制代码
  frameworks/base/services/core/java/com/android/server/wm/WindowOrganizerController.java
  1. class WindowOrganizerController extends IWindowOrganizerController.Stub
  2.     implements BLASTSyncEngine.TransactionReadyListener {
  3.    
  4.      @Override
  5.     public int applySyncTransaction(WindowContainerTransaction t,
  6.             IWindowContainerTransactionCallback callback) {
  7.         if (t == null) {
  8.             throw new IllegalArgumentException("Null transaction passed to applySyncTransaction");
  9.         }
  10.         enforceTaskPermission("applySyncTransaction()");
  11.         final CallerInfo caller = new CallerInfo();
  12.         final long ident = Binder.clearCallingIdentity();
  13.         try {
  14.             synchronized (mGlobalLock) {
  15.                 int syncId = -1;
  16.                 if (callback != null) {
  17.                     syncId = startSyncWithOrganizer(callback);
  18.                 }
  19.                 applyTransaction(t, syncId, null /*transition*/, caller);
  20.                 if (syncId >= 0) {
  21.                     setSyncReady(syncId);
  22.                 }
  23.                 return syncId;
  24.             }
  25.         } finally {
  26.             Binder.restoreCallingIdentity(ident);
  27.         }
  28.     }
  29. }
复制代码
这里还是运用了WindowOrganizer框架的能力,把所有修改点封装到 WindowContainerTransaction中,然后通过mTaskOrganizer.applyTransaction(wct); 转交给Framework,Framework剖析WindowContainerTransaction,然后实行对应的厘革
我们可以看看WindowContainerTransaction的内容

   Android12上两个应用都得是从任务管理器中起 startActivityFromRecents
在Android13上支持通过wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions)新起一个应用。
  六、通过命令行触发分屏

1、除了调用WMShell模块组件提供的方法触发分屏意外,我们还可以通过命令行来触发分屏。
  1. // taskId 可以通过adb shell am stack list 来查看应用对应的taskId
  2. // SideStagePosition 0 代表左边, 1 代表右边
  3. adb shell dumpsys activity service SystemUIService WMShell moveToSideStage <taskId> <SideStagePosition>
复制代码
命令行会把taskId对应的task挂载到SideStage对应的RootTask下,然后SideStage监听到task厘革,然后就会激活MainStage,然后申请分屏操纵。
2、这部分代码如下。
   frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
  1. class StageCoordinator implements SplitLayout.SplitLayoutHandler,
  2.         RootTaskDisplayAreaOrganizer.RootTaskDisplayAreaListener, Transitions.TransitionHandler {
  3. private void onStageHasChildrenChanged(StageListenerImpl stageListener) {
  4.         final boolean hasChildren = stageListener.mHasChildren;
  5.         final boolean isSideStage = stageListener == mSideStageListener;
  6.         if (!hasChildren) {
  7.             if (isSideStage && mMainStageListener.mVisible) {
  8.                 // Exit to main stage if side stage no longer has children.
  9.                 exitSplitScreen(mMainStage, EXIT_REASON_APP_FINISHED);
  10.             } else if (!isSideStage && mSideStageListener.mVisible) {
  11.                 // Exit to side stage if main stage no longer has children.
  12.                 exitSplitScreen(mSideStage, EXIT_REASON_APP_FINISHED);
  13.             }
  14.         } else if (isSideStage) {
  15.                 //SideStage对应的RootTask监听到task变化,然后就会触发分屏操作
  16.             final WindowContainerTransaction wct = new WindowContainerTransaction();
  17.             //Make sure the main stage is active.
  18.             //这里的reparent是关键,为true后会把后台的Task作为分屏的一部分,如果没有后台task,不能触发分屏
  19.             mMainStage.activate(getMainStageBounds(), wct, true /* reparent */);
  20.             mSideStage.moveToTop(getSideStageBounds(), wct);
  21.             mSyncQueue.queue(wct);
  22.             mSyncQueue.runInSync(t -> updateSurfaceBounds(mSplitLayout, t));
  23.         }
  24.         if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) {
  25.             mShouldUpdateRecents = true;
  26.             updateRecentTasksSplitPair();
  27.             if (!mLogger.hasStartedSession()) {
  28.                 mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
  29.                         getMainStagePosition(), mMainStage.getTopChildTaskUid(),
  30.                         getSideStagePosition(), mSideStage.getTopChildTaskUid(),
  31.                         mSplitLayout.isLandscape());
  32.             }
  33.         }
  34.     }
  35. }
复制代码
这里必要注意 mMainStage.activate(getMainStageBounds(), wct, true /* reparent */ ); 这里的reparent是关键,为true后会把后台的Task作为分屏的一部分,如果没有后台task,不能触发分屏,而且命令行分屏由于缺少了Launcher3的加入,缺少分屏之前的动画,效果上就是直接硬切的。
参考文档:https://juejin.cn/post/7346977510514884619

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

泉缘泉

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表