1. 长按 Overview 按钮触发

2. 点击 “Split Screen” 触发

在 Overview 点击应用图标后出现的 Menu 是在 TaskMenuVew 中添加的。

package com.android.quickstep.views;
/**
 * Contains options for a recent task when long-pressing its icon.
 */
public class TaskMenuView extends AbstractFloatingView {
    /** Note that these will be shown in order from top to bottom, if available for the task. */
    public static final TaskSystemShortcut[] MENU_OPTIONS = new TaskSystemShortcut[] {
            new TaskSystemShortcut.AppInfo(),
            new TaskSystemShortcut.SplitScreen(),
            new TaskSystemShortcut.Pin(),
            new TaskSystemShortcut.Install(),
    };
    ...
    private void addMenuOptions(TaskView taskView) {
        ...
        for (TaskSystemShortcut menuOption : MENU_OPTIONS) {
            OnClickListener onClickListener = menuOption.getOnClickListener(mActivity, taskView);
            if (onClickListener != null) {
                // 设置点击事件
                addMenuOption(menuOption, onClickListener);
            }
        }
    }
}

SplitScreen Menu 就是 new TaskSystemShortcut.SplitScreen() 返回的。SplitScreen 类是 TaskSystemShortcut 类的内部类。getOnClickListener() 方法返回 OnClickListener 对象,当点击“Split Screen” Menu 时调用。

返回的 OnClickListener 对象中调用 AMS 的 startActivityManagerFromRecents() 方法,参数 ActivityOption 对象是调用 ActivityOptionsCompat.makeSplitScreenOptions() 创建的。

package com.android.quickstep;
/**
 * Represents a system shortcut that can be shown for a recent task.
 */
public class TaskSystemShortcut<T extends SystemShortcut> extends SystemShortcut

public static class SplitScreen extends TaskSystemShortcut {
    @Override
    public View.OnClickListener getOnClickListener(
            BaseDraggingActivity activity, TaskView taskView) {
        ...
        return (v -> {
            ...
            if (ActivityManagerWrapper.getInstance().startActivityFromRecents(taskId,
                    ActivityOptionsCompat.makeSplitScreenOptions(dockTopOrLeft) {
                ISystemUiProxy sysUiProxy = RecentsModel.getInstance(activity).getSystemUiProxy();
                try {
                    sysUiProxy.onSplitScreenInvoked();
                } catch (RemoteException e) {
                    Log.w(TAG, "Failed to notify SysUI of split screen: ", e);
                    return;
                }
                ...
}});}}

makeSplitScreenOptions() 方法返回以 SplitScreen 模式启动 task 的 ActivityOption 对象。主要是调用 setLaunchWindowingMode() 方法设置了 WindowingMode。

package com.android.systemui.shared.system;
/**
 * Wrapper around internal ActivityOptions creation.
 */
public abstract class ActivityOptionsCompat {
    /**
     * @return ActivityOptions for starting a task in split screen.
     */
    public static ActivityOptions makeSplitScreenOptions(boolean dockTopLeft) {
        final ActivityOptions options = ActivityOptions.makeBasic();
        options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
        options.setSplitScreenCreateMode(dockTopLeft
                ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
                : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT);
        return options;
}}

接下来分析用 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY 调用 startActivityFromRecents() 方法时都有什么流程,怎么启动了分屏。

3. 拖动窗口到边缘触发

3.1 边缘 View

在最近任务页面,长按 task 后边缘出现的可拖动区域是 DockState 类,内部创建了 5 个静态对象,分别对应上下左右和空。

Dock 的显示配置是在 RecentsConfiguration 中定义的。手机纵向时显示 TOP,横向时显示 LEFT。平板纵向时显示 TOP,横向时显示 LEFT 和 RIGHT。RecentsConfiguration 类中 getDockStatesForCurrentOrientation() 方法可以根据设备类型和方向返回相应的 DockState 对象。

3.2 拖动事件

3.2.1 开始拖动

拖动事件是用 EventBus 发送的,拖动开始事件是 DragStartEvent,拖动结束事件是 DragEndEvent。