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

Commit 78432215 authored by Jerry Chang's avatar Jerry Chang
Browse files

Integrate keyguard behavior in split screen with shell-transition

Support to hide the divider bar when keyguard showing and support to
dismiss split after unlocked on folded device. Also unbind
show-when-locked split dismissing flow with stage visibility changed
callback to simplify the code.

Bug: 206487881
Test: atest WMShellUnitTests
Test: trigger split, won't see divider bar showing above keyguard.
Test: trigger split, fold the device and unlock will dismiss split. And
      there's no such split pair in recents.
Test: trigger split with show-when-locked activity, it'll dismiss split
      when it's occluding keyguard.
Change-Id: If536121ef0cae4acda12268ffb32024a9736bacd
parent 52e1f367
Loading
Loading
Loading
Loading
+0 −9
Original line number Diff line number Diff line
@@ -75,12 +75,6 @@ public interface SplitScreen {
        return null;
    }

    /**
     * Called when the keyguard occluded state changes.
     * @param occluded Indicates if the keyguard is now occluded.
     */
    void onKeyguardOccludedChanged(boolean occluded);

    /**
     * Called when the visibility of the keyguard changes.
     * @param showing Indicates if the keyguard is now visible.
@@ -90,9 +84,6 @@ public interface SplitScreen {
    /** Called when device waking up finished. */
    void onFinishedWakingUp();

    /** Called when device going to sleep finished. */
    void onFinishedGoingToSleep();

    /** Get a string representation of a stage type */
    static String stageTypeToString(@StageType int stage) {
        switch (stage) {
+0 −22
Original line number Diff line number Diff line
@@ -249,10 +249,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
        mStageCoordinator.exitSplitScreen(toTopTaskId, exitReason);
    }

    public void onKeyguardOccludedChanged(boolean occluded) {
        mStageCoordinator.onKeyguardOccludedChanged(occluded);
    }

    public void onKeyguardVisibilityChanged(boolean showing) {
        mStageCoordinator.onKeyguardVisibilityChanged(showing);
    }
@@ -261,10 +257,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
        mStageCoordinator.onFinishedWakingUp();
    }

    public void onFinishedGoingToSleep() {
        mStageCoordinator.onFinishedGoingToSleep();
    }

    public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
        mStageCoordinator.exitSplitScreenOnHide(exitSplitScreenOnHide);
    }
@@ -490,13 +482,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
            return mISplitScreen;
        }

        @Override
        public void onKeyguardOccludedChanged(boolean occluded) {
            mMainExecutor.execute(() -> {
                SplitScreenController.this.onKeyguardOccludedChanged(occluded);
            });
        }

        @Override
        public void registerSplitScreenListener(SplitScreenListener listener, Executor executor) {
            if (mExecutors.containsKey(listener)) return;
@@ -538,13 +523,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
                SplitScreenController.this.onFinishedWakingUp();
            });
        }

        @Override
        public void onFinishedGoingToSleep() {
            mMainExecutor.execute(() -> {
                SplitScreenController.this.onFinishedGoingToSleep();
            });
        }
    }

    /**
+61 −53
Original line number Diff line number Diff line
@@ -46,7 +46,6 @@ import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON
import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
import static com.android.wm.shell.splitscreen.SplitScreenTransitions.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS_SNAP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
import static com.android.wm.shell.transition.Transitions.isClosingType;
import static com.android.wm.shell.transition.Transitions.isOpeningType;
@@ -157,8 +156,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
    // and exit, since exit itself can trigger a number of changes that update the stages.
    private boolean mShouldUpdateRecents;
    private boolean mExitSplitScreenOnHide;
    private boolean mKeyguardOccluded;
    private boolean mDeviceSleep;

    /** The target stage to dismiss to when unlock after folded. */
    @StageType
@@ -171,6 +168,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            // properly for the animation itself.
            mSplitLayout.release();
            mSplitLayout.resetDividerPosition();
            mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
        }
    };

@@ -554,29 +552,54 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        mTaskOrganizer.applyTransaction(wct);
    }

    void onKeyguardOccludedChanged(boolean occluded) {
        // Do not exit split directly, because it needs to wait for task info update to determine
        // which task should remain on top after split dismissed.
        mKeyguardOccluded = occluded;
    void onKeyguardVisibilityChanged(boolean showing) {
        if (!mMainStage.isActive()) {
            return;
        }

    void onKeyguardVisibilityChanged(boolean showing) {
        if (!showing && mMainStage.isActive()
                && mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
            exitSplitScreen(mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
        if (ENABLE_SHELL_TRANSITIONS) {
            // Update divider visibility so it won't float on top of keyguard.
            setDividerVisibility(!showing, null /* transaction */);
        }

        if (!showing && mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
            if (ENABLE_SHELL_TRANSITIONS) {
                final WindowContainerTransaction wct = new WindowContainerTransaction();
                prepareExitSplitScreen(mTopStageAfterFoldDismiss, wct);
                mSplitTransitions.startDismissTransition(null /* transition */, wct, this,
                        mTopStageAfterFoldDismiss, EXIT_REASON_DEVICE_FOLDED);
            } else {
                exitSplitScreen(
                        mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
                        EXIT_REASON_DEVICE_FOLDED);
            }
        }
    }

    void onFinishedWakingUp() {
        if (mMainStage.isActive()) {
            exitSplitScreenIfKeyguardOccluded();
        }
        mDeviceSleep = false;
        if (!mMainStage.isActive()) {
            return;
        }

    void onFinishedGoingToSleep() {
        mDeviceSleep = true;
        // Check if there's only one stage visible while keyguard occluded.
        final boolean mainStageVisible = mMainStage.mRootTaskInfo.isVisible;
        final boolean oneStageVisible =
                mMainStage.mRootTaskInfo.isVisible != mSideStage.mRootTaskInfo.isVisible;
        if (oneStageVisible) {
            // Dismiss split because there's show-when-locked activity showing on top of keyguard.
            // Also make sure the task contains show-when-locked activity remains on top after split
            // dismissed.
            if (!ENABLE_SHELL_TRANSITIONS) {
                final StageTaskListener toTop = mainStageVisible ? mMainStage : mSideStage;
                exitSplitScreen(toTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
            } else {
                final int dismissTop = mainStageVisible ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
                final WindowContainerTransaction wct = new WindowContainerTransaction();
                prepareExitSplitScreen(dismissTop, wct);
                mSplitTransitions.startDismissTransition(null /* transition */, wct, this,
                        dismissTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
            }
        }
    }

    void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
@@ -607,19 +630,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        applyExitSplitScreen(childrenToTop, wct, exitReason);
    }

    private void exitSplitScreenIfKeyguardOccluded() {
        final boolean mainStageVisible = mMainStageListener.mVisible;
        final boolean oneStageVisible = mainStageVisible ^ mSideStageListener.mVisible;
        if (mDeviceSleep && mKeyguardOccluded && oneStageVisible) {
            // Only the stages include show-when-locked activity is visible while keyguard occluded.
            // Dismiss split because there's show-when-locked activity showing on top of keyguard.
            // Also make sure the task contains show-when-locked activity remains on top after split
            // dismissed.
            final StageTaskListener toTop = mainStageVisible ? mMainStage : mSideStage;
            exitSplitScreen(toTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
        }
    }

    private void applyExitSplitScreen(StageTaskListener childrenToTop,
            WindowContainerTransaction wct, @ExitReason int exitReason) {
        mRecentTasks.ifPresent(recentTasks -> {
@@ -669,6 +679,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            case EXIT_REASON_APP_FINISHED:
            // One of the children enters PiP
            case EXIT_REASON_CHILD_TASK_ENTER_PIP:
            // One of the apps occludes lock screen.
            case EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP:
            // User has unlocked the device after folded
            case EXIT_REASON_DEVICE_FOLDED:
                return true;
            default:
                return false;
@@ -828,31 +842,27 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
    private void onStageVisibilityChanged(StageListenerImpl stageListener) {
        final boolean sideStageVisible = mSideStageListener.mVisible;
        final boolean mainStageVisible = mMainStageListener.mVisible;
        final boolean bothStageVisible = sideStageVisible && mainStageVisible;
        final boolean bothStageInvisible = !sideStageVisible && !mainStageVisible;
        final boolean sameVisibility = sideStageVisible == mainStageVisible;

        if (bothStageInvisible) {
        // Wait for both stages having the same visibility to prevent causing flicker.
        if (mainStageVisible != sideStageVisible) {
            return;
        }

        if (!mainStageVisible) {
            // Both stages are not visible, check if it needs to dismiss split screen.
            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.
                    // Don't dismiss split screen when both stages are not visible due to sleeping
                    // display.
                    || (!mMainStage.mRootTaskInfo.isSleeping
                    && !mSideStage.mRootTaskInfo.isSleeping)) {
            // Don't dismiss staged split when both stages are not visible due to sleeping display,
            // like the cases keyguard showing or screen off.
                exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RETURN_HOME);
            }
        }
        exitSplitScreenIfKeyguardOccluded();

        mSyncQueue.runInSync(t -> {
            // 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(mSideStage.mRootLeash, bothStageVisible)
                        .setVisibility(mMainStage.mRootLeash, bothStageVisible);
                setDividerVisibility(bothStageVisible, t);
            }
            t.setVisibility(mSideStage.mRootLeash, sideStageVisible)
                    .setVisibility(mMainStage.mRootLeash, mainStageVisible);
            setDividerVisibility(mainStageVisible, t);
        });
    }

@@ -1374,11 +1384,9 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        setSplitsVisible(false);
        // Wait until after animation to update divider

        if (info.getType() == TRANSIT_SPLIT_DISMISS_SNAP) {
        // Reset crops so they don't interfere with subsequent launches
        t.setWindowCrop(mMainStage.mRootLeash, null);
        t.setWindowCrop(mSideStage.mRootLeash, null);
        }

        if (dismissTransition.mDismissTop == STAGE_TYPE_UNDEFINED) {
            logExit(dismissTransition.mReason);
+0 −10
Original line number Diff line number Diff line
@@ -258,11 +258,6 @@ public final class WMShell extends CoreStartable
            public void onKeyguardVisibilityChanged(boolean showing) {
                splitScreen.onKeyguardVisibilityChanged(showing);
            }

            @Override
            public void onKeyguardOccludedChanged(boolean occluded) {
                splitScreen.onKeyguardOccludedChanged(occluded);
            }
        };
        mKeyguardUpdateMonitor.registerCallback(mSplitScreenKeyguardCallback);

@@ -271,11 +266,6 @@ public final class WMShell extends CoreStartable
            public void onFinishedWakingUp() {
                splitScreen.onFinishedWakingUp();
            }

            @Override
            public void onFinishedGoingToSleep() {
                splitScreen.onFinishedGoingToSleep();
            }
        });
    }