diff options
| author | 2021-10-08 18:37:53 +0000 | |
|---|---|---|
| committer | 2021-10-08 18:37:53 +0000 | |
| commit | 4097e44f2a4ca1611b600bd7d8c21c723784c8d7 (patch) | |
| tree | 4b8468818635ee56ff89d810adb38d3aefe079b4 | |
| parent | 7a8f7189e25049d20f9211d2c8341c869219e7c2 (diff) | |
| parent | 9a5b9ad6f446b2902284c7cbcb21a6b1bf68f535 (diff) | |
Merge "Port IME tasksnapshot over to shell transitions" into sc-v2-dev
7 files changed, 153 insertions, 43 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 68bc925c1a67..394ff755d252 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -4890,8 +4890,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * @param visible {@code true} if this {@link ActivityRecord} should become visible, otherwise * this should become invisible. * @param performLayout if {@code true}, perform surface placement after committing visibility. + * @param fromTransition {@code true} if this is part of finishing a transition. */ - void commitVisibility(boolean visible, boolean performLayout) { + void commitVisibility(boolean visible, boolean performLayout, boolean fromTransition) { // Reset the state of mVisibleSetFromTransferredStartingWindow since visibility is actually // been set by the app now. mVisibleSetFromTransferredStartingWindow = false; @@ -4941,7 +4942,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/); mUseTransferredAnimation = false; - postApplyAnimation(visible); + postApplyAnimation(visible, fromTransition); + } + + void commitVisibility(boolean visible, boolean performLayout) { + commitVisibility(visible, performLayout, false /* fromTransition */); } /** @@ -4952,8 +4957,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * * @param visible {@code true} if this {@link ActivityRecord} has become visible, otherwise * this has become invisible. + * @param fromTransition {@code true} if this call is part of finishing a transition. This is + * needed because the shell transition is no-longer active by the time + * commitVisibility is called. */ - private void postApplyAnimation(boolean visible) { + private void postApplyAnimation(boolean visible, boolean fromTransition) { final boolean usingShellTransitions = mTransitionController.isShellTransitionsEnabled(); final boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN, ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION @@ -4994,7 +5002,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final DisplayContent displayContent = getDisplayContent(); if (!displayContent.mClosingApps.contains(this) - && !displayContent.mOpeningApps.contains(this)) { + && !displayContent.mOpeningApps.contains(this) + && !fromTransition) { // Take the screenshot before possibly hiding the WSA, otherwise the screenshot // will not be taken. mWmService.mTaskSnapshotController.notifyAppVisibilityChanged(this, visible); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index a4f188c7ad74..60a514e4d612 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -991,6 +991,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { synchronized (mGlobalLock) { mWindowManager = wm; mRootWindowContainer = wm.mRoot; + mWindowOrganizerController.setWindowManager(wm); mTempConfig.setToDefaults(); mTempConfig.setLocales(LocaleList.getDefault()); mConfigurationSeq = mTempConfig.seq = 1; diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 5ce9938ff71d..ce93f2495c22 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -178,46 +178,49 @@ class TaskSnapshotController { snapshotTasks(tasks, false /* allowSnapshotHome */); } - private void snapshotTasks(ArraySet<Task> tasks, boolean allowSnapshotHome) { - for (int i = tasks.size() - 1; i >= 0; i--) { - final Task task = tasks.valueAt(i); - final TaskSnapshot snapshot; - final boolean snapshotHome = allowSnapshotHome && task.isActivityTypeHome(); - if (snapshotHome) { - snapshot = snapshotTask(task); - } else { - switch (getSnapshotMode(task)) { - case SNAPSHOT_MODE_NONE: - continue; - case SNAPSHOT_MODE_APP_THEME: - snapshot = drawAppThemeSnapshot(task); - break; - case SNAPSHOT_MODE_REAL: - snapshot = snapshotTask(task); - break; - default: - snapshot = null; - break; - } + void recordTaskSnapshot(Task task, boolean allowSnapshotHome) { + final TaskSnapshot snapshot; + final boolean snapshotHome = allowSnapshotHome && task.isActivityTypeHome(); + if (snapshotHome) { + snapshot = snapshotTask(task); + } else { + switch (getSnapshotMode(task)) { + case SNAPSHOT_MODE_NONE: + return; + case SNAPSHOT_MODE_APP_THEME: + snapshot = drawAppThemeSnapshot(task); + break; + case SNAPSHOT_MODE_REAL: + snapshot = snapshotTask(task); + break; + default: + snapshot = null; + break; } - if (snapshot != null) { - final HardwareBuffer buffer = snapshot.getHardwareBuffer(); - if (buffer.getWidth() == 0 || buffer.getHeight() == 0) { - buffer.close(); - Slog.e(TAG, "Invalid task snapshot dimensions " + buffer.getWidth() + "x" - + buffer.getHeight()); - } else { - mCache.putSnapshot(task, snapshot); - // Don't persist or notify the change for the temporal snapshot. - if (!snapshotHome) { - mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot); - task.onSnapshotChanged(snapshot); - } + } + if (snapshot != null) { + final HardwareBuffer buffer = snapshot.getHardwareBuffer(); + if (buffer.getWidth() == 0 || buffer.getHeight() == 0) { + buffer.close(); + Slog.e(TAG, "Invalid task snapshot dimensions " + buffer.getWidth() + "x" + + buffer.getHeight()); + } else { + mCache.putSnapshot(task, snapshot); + // Don't persist or notify the change for the temporal snapshot. + if (!snapshotHome) { + mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot); + task.onSnapshotChanged(snapshot); } } } } + private void snapshotTasks(ArraySet<Task> tasks, boolean allowSnapshotHome) { + for (int i = tasks.size() - 1; i >= 0; i--) { + recordTaskSnapshot(tasks.valueAt(i), allowSnapshotHome); + } + } + /** * Retrieves a snapshot. If {@param restoreFromDisk} equals {@code true}, DO NOT HOLD THE WINDOW * MANAGER LOCK WHEN CALLING THIS METHOD! diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index e50e8ef56778..e537c0afc147 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -415,7 +415,16 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe if (commitVisibility) { ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " Commit activity becoming invisible: %s", ar); - ar.commitVisibility(false /* visible */, false /* performLayout */); + final Task task = ar.getTask(); + if (task != null && !task.isVisibleRequested() + && mTransientLaunches != null) { + // If transition is transient, then snapshots are taken at end of + // transition. + mController.mTaskSnapshotController.recordTaskSnapshot( + task, false /* allowSnapshotHome */); + } + ar.commitVisibility(false /* visible */, false /* performLayout */, + true /* fromTransition */); activitiesWentInvisible = true; } } @@ -558,6 +567,19 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe mVisibleAtTransitionEndTokens.add(wc.asWindowToken()); } + // Take task snapshots before the animation so that we can capture IME before it gets + // transferred. If transition is transient, IME won't be moved during the transition and + // the tasks are still live, so we take the snapshot at the end of the transition instead. + if (mTransientLaunches == null) { + for (int i = mParticipants.size() - 1; i >= 0; --i) { + final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord(); + if (ar == null || ar.isVisibleRequested() || ar.getTask() == null + || ar.getTask().isVisibleRequested()) continue; + mController.mTaskSnapshotController.recordTaskSnapshot( + ar.getTask(), false /* allowSnapshotHome */); + } + } + mStartTransaction = transaction; mFinishTransaction = mController.mAtm.mWindowManager.mTransactionFactory.get(); buildFinishTransaction(mFinishTransaction, info.getRootLeash()); diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index fc5423942dc3..ff4cc3d1b784 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -59,6 +59,7 @@ class TransitionController { private ITransitionPlayer mTransitionPlayer; final ActivityTaskManagerService mAtm; + final TaskSnapshotController mTaskSnapshotController; private final ArrayList<WindowManagerInternal.AppTransitionListener> mLegacyListeners = new ArrayList<>(); @@ -79,9 +80,11 @@ class TransitionController { // TODO(b/188595497): remove when not needed. final StatusBarManagerInternal mStatusBar; - TransitionController(ActivityTaskManagerService atm) { + TransitionController(ActivityTaskManagerService atm, + TaskSnapshotController taskSnapshotController) { mAtm = atm; mStatusBar = LocalServices.getService(StatusBarManagerInternal.class); + mTaskSnapshotController = taskSnapshotController; mTransitionPlayerDeath = () -> { synchronized (mAtm.mGlobalLock) { // Clean-up/finish any playing transitions. diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 781b53df998e..54ce5fc6bbec 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -117,7 +117,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final DisplayAreaOrganizerController mDisplayAreaOrganizerController; final TaskFragmentOrganizerController mTaskFragmentOrganizerController; - final TransitionController mTransitionController; + TransitionController mTransitionController; /** * A Map which manages the relationship between * {@link TaskFragmentCreationParams#getFragmentToken()} and {@link TaskFragment} @@ -131,7 +131,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub mTaskOrganizerController = new TaskOrganizerController(mService); mDisplayAreaOrganizerController = new DisplayAreaOrganizerController(mService); mTaskFragmentOrganizerController = new TaskFragmentOrganizerController(atm); - mTransitionController = new TransitionController(atm); + } + + void setWindowManager(WindowManagerService wms) { + mTransitionController = new TransitionController(mService, wms.mTaskSnapshotController); } TransitionController getTransitionController() { diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index 6d60bcf1fce6..a1c24c26af35 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -34,8 +34,11 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import android.os.IBinder; import android.platform.test.annotations.Presubmit; @@ -448,7 +451,8 @@ public class TransitionTests extends WindowTestsBase { @Test public void testIntermediateVisibility() { - final TransitionController controller = new TransitionController(mAtm); + final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class); + final TransitionController controller = new TransitionController(mAtm, snapshotController); final ITransitionPlayer player = new ITransitionPlayer.Default(); controller.registerTransitionPlayer(player); ITaskOrganizer mockOrg = mock(ITaskOrganizer.class); @@ -511,6 +515,71 @@ public class TransitionTests extends WindowTestsBase { assertTrue(activity2.isVisible()); } + @Test + public void testTransientLaunch() { + final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class); + final TransitionController controller = new TransitionController(mAtm, snapshotController); + final ITransitionPlayer player = new ITransitionPlayer.Default(); + controller.registerTransitionPlayer(player); + ITaskOrganizer mockOrg = mock(ITaskOrganizer.class); + final Transition openTransition = controller.createTransition(TRANSIT_OPEN); + + // Start out with task2 visible and set up a transition that closes task2 and opens task1 + final Task task1 = createTask(mDisplayContent); + task1.mTaskOrganizer = mockOrg; + final ActivityRecord activity1 = createActivityRecord(task1); + activity1.mVisibleRequested = false; + activity1.setVisible(false); + final Task task2 = createTask(mDisplayContent); + task2.mTaskOrganizer = mockOrg; + final ActivityRecord activity2 = createActivityRecord(task2); + activity2.mVisibleRequested = true; + activity2.setVisible(true); + + openTransition.collectExistenceChange(task1); + openTransition.collectExistenceChange(activity1); + openTransition.collectExistenceChange(task2); + openTransition.collectExistenceChange(activity2); + + activity1.mVisibleRequested = true; + activity1.setVisible(true); + activity2.mVisibleRequested = false; + + // Using abort to force-finish the sync (since we can't wait for drawing in unit test). + // We didn't call abort on the transition itself, so it will still run onTransactionReady + // normally. + mWm.mSyncEngine.abort(openTransition.getSyncId()); + + verify(snapshotController, times(1)).recordTaskSnapshot(eq(task2), eq(false)); + + openTransition.finishTransition(); + + // We are now going to simulate closing task1 to return back to (open) task2. + final Transition closeTransition = controller.createTransition(TRANSIT_CLOSE); + + closeTransition.collectExistenceChange(task1); + closeTransition.collectExistenceChange(activity1); + closeTransition.collectExistenceChange(task2); + closeTransition.collectExistenceChange(activity2); + closeTransition.setTransientLaunch(activity2); + + activity1.mVisibleRequested = false; + activity2.mVisibleRequested = true; + + // Using abort to force-finish the sync (since we obviously can't wait for drawing). + // We didn't call abort on the actual transition, so it will still run onTransactionReady + // normally. + mWm.mSyncEngine.abort(closeTransition.getSyncId()); + + // Make sure we haven't called recordSnapshot (since we are transient, it shouldn't be + // called until finish). + verify(snapshotController, times(0)).recordTaskSnapshot(eq(task1), eq(false)); + + closeTransition.finishTransition(); + + verify(snapshotController, times(1)).recordTaskSnapshot(eq(task1), eq(false)); + } + /** Fill the change map with all the parents of top. Change maps are usually fully populated */ private static void fillChangeMap(ArrayMap<WindowContainer, Transition.ChangeInfo> changes, WindowContainer top) { |