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

Commit d2f034f1 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fix flicker when task move to back" into sc-v2-dev

parents bd64fd9f 3ad28efb
Loading
Loading
Loading
Loading
+22 −45
Original line number Diff line number Diff line
@@ -18,8 +18,6 @@ package com.android.wm.shell.splitscreen;

import static android.app.ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
@@ -515,7 +513,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        mSideStage.removeAllTasks(wct, childrenToTop == mSideStage);
        mMainStage.deactivate(wct, childrenToTop == mMainStage);
        mTaskOrganizer.applyTransaction(wct);
        // Reset divider position.
        // Hide divider and reset its position.
        setDividerVisibility(false);
        mSplitLayout.resetDividerPosition();
        mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
        if (childrenToTop != null) {
@@ -649,10 +648,15 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
    private void onStageVisibilityChanged(StageListenerImpl stageListener) {
        final boolean sideStageVisible = mSideStageListener.mVisible;
        final boolean mainStageVisible = mMainStageListener.mVisible;
        // Divider is only visible if both the main stage and side stages are visible
        setDividerVisibility(isSplitScreenVisible());
        final boolean bothStageVisible = sideStageVisible && mainStageVisible;
        final boolean sameVisibility = sideStageVisible == mainStageVisible;
        // Only add or remove divider when both visible or both invisible to avoid sometimes we only
        // got one stage visibility changed for a moment and it will cause flicker.
        if (sameVisibility) {
            setDividerVisibility(bothStageVisible);
        }

        if (!mainStageVisible && !sideStageVisible) {
        if (!bothStageVisible) {
            if (mExitSplitScreenOnHide
            // Don't dismiss staged split when both stages are not visible due to sleeping display,
            // like the cases keyguard showing or screen off.
@@ -669,59 +673,32 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            exitSplitScreen(toTop, SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED_SHOW_ON_TOP);
        }

        // When both stage's visibility changed to visible, main stage might receives visibility
        // changed before side stage if it has higher z-order than side stage. Make sure we only
        // update main stage's windowing mode with the visibility changed of side stage to prevent
        // stacking multiple windowing mode transactions which result to flicker issue.
        if (mainStageVisible && stageListener == mSideStageListener) {
            final WindowContainerTransaction wct = new WindowContainerTransaction();
            if (sideStageVisible) {
                // The main stage configuration should to follow split layout when side stage is
                // visible.
                mMainStage.updateConfiguration(
                        WINDOWING_MODE_MULTI_WINDOW, getMainStageBounds(), wct);
            } else if (!mSideStage.mRootTaskInfo.isSleeping) {
                // We want the main stage configuration to be fullscreen when the side stage isn't
                // visible.
                // We should not do it when side stage are not visible due to sleeping display too.
                mMainStage.updateConfiguration(WINDOWING_MODE_FULLSCREEN, null, wct);
            }
            // TODO: Change to `mSyncQueue.queue(wct)` once BLAST is stable.
            mTaskOrganizer.applyTransaction(wct);
        }

        mSyncQueue.runInSync(t -> {
            final SurfaceControl sideStageLeash = mSideStage.mRootLeash;
            final SurfaceControl mainStageLeash = mMainStage.mRootLeash;

            if (sideStageVisible) {
                final Rect sideStageBounds = getSideStageBounds();
                t.show(sideStageLeash)
                        .setPosition(sideStageLeash,
                t.setPosition(sideStageLeash,
                        sideStageBounds.left, sideStageBounds.top)
                        .setWindowCrop(sideStageLeash,
                                sideStageBounds.width(), sideStageBounds.height());
            } else {
                t.hide(sideStageLeash);
            }

            if (mainStageVisible) {
                final Rect mainStageBounds = getMainStageBounds();
                t.show(mainStageLeash);
                if (sideStageVisible) {
                t.setPosition(mainStageLeash, mainStageBounds.left, mainStageBounds.top)
                        .setWindowCrop(mainStageLeash,
                                mainStageBounds.width(), mainStageBounds.height());
                } else {
                    // Clear window crop and position if side stage isn't visible.
                    t.setPosition(mainStageLeash, 0, 0)
                            .setWindowCrop(mainStageLeash, null);
                }
            } else {
                t.hide(mainStageLeash);
            }

            // Same above, we only set root tasks and divider leash visibility when both stage
            // change to visible or invisible to avoid flicker.
            if (sameVisibility) {
                t.setVisibility(sideStageLeash, bothStageVisible)
                        .setVisibility(mainStageLeash, bothStageVisible);
                applyDividerVisibility(t);
            }
        });
    }