From 3ad28efb880fe9126603cb952a2fcdd8affa8b04 Mon Sep 17 00:00:00 2001 From: Tony Huang Date: Thu, 9 Sep 2021 17:16:22 +0800 Subject: Fix flicker when task move to back When task move to back, the task visibility will be invisible temporarily because visile app task reparent to TDA and below task still not move to front. Because this visibility change, we will hide divider and stage root task then it cause flicker. Fix this by only update divider and stage visibility when both stage visible or invisible. Bug: 199369390 Test: manual Test: pass existing tests Change-Id: Ide0b277e26e03ea3d7fb20132ff0e21807eee332 --- .../wm/shell/splitscreen/StageCoordinator.java | 67 +++++++--------------- 1 file changed, 22 insertions(+), 45 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index d9708f05e7dd..80d33137787c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -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; @@ -501,7 +499,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) { @@ -635,10 +634,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. @@ -655,59 +659,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, - sideStageBounds.left, sideStageBounds.top) + 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); + t.setPosition(mainStageLeash, mainStageBounds.left, mainStageBounds.top) + .setWindowCrop(mainStageLeash, + mainStageBounds.width(), mainStageBounds.height()); } - applyDividerVisibility(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(sideStageLeash, bothStageVisible) + .setVisibility(mainStageLeash, bothStageVisible); + applyDividerVisibility(t); + } }); } -- cgit v1.2.3-59-g8ed1b