Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2bc5bd51 authored by Evan Rosky's avatar Evan Rosky
Browse files

Add shell transition handling for staged split-screen.

This makes StageCoordinator implement the TransitionHandler
interface.

In general, this currently expects 'enter' transitions to
contain 2 tasks (one in each split). The current UX is undefined
when one only one of the splits is occupied, so for now it will
throw an exception if that case is hit.

There is a split-screen API called startTasks which takes a list
of tasks (currently only supports 2) and associated options and
creates a transition to both enter split-screen and launch those
tasks into their respective stages.

These are the currently accounted-for entrypoints into
the handler interface:

- Core-initiated (handleRequest)
  - in split: trigger=HOME that is opening -> full dismiss.
  - in split: trigger=task with a stage parent that is last closing in
                    that stage -> dismiss with other stage onTop
  - NOT split: trigger=task with stage parent -> exception
- Shell-initiated
  - NOT split: startTasks -> enter split with 2 tasks
  - in split: snap-to-dismiss -> dismiss with other stage on top

Bug: 182002789
Test: atest SplitTransitionTests
      Or use the experimental pair-launch split-screen and observe
      protologs to see clean transition-infos.
Change-Id: I4f4dd431ad5642cf98b4a01c32eb1d09e5b9a11e
parent 298bb6c1
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -921,6 +921,30 @@ public interface WindowManager extends ViewManager {
    default void setForceCrossWindowBlurDisabled(boolean disable) {
    }

    /**
     * @hide
     */
    static String transitTypeToString(@TransitionType int type) {
        switch (type) {
            case TRANSIT_NONE: return "NONE";
            case TRANSIT_OPEN: return "OPEN";
            case TRANSIT_CLOSE: return "CLOSE";
            case TRANSIT_TO_FRONT: return "TO_FRONT";
            case TRANSIT_TO_BACK: return "TO_BACK";
            case TRANSIT_RELAUNCH: return "RELAUNCH";
            case TRANSIT_CHANGE: return "CHANGE";
            case TRANSIT_KEYGUARD_GOING_AWAY: return "KEYGUARD_GOING_AWAY";
            case TRANSIT_KEYGUARD_OCCLUDE: return "KEYGUARD_OCCLUDE";
            case TRANSIT_KEYGUARD_UNOCCLUDE: return "KEYGUARD_UNOCCLUDE";
            case TRANSIT_FIRST_CUSTOM: return "FIRST_CUSTOM";
            default:
                if (type > TRANSIT_FIRST_CUSTOM) {
                    return "FIRST_CUSTOM+" + (type - TRANSIT_FIRST_CUSTOM);
                }
                return "UNKNOWN(" + type + ")";
        }
    }

    public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
        /**
         * X position for this window.  With the default gravity it is ignored.
+2 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.transitTypeToString;

import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -205,7 +206,7 @@ public final class TransitionInfo implements Parcelable {
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("{t=" + mType + " f=" + Integer.toHexString(mFlags)
        sb.append("{t=" + transitTypeToString(mType) + " f=" + Integer.toHexString(mFlags)
                + " ro=" + mRootOffset + " c=[");
        for (int i = 0; i < mChanges.size(); ++i) {
            if (i > 0) {
+8 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.os.UserHandle;
import android.window.IRemoteTransition;

import com.android.wm.shell.splitscreen.ISplitScreenListener;

@@ -74,4 +75,11 @@ interface ISplitScreen {
     */
    oneway void startIntent(in PendingIntent intent, in Intent fillInIntent, int stage,
            int position, in Bundle options) = 9;

    /**
     * Starts tasks simultaneously in one transition. The first task in the list will be in the
     * main-stage and on the left/top.
     */
    oneway void startTasks(int mainTaskId, in Bundle mainOptions, int sideTaskId,
            in Bundle sideOptions, int sidePosition, in IRemoteTransition remoteTransition) = 10;
}
+1 −3
Original line number Diff line number Diff line
@@ -16,10 +16,7 @@

package com.android.wm.shell.splitscreen;

import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;

import android.graphics.Rect;
import android.window.WindowContainerToken;
@@ -52,6 +49,7 @@ class MainStage extends StageTaskListener {

        final WindowContainerToken rootToken = mRootTaskInfo.token;
        wct.setBounds(rootToken, rootBounds)
                .setWindowingMode(rootToken, WINDOWING_MODE_MULTI_WINDOW)
                .setLaunchRoot(
                        rootToken,
                        CONTROLLED_WINDOWING_MODES,
+10 −10
Original line number Diff line number Diff line
@@ -17,18 +17,8 @@
package com.android.wm.shell.splitscreen;

import android.annotation.IntDef;
import android.app.ActivityManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.UserHandle;

import androidx.annotation.Nullable;

import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.draganddrop.DragAndDropPolicy;

/**
 * Interface to engage split-screen feature.
@@ -95,4 +85,14 @@ public interface SplitScreen {
    default ISplitScreen createExternalInterface() {
        return null;
    }

    /** Get a string representation of a stage type */
    static String stageTypeToString(@StageType int stage) {
        switch (stage) {
            case STAGE_TYPE_UNDEFINED: return "UNDEFINED";
            case STAGE_TYPE_MAIN: return "MAIN";
            case STAGE_TYPE_SIDE: return "SIDE";
            default: return "UNKNOWN(" + stage + ")";
        }
    }
}
Loading