diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 23f83e161e609..ad151df055796 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -218,9 +218,13 @@ public class WindowlessWindowManager implements IWindowSession { throw new IllegalArgumentException( "Invalid window token (never added or removed already)"); } + removeSurface(state.mSurfaceControl); + } + /** Separate from {@link #remove} so that subclasses can put removal on a sync transaction. */ + protected void removeSurface(SurfaceControl sc) { try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) { - t.remove(state.mSurfaceControl).apply(); + t.remove(sc).apply(); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index b52c8d118711f..5246117486ed5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -98,6 +98,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange private WindowContainerToken mWinToken2; private int mDividePosition; private boolean mInitialized = false; + private boolean mFreezeDividerWindow = false; private int mOrientation; private int mRotation; @@ -225,11 +226,6 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null); initDividerPosition(mTempRect); - if (mInitialized) { - release(); - init(); - } - return true; } @@ -298,20 +294,37 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange } /** Releases the surface holding the current {@link DividerView}. */ - public void release() { + public void release(SurfaceControl.Transaction t) { if (!mInitialized) return; mInitialized = false; - mSplitWindowManager.release(); + mSplitWindowManager.release(t); mDisplayImeController.removePositionProcessor(mImePositionProcessor); mImePositionProcessor.reset(); } + public void release() { + release(null /* t */); + } + + /** Releases and re-inflates {@link DividerView} on the root surface. */ + public void update(SurfaceControl.Transaction t) { + if (!mInitialized) return; + mSplitWindowManager.release(t); + mImePositionProcessor.reset(); + mSplitWindowManager.init(this, mInsetsState); + } + @Override public void insetsChanged(InsetsState insetsState) { mInsetsState.set(insetsState); if (!mInitialized) { return; } + if (mFreezeDividerWindow) { + // DO NOT change its layout before transition actually run because it might cause + // flicker. + return; + } mSplitWindowManager.onInsetsChanged(insetsState); } @@ -323,6 +336,10 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange } } + public void setFreezeDividerWindow(boolean freezeDividerWindow) { + mFreezeDividerWindow = freezeDividerWindow; + } + /** * Updates bounds with the passing position. Usually used to update recording bounds while * performing animation or dragging divider bar to resize the splits. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java index 4903f9d46dc74..833d9d50701c8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java @@ -58,6 +58,9 @@ public final class SplitWindowManager extends WindowlessWindowManager { private SurfaceControl mLeash; private DividerView mDividerView; + // Used to "pass" a transaction to WWM.remove so that view removal can be synchronized. + private SurfaceControl.Transaction mSyncTransaction = null; + public interface ParentContainerCallbacks { void attachToParentSurface(SurfaceControl.Builder b); void onLeashReady(SurfaceControl leash); @@ -130,22 +133,38 @@ public final class SplitWindowManager extends WindowlessWindowManager { * Releases the surface control of the current {@link DividerView} and tear down the view * hierarchy. */ - void release() { + void release(@Nullable SurfaceControl.Transaction t) { if (mDividerView != null) { mDividerView = null; } if (mViewHost != null){ + mSyncTransaction = t; mViewHost.release(); + mSyncTransaction = null; mViewHost = null; } if (mLeash != null) { - new SurfaceControl.Transaction().remove(mLeash).apply(); + if (t == null) { + new SurfaceControl.Transaction().remove(mLeash).apply(); + } else { + t.remove(mLeash); + } mLeash = null; } } + @Override + protected void removeSurface(SurfaceControl sc) { + // This gets called via SurfaceControlViewHost.release() + if (mSyncTransaction != null) { + mSyncTransaction.remove(sc); + } else { + super.removeSurface(sc); + } + } + void setInteractive(boolean interactive) { if (mDividerView == null) return; mDividerView.setInteractive(interactive); 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 48dd1fe3cb7e0..ec1ddf0777958 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 @@ -29,6 +29,7 @@ import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManager.transitTypeToString; import static android.view.WindowManagerPolicyConstants.SPLIT_DIVIDER_LAYER; +import static android.window.TransitionInfo.FLAG_IS_DISPLAY; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; @@ -1171,6 +1172,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, updateUnfoldBounds(); return; } + + mSplitLayout.update(null /* t */); onLayoutSizeChanged(mSplitLayout); } } @@ -1198,7 +1201,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (!ENABLE_SHELL_TRANSITIONS) return; final SurfaceControl.Transaction t = mTransactionPool.acquire(); - setDividerVisibility(false, t); mDisplayLayout.rotateTo(mContext.getResources(), toRotation); mSplitLayout.rotateTo(toRotation, mDisplayLayout.stableInsets()); updateWindowBounds(mSplitLayout, wct); @@ -1255,8 +1257,15 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, @Nullable TransitionRequestInfo request) { final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask(); if (triggerTask == null) { - // Still want to monitor everything while in split-screen, so return non-null. - return mMainStage.isActive() ? new WindowContainerTransaction() : null; + if (mMainStage.isActive()) { + if (request.getType() == TRANSIT_CHANGE && request.getDisplayChange() != null) { + mSplitLayout.setFreezeDividerWindow(true); + } + // Still want to monitor everything while in split-screen, so return non-null. + return new WindowContainerTransaction(); + } else { + return null; + } } else if (triggerTask.displayId != mDisplayId) { // Skip handling task on the other display. return null; @@ -1352,8 +1361,14 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, // If we're not in split-mode, just abort so something else can handle it. if (!mMainStage.isActive()) return false; + mSplitLayout.setFreezeDividerWindow(false); for (int iC = 0; iC < info.getChanges().size(); ++iC) { final TransitionInfo.Change change = info.getChanges().get(iC); + if (change.getMode() == TRANSIT_CHANGE + && (change.getFlags() & FLAG_IS_DISPLAY) != 0) { + mSplitLayout.update(startTransaction); + } + final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); if (taskInfo == null || !taskInfo.hasParentTask()) continue; final StageTaskListener stage = getStageOfTask(taskInfo); @@ -1368,10 +1383,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, Log.w(TAG, "Expected onTaskVanished on " + stage + " to have been called" + " with " + taskInfo.taskId + " before startAnimation()."); } - } else if (info.getType() == TRANSIT_CHANGE - && change.getStartRotation() != change.getEndRotation()) { - // Show the divider after transition finished. - setDividerVisibility(true, finishTransaction); } } if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java index 9bb54a18063f6..2e5078d86a8b2 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java @@ -61,7 +61,7 @@ public class SplitWindowManagerTests extends ShellTestCase { public void testInitRelease() { mSplitWindowManager.init(mSplitLayout, new InsetsState()); assertThat(mSplitWindowManager.getSurfaceControl()).isNotNull(); - mSplitWindowManager.release(); + mSplitWindowManager.release(null /* t */); assertThat(mSplitWindowManager.getSurfaceControl()).isNull(); } }