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

Commit 0cc4156b authored by Nick Chameyev's avatar Nick Chameyev Committed by Android (Google) Code Review
Browse files

Merge "Add split screen unfold animation" into sc-v2-dev

parents 39615056 f96ed6b6
Loading
Loading
Loading
Loading
+7 −50
Original line number Diff line number Diff line
@@ -16,9 +16,6 @@

package com.android.wm.shell.fullscreen;

import static android.graphics.Color.blue;
import static android.graphics.Color.green;
import static android.graphics.Color.red;
import static android.util.MathUtils.lerp;
import static android.view.Display.DEFAULT_DISPLAY;

@@ -36,12 +33,11 @@ import android.view.InsetsState;
import android.view.SurfaceControl;

import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.wm.shell.R;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener;
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider;
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider.UnfoldListener;
import com.android.wm.shell.unfold.UnfoldBackgroundController;

import java.util.concurrent.Executor;

@@ -59,21 +55,17 @@ public final class FullscreenUnfoldController implements UnfoldListener,
    private static final float VERTICAL_START_MARGIN = 0.03f;
    private static final float END_SCALE = 1f;
    private static final float START_SCALE = END_SCALE - VERTICAL_START_MARGIN * 2;
    private static final int BACKGROUND_LAYER_Z_INDEX = -1;

    private final Context mContext;
    private final Executor mExecutor;
    private final ShellUnfoldProgressProvider mProgressProvider;
    private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
    private final DisplayInsetsController mDisplayInsetsController;

    private final SparseArray<AnimationContext> mAnimationContextByTaskId = new SparseArray<>();
    private final UnfoldBackgroundController mBackgroundController;

    private SurfaceControl mBackgroundLayer;
    private InsetsSource mTaskbarInsetsSource;

    private final float mWindowCornerRadiusPx;
    private final float[] mBackgroundColor;
    private final float mExpandedTaskBarHeight;

    private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
@@ -81,19 +73,17 @@ public final class FullscreenUnfoldController implements UnfoldListener,
    public FullscreenUnfoldController(
            @NonNull Context context,
            @NonNull Executor executor,
            @NonNull UnfoldBackgroundController backgroundController,
            @NonNull ShellUnfoldProgressProvider progressProvider,
            @NonNull RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
            @NonNull DisplayInsetsController displayInsetsController
    ) {
        mContext = context;
        mExecutor = executor;
        mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
        mProgressProvider = progressProvider;
        mDisplayInsetsController = displayInsetsController;
        mWindowCornerRadiusPx = ScreenDecorationsUtils.getWindowCornerRadius(context);
        mExpandedTaskBarHeight = context.getResources().getDimensionPixelSize(
                com.android.internal.R.dimen.taskbar_frame_height);
        mBackgroundColor = getBackgroundColor();
        mBackgroundController = backgroundController;
    }

    /**
@@ -108,7 +98,7 @@ public final class FullscreenUnfoldController implements UnfoldListener,
    public void onStateChangeProgress(float progress) {
        if (mAnimationContextByTaskId.size() == 0) return;

        ensureBackground();
        mBackgroundController.ensureBackground(mTransaction);

        for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) {
            final AnimationContext context = mAnimationContextByTaskId.valueAt(i);
@@ -135,7 +125,7 @@ public final class FullscreenUnfoldController implements UnfoldListener,
            resetSurface(context);
        }

        removeBackground();
        mBackgroundController.removeBackground(mTransaction);
        mTransaction.apply();
    }

@@ -178,7 +168,7 @@ public final class FullscreenUnfoldController implements UnfoldListener,
        }

        if (mAnimationContextByTaskId.size() == 0) {
            removeBackground();
            mBackgroundController.removeBackground(mTransaction);
        }

        mTransaction.apply();
@@ -194,39 +184,6 @@ public final class FullscreenUnfoldController implements UnfoldListener,
                        (float) context.mTaskInfo.positionInParent.y);
    }

    private void ensureBackground() {
        if (mBackgroundLayer != null) return;

        SurfaceControl.Builder colorLayerBuilder = new SurfaceControl.Builder()
                .setName("app-unfold-background")
                .setCallsite("AppUnfoldTransitionController")
                .setColorLayer();
        mRootTaskDisplayAreaOrganizer.attachToDisplayArea(DEFAULT_DISPLAY, colorLayerBuilder);
        mBackgroundLayer = colorLayerBuilder.build();

        mTransaction
                .setColor(mBackgroundLayer, mBackgroundColor)
                .show(mBackgroundLayer)
                .setLayer(mBackgroundLayer, BACKGROUND_LAYER_Z_INDEX);
    }

    private void removeBackground() {
        if (mBackgroundLayer == null) return;
        if (mBackgroundLayer.isValid()) {
            mTransaction.remove(mBackgroundLayer);
        }
        mBackgroundLayer = null;
    }

    private float[] getBackgroundColor() {
        int colorInt = mContext.getResources().getColor(R.color.unfold_transition_background);
        return new float[]{
                (float) red(colorInt) / 255.0F,
                (float) green(colorInt) / 255.0F,
                (float) blue(colorInt) / 255.0F
        };
    }

    private class AnimationContext {
        final SurfaceControl mLeash;
        final Rect mStartCropRect = new Rect();
+5 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.wm.shell.splitscreen;

import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;

import android.annotation.Nullable;
import android.graphics.Rect;
import android.view.SurfaceSession;
import android.window.WindowContainerToken;
@@ -38,8 +39,10 @@ class MainStage extends StageTaskListener {

    MainStage(ShellTaskOrganizer taskOrganizer, int displayId,
            StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
            SurfaceSession surfaceSession) {
        super(taskOrganizer, displayId, callbacks, syncQueue, surfaceSession);
            SurfaceSession surfaceSession,
            @Nullable StageTaskUnfoldController stageTaskUnfoldController) {
        super(taskOrganizer, displayId, callbacks, syncQueue, surfaceSession,
                stageTaskUnfoldController);
    }

    boolean isActive() {
+4 −2
Original line number Diff line number Diff line
@@ -46,8 +46,10 @@ class SideStage extends StageTaskListener implements

    SideStage(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
            StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
            SurfaceSession surfaceSession) {
        super(taskOrganizer, displayId, callbacks, syncQueue, surfaceSession);
            SurfaceSession surfaceSession,
            @Nullable StageTaskUnfoldController stageTaskUnfoldController) {
        super(taskOrganizer, displayId, callbacks, syncQueue, surfaceSession,
                stageTaskUnfoldController);
        mContext = context;
    }

+9 −2
Original line number Diff line number Diff line
@@ -68,8 +68,11 @@ import com.android.wm.shell.transition.Transitions;

import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Optional;
import java.util.concurrent.Executor;

import javax.inject.Provider;

/**
 * Class manages split-screen multitasking mode and implements the main interface
 * {@link SplitScreen}.
@@ -91,6 +94,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
    private final Transitions mTransitions;
    private final TransactionPool mTransactionPool;
    private final SplitscreenEventLogger mLogger;
    private final Provider<Optional<StageTaskUnfoldController>> mUnfoldControllerProvider;

    private StageCoordinator mStageCoordinator;

@@ -99,7 +103,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
            RootTaskDisplayAreaOrganizer rootTDAOrganizer,
            ShellExecutor mainExecutor, DisplayImeController displayImeController,
            DisplayInsetsController displayInsetsController,
            Transitions transitions, TransactionPool transactionPool) {
            Transitions transitions, TransactionPool transactionPool,
            Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) {
        mTaskOrganizer = shellTaskOrganizer;
        mSyncQueue = syncQueue;
        mContext = context;
@@ -109,6 +114,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
        mDisplayInsetsController = displayInsetsController;
        mTransitions = transitions;
        mTransactionPool = transactionPool;
        mUnfoldControllerProvider = unfoldControllerProvider;
        mLogger = new SplitscreenEventLogger();
    }

@@ -131,7 +137,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
            // TODO: Multi-display
            mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
                    mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController,
                    mDisplayInsetsController, mTransitions, mTransactionPool, mLogger);
                    mDisplayInsetsController, mTransitions, mTransactionPool, mLogger,
                    mUnfoldControllerProvider);
        }
    }

+38 −4
Original line number Diff line number Diff line
@@ -95,6 +95,9 @@ import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import javax.inject.Provider;

/**
 * Coordinates the staging (visibility, sizing, ...) of the split-screen {@link MainStage} and
@@ -121,8 +124,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,

    private final MainStage mMainStage;
    private final StageListenerImpl mMainStageListener = new StageListenerImpl();
    private final StageTaskUnfoldController mMainUnfoldController;
    private final SideStage mSideStage;
    private final StageListenerImpl mSideStageListener = new StageListenerImpl();
    private final StageTaskUnfoldController mSideUnfoldController;
    @SplitPosition
    private int mSideStagePosition = SPLIT_POSITION_BOTTOM_OR_RIGHT;

@@ -179,26 +184,32 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
            DisplayImeController displayImeController,
            DisplayInsetsController displayInsetsController, Transitions transitions,
            TransactionPool transactionPool, SplitscreenEventLogger logger) {
            TransactionPool transactionPool, SplitscreenEventLogger logger,
            Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) {
        mContext = context;
        mDisplayId = displayId;
        mSyncQueue = syncQueue;
        mRootTDAOrganizer = rootTDAOrganizer;
        mTaskOrganizer = taskOrganizer;
        mLogger = logger;
        mMainUnfoldController = unfoldControllerProvider.get().orElse(null);
        mSideUnfoldController = unfoldControllerProvider.get().orElse(null);

        mMainStage = new MainStage(
                mTaskOrganizer,
                mDisplayId,
                mMainStageListener,
                mSyncQueue,
                mSurfaceSession);
                mSurfaceSession,
                mMainUnfoldController);
        mSideStage = new SideStage(
                mContext,
                mTaskOrganizer,
                mDisplayId,
                mSideStageListener,
                mSyncQueue,
                mSurfaceSession);
                mSurfaceSession,
                mSideUnfoldController);
        mDisplayImeController = displayImeController;
        mDisplayInsetsController = displayInsetsController;
        mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSideStage);
@@ -218,7 +229,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            MainStage mainStage, SideStage sideStage, DisplayImeController displayImeController,
            DisplayInsetsController displayInsetsController, SplitLayout splitLayout,
            Transitions transitions, TransactionPool transactionPool,
            SplitscreenEventLogger logger) {
            SplitscreenEventLogger logger,
            Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) {
        mContext = context;
        mDisplayId = displayId;
        mSyncQueue = syncQueue;
@@ -232,6 +244,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        mSplitLayout = splitLayout;
        mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
                mOnTransitionAnimationComplete);
        mMainUnfoldController = unfoldControllerProvider.get().orElse(null);
        mSideUnfoldController = unfoldControllerProvider.get().orElse(null);
        mLogger = logger;
        transitions.addHandler(this);
    }
@@ -460,6 +474,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                onLayoutChanged(mSplitLayout);
            } else {
                updateWindowBounds(mSplitLayout, wct);
                updateUnfoldBounds();
            }
        }
    }
@@ -606,6 +621,11 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            final SplitScreen.SplitScreenListener l = mListeners.get(i);
            l.onSplitVisibilityChanged(mDividerVisible);
        }

        if (mMainUnfoldController != null && mSideUnfoldController != null) {
            mMainUnfoldController.onSplitVisibilityChanged(mDividerVisible);
            mSideUnfoldController.onSplitVisibilityChanged(mDividerVisible);
        }
    }

    private void onStageRootTaskAppeared(StageListenerImpl stageListener) {
@@ -644,6 +664,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        mDividerVisible = visible;
        if (visible) {
            mSplitLayout.init();
            updateUnfoldBounds();
        } else {
            mSplitLayout.release();
        }
@@ -787,12 +808,20 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
    public void onLayoutChanged(SplitLayout layout) {
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        updateWindowBounds(layout, wct);
        updateUnfoldBounds();
        mSyncQueue.queue(wct);
        mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t));
        mSideStage.setOutlineVisibility(true);
        mLogger.logResize(mSplitLayout.getDividerPositionAsFraction());
    }

    private void updateUnfoldBounds() {
        if (mMainUnfoldController != null && mSideUnfoldController != null) {
            mMainUnfoldController.onLayoutChanged(getMainStageBounds());
            mSideUnfoldController.onLayoutChanged(getSideStageBounds());
        }
    }

    /**
     * Populates `wct` with operations that match the split windows to the current layout.
     * To match relevant surfaces, make sure to call updateSurfaceBounds after `wct` is applied
@@ -849,6 +878,11 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                    mDisplayAreaInfo.configuration, this, mParentContainerCallbacks,
                    mDisplayImeController, mTaskOrganizer);
            mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSplitLayout);

            if (mMainUnfoldController != null && mSideUnfoldController != null) {
                mMainUnfoldController.init();
                mSideUnfoldController.init();
            }
        }
    }

Loading