Loading services/core/java/com/android/server/wm/Task.java +1 −1 Original line number Diff line number Diff line Loading @@ -4834,7 +4834,7 @@ class Task extends TaskFragment { if (topActivity.mTransitionController.inFinishingTransition(topActivity)) { final SurfaceControl.Transaction tx = taskDisplayArea.getPendingTransaction(); Transition.assignLayers(taskDisplayArea, tx); Transition.assignLayersForStartTransaction(taskDisplayArea, tx); final SurfaceControl leash = topActivity.getFixedRotationLeash(); if (leash != null) { tx.setLayer(leash, topActivity.getLastLayer()); Loading services/core/java/com/android/server/wm/Transition.java +18 −4 Original line number Diff line number Diff line Loading @@ -1190,7 +1190,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { // Need to update layers on involved displays since they were all paused while // the animation played. This puts the layers back into the correct order. for (int i = participantDisplays.length - 1; i >= 0; --i) { assignLayers(participantDisplays[i], t); assignLayersForFinishTransaction(participantDisplays[i], t); } for (int i = 0; i < info.getRootCount(); ++i) { Loading @@ -1198,13 +1198,27 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } } /** Assigns the layers for the start or end state of transition. */ static void assignLayers(WindowContainer<?> wc, SurfaceControl.Transaction t) { /** Assigns the layers for the start state of the transition. */ static void assignLayersForStartTransaction(WindowContainer<?> wc, SurfaceControl.Transaction t) { wc.mTransitionController.mBuildingTransitionLayers = true; try { wc.assignChildLayers(t); } finally { wc.mTransitionController.mBuildingTransitionLayers = false; } } /** Assigns the layers for the end state of transition. */ static void assignLayersForFinishTransaction(WindowContainer<?> wc, SurfaceControl.Transaction t) { wc.mTransitionController.mBuildingTransitionLayers = true; wc.mTransitionController.mBuildingFinishLayers = true; try { wc.assignChildLayers(t); } finally { wc.mTransitionController.mBuildingFinishLayers = false; wc.mTransitionController.mBuildingTransitionLayers = false; } } Loading Loading @@ -2986,7 +3000,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { rootLeash.setUnreleasedWarningCallSite("Transition.calculateTransitionRoots"); // Update layers to start transaction because we prevent assignment during collect, so // the layer of transition root can be correct. assignLayers(dc, startT); assignLayersForStartTransaction(dc, startT); startT.setLayer(rootLeash, leashReference.getLastLayer()); outInfo.addRootLeash(endDisplayId, rootLeash, ancestor.getBounds().left, ancestor.getBounds().top); Loading services/core/java/com/android/server/wm/TransitionController.java +10 −4 Original line number Diff line number Diff line Loading @@ -213,10 +213,16 @@ class TransitionController { final SparseArray<ArrayList<Task>> mLatestOnTopTasksReported = new SparseArray<>(); /** * `true` when building surface layer order for the finish transaction. We want to prevent * `true` when building surface layer order for the start/finish transaction. We want to prevent * wm from touching z-order of surfaces during transitions, but we still need to be able to * calculate the layers for the finishTransaction. So, when assigning layers into the finish * transaction, set this to true so that the {@link canAssignLayers} will allow it. * calculate the layers. So, when assigning layers into the start/finish transaction, set this * to true so that the {@link canAssignLayers} will allow it. */ boolean mBuildingTransitionLayers = false; /** * `true` when building surface layer order for the finish transaction. We use this to * force-assign layers to the finish transaction {@link WindowContainer#assignLayer()}. */ boolean mBuildingFinishLayers = false; Loading Loading @@ -686,7 +692,7 @@ class TransitionController { boolean canAssignLayers(@NonNull WindowContainer wc) { // Don't build window state into finish transaction in case another window is added or // removed during transition playing. if (mBuildingFinishLayers) { if (mBuildingTransitionLayers) { return wc.asWindowState() == null; } // Always allow WindowState to assign layers since it won't affect transition. Loading services/core/java/com/android/server/wm/WindowContainer.java +16 −5 Original line number Diff line number Diff line Loading @@ -2677,13 +2677,20 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return true; } /** * Assigns the layer for this container in the given transaction. The assignment only happens * if the current state allows assigning layers (ie. outside of a transition) and if the layers * have changed since they were last set, or if we are explicitly building the finish * transaction for a transition. */ void assignLayer(Transaction t, int layer) { // Don't assign layers while a transition animation is playing // TODO(b/173528115): establish robust best-practices around z-order fighting. if (!mTransitionController.canAssignLayers(this)) return; final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null; if (mSurfaceControl != null && changed) { if (mSyncState != SYNC_STATE_NONE) { final boolean layersChanged = layer != mLastLayer || mLastRelativeToLayer != null; final boolean forceUpdate = mTransitionController.mBuildingFinishLayers; if (mSurfaceControl != null && (layersChanged || forceUpdate)) { if (mSyncState != SYNC_STATE_NONE && !forceUpdate) { // When this container needs to be synced, assign layer with its own sync // transaction to avoid out of ordering when merge. // Still use the passed-in transaction for non-sync case, such as building finish Loading @@ -2696,10 +2703,14 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } } /** * Assigns the a relative layer for this container in the given transaction. The assignment * only happens if the layers have changed since they were last set. */ void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer, boolean forceUpdate) { final boolean changed = layer != mLastLayer || mLastRelativeToLayer != relativeTo; if (mSurfaceControl != null && (changed || forceUpdate)) { final boolean layersChanged = layer != mLastLayer || mLastRelativeToLayer != relativeTo; if (mSurfaceControl != null && (layersChanged || forceUpdate)) { if (mSyncState != SYNC_STATE_NONE) { // When this container needs to be synced, assign layer with its own sync // transaction to avoid out of ordering when merge. Loading services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +51 −11 Original line number Diff line number Diff line Loading @@ -1141,29 +1141,69 @@ public class WindowContainerTests extends WindowTestsBase { verify(win).clearFrozenInsetsState(); } @Test public void testAssignLayer() { final WindowContainer container = new WindowContainer(mWm); container.mSurfaceControl = mock(SurfaceControl.class); // Trigger layer call with a pending transaction, verify layer set container.assignLayer(mTransaction, 1 /* layer */); verify(mTransaction).setLayer(container.mSurfaceControl, 1 /* layer */); // Trigger layer call with a pending transaction, verify layer not set clearInvocations(mTransaction); container.assignLayer(mTransaction, 1 /* layer */); verify(mTransaction, never()).setLayer(container.mSurfaceControl, 1 /* layer */); // Trigger layer call while building a (non-finish) transition transaction, verify layer // not set container.mTransitionController.mBuildingTransitionLayers = true; clearInvocations(mTransaction); container.assignLayer(mTransaction, 1 /* layer */); verify(mTransaction, never()).setLayer(container.mSurfaceControl, 1 /* layer */); container.mTransitionController.mBuildingTransitionLayers = false; // Trigger layer call while building a finish transition transaction, verify layer set container.mTransitionController.mBuildingTransitionLayers = true; container.mTransitionController.mBuildingFinishLayers = true; clearInvocations(mTransaction); container.assignLayer(mTransaction, 1 /* layer */); verify(mTransaction).setLayer(container.mSurfaceControl, 1 /* layer */); container.mTransitionController.mBuildingTransitionLayers = false; container.mTransitionController.mBuildingFinishLayers = false; // Trigger another layer call while building a finish transition transaction, verify layer // set container.mTransitionController.mBuildingTransitionLayers = true; container.mTransitionController.mBuildingFinishLayers = true; clearInvocations(mTransaction); container.assignLayer(mTransaction, 1 /* layer */); verify(mTransaction).setLayer(container.mSurfaceControl, 1 /* layer */); container.mTransitionController.mBuildingTransitionLayers = false; container.mTransitionController.mBuildingFinishLayers = false; } @Test public void testAssignRelativeLayer() { final WindowContainer container = new WindowContainer(mWm); container.mSurfaceControl = mock(SurfaceControl.class); spyOn(container); doReturn(mTransaction).when(container).getPendingTransaction(); doReturn(mTransaction).when(container).getSyncTransaction(); final SurfaceAnimator surfaceAnimator = container.mSurfaceAnimator; final SurfaceControl relativeParent = mock(SurfaceControl.class); final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); spyOn(container); final SurfaceControl.Transaction otherTx = mock(SurfaceControl.Transaction.class); spyOn(surfaceAnimator); doReturn(t).when(container).getSyncTransaction(); // Trigger for first relative layer call. container.assignRelativeLayer(t, relativeParent, 1 /* layer */); verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 1 /* layer */); container.assignRelativeLayer(mTransaction, relativeParent, 1 /* layer */); verify(surfaceAnimator).setRelativeLayer(mTransaction, relativeParent, 1 /* layer */); // Not trigger for the same relative layer call. clearInvocations(surfaceAnimator); container.assignRelativeLayer(t, relativeParent, 1 /* layer */); verify(surfaceAnimator, never()).setRelativeLayer(t, relativeParent, 1 /* layer */); // Trigger for the same relative layer call if forceUpdate=true container.assignRelativeLayer(t, relativeParent, 1 /* layer */, true /* forceUpdate */); verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 1 /* layer */); container.assignRelativeLayer(mTransaction, relativeParent, 1 /* layer */); verify(surfaceAnimator, never()).setRelativeLayer(mTransaction, relativeParent, 1 /* layer */); } @Test Loading Loading
services/core/java/com/android/server/wm/Task.java +1 −1 Original line number Diff line number Diff line Loading @@ -4834,7 +4834,7 @@ class Task extends TaskFragment { if (topActivity.mTransitionController.inFinishingTransition(topActivity)) { final SurfaceControl.Transaction tx = taskDisplayArea.getPendingTransaction(); Transition.assignLayers(taskDisplayArea, tx); Transition.assignLayersForStartTransaction(taskDisplayArea, tx); final SurfaceControl leash = topActivity.getFixedRotationLeash(); if (leash != null) { tx.setLayer(leash, topActivity.getLastLayer()); Loading
services/core/java/com/android/server/wm/Transition.java +18 −4 Original line number Diff line number Diff line Loading @@ -1190,7 +1190,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { // Need to update layers on involved displays since they were all paused while // the animation played. This puts the layers back into the correct order. for (int i = participantDisplays.length - 1; i >= 0; --i) { assignLayers(participantDisplays[i], t); assignLayersForFinishTransaction(participantDisplays[i], t); } for (int i = 0; i < info.getRootCount(); ++i) { Loading @@ -1198,13 +1198,27 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } } /** Assigns the layers for the start or end state of transition. */ static void assignLayers(WindowContainer<?> wc, SurfaceControl.Transaction t) { /** Assigns the layers for the start state of the transition. */ static void assignLayersForStartTransaction(WindowContainer<?> wc, SurfaceControl.Transaction t) { wc.mTransitionController.mBuildingTransitionLayers = true; try { wc.assignChildLayers(t); } finally { wc.mTransitionController.mBuildingTransitionLayers = false; } } /** Assigns the layers for the end state of transition. */ static void assignLayersForFinishTransaction(WindowContainer<?> wc, SurfaceControl.Transaction t) { wc.mTransitionController.mBuildingTransitionLayers = true; wc.mTransitionController.mBuildingFinishLayers = true; try { wc.assignChildLayers(t); } finally { wc.mTransitionController.mBuildingFinishLayers = false; wc.mTransitionController.mBuildingTransitionLayers = false; } } Loading Loading @@ -2986,7 +3000,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { rootLeash.setUnreleasedWarningCallSite("Transition.calculateTransitionRoots"); // Update layers to start transaction because we prevent assignment during collect, so // the layer of transition root can be correct. assignLayers(dc, startT); assignLayersForStartTransaction(dc, startT); startT.setLayer(rootLeash, leashReference.getLastLayer()); outInfo.addRootLeash(endDisplayId, rootLeash, ancestor.getBounds().left, ancestor.getBounds().top); Loading
services/core/java/com/android/server/wm/TransitionController.java +10 −4 Original line number Diff line number Diff line Loading @@ -213,10 +213,16 @@ class TransitionController { final SparseArray<ArrayList<Task>> mLatestOnTopTasksReported = new SparseArray<>(); /** * `true` when building surface layer order for the finish transaction. We want to prevent * `true` when building surface layer order for the start/finish transaction. We want to prevent * wm from touching z-order of surfaces during transitions, but we still need to be able to * calculate the layers for the finishTransaction. So, when assigning layers into the finish * transaction, set this to true so that the {@link canAssignLayers} will allow it. * calculate the layers. So, when assigning layers into the start/finish transaction, set this * to true so that the {@link canAssignLayers} will allow it. */ boolean mBuildingTransitionLayers = false; /** * `true` when building surface layer order for the finish transaction. We use this to * force-assign layers to the finish transaction {@link WindowContainer#assignLayer()}. */ boolean mBuildingFinishLayers = false; Loading Loading @@ -686,7 +692,7 @@ class TransitionController { boolean canAssignLayers(@NonNull WindowContainer wc) { // Don't build window state into finish transaction in case another window is added or // removed during transition playing. if (mBuildingFinishLayers) { if (mBuildingTransitionLayers) { return wc.asWindowState() == null; } // Always allow WindowState to assign layers since it won't affect transition. Loading
services/core/java/com/android/server/wm/WindowContainer.java +16 −5 Original line number Diff line number Diff line Loading @@ -2677,13 +2677,20 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return true; } /** * Assigns the layer for this container in the given transaction. The assignment only happens * if the current state allows assigning layers (ie. outside of a transition) and if the layers * have changed since they were last set, or if we are explicitly building the finish * transaction for a transition. */ void assignLayer(Transaction t, int layer) { // Don't assign layers while a transition animation is playing // TODO(b/173528115): establish robust best-practices around z-order fighting. if (!mTransitionController.canAssignLayers(this)) return; final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null; if (mSurfaceControl != null && changed) { if (mSyncState != SYNC_STATE_NONE) { final boolean layersChanged = layer != mLastLayer || mLastRelativeToLayer != null; final boolean forceUpdate = mTransitionController.mBuildingFinishLayers; if (mSurfaceControl != null && (layersChanged || forceUpdate)) { if (mSyncState != SYNC_STATE_NONE && !forceUpdate) { // When this container needs to be synced, assign layer with its own sync // transaction to avoid out of ordering when merge. // Still use the passed-in transaction for non-sync case, such as building finish Loading @@ -2696,10 +2703,14 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } } /** * Assigns the a relative layer for this container in the given transaction. The assignment * only happens if the layers have changed since they were last set. */ void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer, boolean forceUpdate) { final boolean changed = layer != mLastLayer || mLastRelativeToLayer != relativeTo; if (mSurfaceControl != null && (changed || forceUpdate)) { final boolean layersChanged = layer != mLastLayer || mLastRelativeToLayer != relativeTo; if (mSurfaceControl != null && (layersChanged || forceUpdate)) { if (mSyncState != SYNC_STATE_NONE) { // When this container needs to be synced, assign layer with its own sync // transaction to avoid out of ordering when merge. Loading
services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +51 −11 Original line number Diff line number Diff line Loading @@ -1141,29 +1141,69 @@ public class WindowContainerTests extends WindowTestsBase { verify(win).clearFrozenInsetsState(); } @Test public void testAssignLayer() { final WindowContainer container = new WindowContainer(mWm); container.mSurfaceControl = mock(SurfaceControl.class); // Trigger layer call with a pending transaction, verify layer set container.assignLayer(mTransaction, 1 /* layer */); verify(mTransaction).setLayer(container.mSurfaceControl, 1 /* layer */); // Trigger layer call with a pending transaction, verify layer not set clearInvocations(mTransaction); container.assignLayer(mTransaction, 1 /* layer */); verify(mTransaction, never()).setLayer(container.mSurfaceControl, 1 /* layer */); // Trigger layer call while building a (non-finish) transition transaction, verify layer // not set container.mTransitionController.mBuildingTransitionLayers = true; clearInvocations(mTransaction); container.assignLayer(mTransaction, 1 /* layer */); verify(mTransaction, never()).setLayer(container.mSurfaceControl, 1 /* layer */); container.mTransitionController.mBuildingTransitionLayers = false; // Trigger layer call while building a finish transition transaction, verify layer set container.mTransitionController.mBuildingTransitionLayers = true; container.mTransitionController.mBuildingFinishLayers = true; clearInvocations(mTransaction); container.assignLayer(mTransaction, 1 /* layer */); verify(mTransaction).setLayer(container.mSurfaceControl, 1 /* layer */); container.mTransitionController.mBuildingTransitionLayers = false; container.mTransitionController.mBuildingFinishLayers = false; // Trigger another layer call while building a finish transition transaction, verify layer // set container.mTransitionController.mBuildingTransitionLayers = true; container.mTransitionController.mBuildingFinishLayers = true; clearInvocations(mTransaction); container.assignLayer(mTransaction, 1 /* layer */); verify(mTransaction).setLayer(container.mSurfaceControl, 1 /* layer */); container.mTransitionController.mBuildingTransitionLayers = false; container.mTransitionController.mBuildingFinishLayers = false; } @Test public void testAssignRelativeLayer() { final WindowContainer container = new WindowContainer(mWm); container.mSurfaceControl = mock(SurfaceControl.class); spyOn(container); doReturn(mTransaction).when(container).getPendingTransaction(); doReturn(mTransaction).when(container).getSyncTransaction(); final SurfaceAnimator surfaceAnimator = container.mSurfaceAnimator; final SurfaceControl relativeParent = mock(SurfaceControl.class); final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); spyOn(container); final SurfaceControl.Transaction otherTx = mock(SurfaceControl.Transaction.class); spyOn(surfaceAnimator); doReturn(t).when(container).getSyncTransaction(); // Trigger for first relative layer call. container.assignRelativeLayer(t, relativeParent, 1 /* layer */); verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 1 /* layer */); container.assignRelativeLayer(mTransaction, relativeParent, 1 /* layer */); verify(surfaceAnimator).setRelativeLayer(mTransaction, relativeParent, 1 /* layer */); // Not trigger for the same relative layer call. clearInvocations(surfaceAnimator); container.assignRelativeLayer(t, relativeParent, 1 /* layer */); verify(surfaceAnimator, never()).setRelativeLayer(t, relativeParent, 1 /* layer */); // Trigger for the same relative layer call if forceUpdate=true container.assignRelativeLayer(t, relativeParent, 1 /* layer */, true /* forceUpdate */); verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 1 /* layer */); container.assignRelativeLayer(mTransaction, relativeParent, 1 /* layer */); verify(surfaceAnimator, never()).setRelativeLayer(mTransaction, relativeParent, 1 /* layer */); } @Test Loading