Loading services/core/java/com/android/server/wm/ActivityTaskManagerService.java +3 −0 Original line number Diff line number Diff line Loading @@ -5280,6 +5280,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** Applies latest configuration and/or visibility updates if needed. */ boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) { if (starting == null && mTaskSupervisor.isRootVisibilityUpdateDeferred()) { return true; } boolean kept = true; final Task mainRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask(); // mainRootTask is null during startup. Loading services/core/java/com/android/server/wm/Transition.java +23 −2 Original line number Diff line number Diff line Loading @@ -2857,12 +2857,18 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { return false; } /** Applies the new configuration for the changed displays. */ void applyDisplayChangeIfNeeded() { /** * Applies the new configuration for the changed displays. Returns the activities that should * check whether to deliver the new configuration to clients. */ @Nullable ArrayList<ActivityRecord> applyDisplayChangeIfNeeded() { ArrayList<ActivityRecord> activitiesMayChange = null; for (int i = mParticipants.size() - 1; i >= 0; --i) { final WindowContainer<?> wc = mParticipants.valueAt(i); final DisplayContent dc = wc.asDisplayContent(); if (dc == null || !mChanges.get(dc).hasChanged()) continue; final int originalSeq = dc.getConfiguration().seq; dc.sendNewConfiguration(); // Set to ready if no other change controls the ready state. But if there is, such as // if an activity is pausing, it will call setReady(ar, false) and wait for the next Loading @@ -2871,7 +2877,22 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { if (!mReadyTrackerOld.mUsed) { setReady(dc, true); } if (originalSeq == dc.getConfiguration().seq) continue; // If the update is deferred, sendNewConfiguration won't deliver new configuration to // clients, then it is the caller's responsibility to deliver the changes. if (mController.mAtm.mTaskSupervisor.isRootVisibilityUpdateDeferred()) { if (activitiesMayChange == null) { activitiesMayChange = new ArrayList<>(); } final ArrayList<ActivityRecord> visibleActivities = activitiesMayChange; dc.forAllActivities(r -> { if (r.isVisibleRequested()) { visibleActivities.add(r); } }); } } return activitiesMayChange; } boolean getLegacyIsReady() { Loading services/core/java/com/android/server/wm/WindowOrganizerController.java +19 −2 Original line number Diff line number Diff line Loading @@ -570,8 +570,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub mService.deferWindowLayout(); mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */); try { if (transition != null) { transition.applyDisplayChangeIfNeeded(); final ArrayList<ActivityRecord> activitiesMayChange = transition != null ? transition.applyDisplayChangeIfNeeded() : null; if (activitiesMayChange != null) { effects |= TRANSACT_EFFECTS_CLIENT_CONFIG; } final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps(); final int hopSize = hops.size(); Loading Loading @@ -695,8 +697,23 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub for (int i = haveConfigChanges.size() - 1; i >= 0; --i) { haveConfigChanges.valueAt(i).forAllActivities(r -> { r.ensureActivityConfiguration(0, PRESERVE_WINDOWS); if (activitiesMayChange != null) { activitiesMayChange.remove(r); } }); } // TODO(b/258618073): Combine with haveConfigChanges after confirming that there // is no problem to always preserve window. Currently this uses the parameters // as ATMS#ensureConfigAndVisibilityAfterUpdate. if (activitiesMayChange != null) { for (int i = activitiesMayChange.size() - 1; i >= 0; --i) { final ActivityRecord ar = activitiesMayChange.get(i); if (!ar.isVisibleRequested()) continue; ar.ensureActivityConfiguration(0 /* globalChanges */, !PRESERVE_WINDOWS, true /* ignoreVisibility */, false /* isRequestedOrientationChanged */); } } } if (effects != 0) { Loading services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +13 −10 Original line number Diff line number Diff line Loading @@ -2086,15 +2086,17 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testShellTransitRotation() { DisplayContent dc = createNewDisplay(); dc.setLastHasContent(); final DisplayContent dc = mDisplayContent; // Create 2 visible activities to verify that they can both receive the new configuration. final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build(); final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build(); doReturn(true).when(activity1).isSyncFinished(any()); doReturn(true).when(activity2).isSyncFinished(any()); final TestTransitionPlayer testPlayer = registerTestTransitionPlayer(); final DisplayRotation dr = dc.getDisplayRotation(); doCallRealMethod().when(dr).updateRotationUnchecked(anyBoolean()); // Rotate 180 degree so the display doesn't have configuration change. This condition is // used for the later verification of stop-freezing (without setting mWaitingForConfig). doReturn((dr.getRotation() + 2) % 4).when(dr).rotationForOrientation(anyInt(), anyInt()); spyOn(dr); doReturn((dr.getRotation() + 1) % 4).when(dr).rotationForOrientation(anyInt(), anyInt()); mWm.mDisplayChangeController = new IDisplayChangeWindowController.Stub() { @Override Loading @@ -2109,11 +2111,8 @@ public class DisplayContentTests extends WindowTestsBase { } }; // kill any existing rotation animation (vestigial from test setup). dc.setRotationAnimation(null); final int origRot = dc.getConfiguration().windowConfiguration.getRotation(); dc.setLastHasContent(); mWm.updateRotation(true /* alwaysSendConfiguration */, false /* forceRelayout */); // Should create a transition request without performing rotation assertNotNull(testPlayer.mLastRequest); Loading @@ -2122,6 +2121,10 @@ public class DisplayContentTests extends WindowTestsBase { // Once transition starts, rotation is applied and transition shows DC rotating. testPlayer.startTransition(); waitUntilHandlersIdle(); verify(activity1).ensureActivityConfiguration(anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); verify(activity2).ensureActivityConfiguration(anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); assertNotEquals(origRot, dc.getConfiguration().windowConfiguration.getRotation()); assertNotNull(testPlayer.mLastReady); assertTrue(testPlayer.mController.isPlaying()); Loading Loading
services/core/java/com/android/server/wm/ActivityTaskManagerService.java +3 −0 Original line number Diff line number Diff line Loading @@ -5280,6 +5280,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** Applies latest configuration and/or visibility updates if needed. */ boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) { if (starting == null && mTaskSupervisor.isRootVisibilityUpdateDeferred()) { return true; } boolean kept = true; final Task mainRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask(); // mainRootTask is null during startup. Loading
services/core/java/com/android/server/wm/Transition.java +23 −2 Original line number Diff line number Diff line Loading @@ -2857,12 +2857,18 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { return false; } /** Applies the new configuration for the changed displays. */ void applyDisplayChangeIfNeeded() { /** * Applies the new configuration for the changed displays. Returns the activities that should * check whether to deliver the new configuration to clients. */ @Nullable ArrayList<ActivityRecord> applyDisplayChangeIfNeeded() { ArrayList<ActivityRecord> activitiesMayChange = null; for (int i = mParticipants.size() - 1; i >= 0; --i) { final WindowContainer<?> wc = mParticipants.valueAt(i); final DisplayContent dc = wc.asDisplayContent(); if (dc == null || !mChanges.get(dc).hasChanged()) continue; final int originalSeq = dc.getConfiguration().seq; dc.sendNewConfiguration(); // Set to ready if no other change controls the ready state. But if there is, such as // if an activity is pausing, it will call setReady(ar, false) and wait for the next Loading @@ -2871,7 +2877,22 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { if (!mReadyTrackerOld.mUsed) { setReady(dc, true); } if (originalSeq == dc.getConfiguration().seq) continue; // If the update is deferred, sendNewConfiguration won't deliver new configuration to // clients, then it is the caller's responsibility to deliver the changes. if (mController.mAtm.mTaskSupervisor.isRootVisibilityUpdateDeferred()) { if (activitiesMayChange == null) { activitiesMayChange = new ArrayList<>(); } final ArrayList<ActivityRecord> visibleActivities = activitiesMayChange; dc.forAllActivities(r -> { if (r.isVisibleRequested()) { visibleActivities.add(r); } }); } } return activitiesMayChange; } boolean getLegacyIsReady() { Loading
services/core/java/com/android/server/wm/WindowOrganizerController.java +19 −2 Original line number Diff line number Diff line Loading @@ -570,8 +570,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub mService.deferWindowLayout(); mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */); try { if (transition != null) { transition.applyDisplayChangeIfNeeded(); final ArrayList<ActivityRecord> activitiesMayChange = transition != null ? transition.applyDisplayChangeIfNeeded() : null; if (activitiesMayChange != null) { effects |= TRANSACT_EFFECTS_CLIENT_CONFIG; } final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps(); final int hopSize = hops.size(); Loading Loading @@ -695,8 +697,23 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub for (int i = haveConfigChanges.size() - 1; i >= 0; --i) { haveConfigChanges.valueAt(i).forAllActivities(r -> { r.ensureActivityConfiguration(0, PRESERVE_WINDOWS); if (activitiesMayChange != null) { activitiesMayChange.remove(r); } }); } // TODO(b/258618073): Combine with haveConfigChanges after confirming that there // is no problem to always preserve window. Currently this uses the parameters // as ATMS#ensureConfigAndVisibilityAfterUpdate. if (activitiesMayChange != null) { for (int i = activitiesMayChange.size() - 1; i >= 0; --i) { final ActivityRecord ar = activitiesMayChange.get(i); if (!ar.isVisibleRequested()) continue; ar.ensureActivityConfiguration(0 /* globalChanges */, !PRESERVE_WINDOWS, true /* ignoreVisibility */, false /* isRequestedOrientationChanged */); } } } if (effects != 0) { Loading
services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +13 −10 Original line number Diff line number Diff line Loading @@ -2086,15 +2086,17 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testShellTransitRotation() { DisplayContent dc = createNewDisplay(); dc.setLastHasContent(); final DisplayContent dc = mDisplayContent; // Create 2 visible activities to verify that they can both receive the new configuration. final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build(); final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build(); doReturn(true).when(activity1).isSyncFinished(any()); doReturn(true).when(activity2).isSyncFinished(any()); final TestTransitionPlayer testPlayer = registerTestTransitionPlayer(); final DisplayRotation dr = dc.getDisplayRotation(); doCallRealMethod().when(dr).updateRotationUnchecked(anyBoolean()); // Rotate 180 degree so the display doesn't have configuration change. This condition is // used for the later verification of stop-freezing (without setting mWaitingForConfig). doReturn((dr.getRotation() + 2) % 4).when(dr).rotationForOrientation(anyInt(), anyInt()); spyOn(dr); doReturn((dr.getRotation() + 1) % 4).when(dr).rotationForOrientation(anyInt(), anyInt()); mWm.mDisplayChangeController = new IDisplayChangeWindowController.Stub() { @Override Loading @@ -2109,11 +2111,8 @@ public class DisplayContentTests extends WindowTestsBase { } }; // kill any existing rotation animation (vestigial from test setup). dc.setRotationAnimation(null); final int origRot = dc.getConfiguration().windowConfiguration.getRotation(); dc.setLastHasContent(); mWm.updateRotation(true /* alwaysSendConfiguration */, false /* forceRelayout */); // Should create a transition request without performing rotation assertNotNull(testPlayer.mLastRequest); Loading @@ -2122,6 +2121,10 @@ public class DisplayContentTests extends WindowTestsBase { // Once transition starts, rotation is applied and transition shows DC rotating. testPlayer.startTransition(); waitUntilHandlersIdle(); verify(activity1).ensureActivityConfiguration(anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); verify(activity2).ensureActivityConfiguration(anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); assertNotEquals(origRot, dc.getConfiguration().windowConfiguration.getRotation()); assertNotNull(testPlayer.mLastReady); assertTrue(testPlayer.mController.isPlaying()); Loading