diff options
| author | 2020-09-14 12:35:41 +0800 | |
|---|---|---|
| committer | 2020-10-23 13:25:34 +0800 | |
| commit | 73aab1dc1fce55a544f5ecffe1c4cb7939d77be9 (patch) | |
| tree | fc975885363b75ef5df08440a87eebab8a531900 | |
| parent | ae31181f133dba251225d95169d95ee1574599af (diff) | |
Better IME transition while switching app with recents (2/N)
In TaskSnapshotController#handleClosingApps will capture task snapshot
while applying closing animation or during screen turning-off.
this will overwrite the captured task from RecentsAnimationController,
and makes while quick switching tasks, sometimes will not see the IME
surface on the task snapshot.
Add a check in places which triggers task snapshot to ignore addidnal
snapshot request while RecentsAnimation is active.
Also refined Task#isTaskAnimating as isAnimatingByRecents to simplify
the logic and add the test for its behavior.
Bug: 166736352
Test: manual by:
1) Tapping EditText in app and make keyboard shown
2) Quick switch back and force between apps by swiping navbar
3) Verify if the task snapshot with IME persists shown during
switching apps
Test: atest RecentsAnimationControllerTest#testIsAnimatingByRecents
Change-Id: Icc7abd3338f472e263042f46502615f0446b46eb
5 files changed, 42 insertions, 13 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index aea944cd52d3..9df31d6d0c5e 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2590,7 +2590,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // When finishing the activity preemptively take the snapshot before the app window // is marked as hidden and any configuration changes take place - if (mAtmService.mWindowManager.mTaskSnapshotController != null) { + // Note that RecentsAnimation will handle task snapshot while switching apps with + // the best capture timing (e.g. IME window capture), + // No need additional task capture while task is controlled by RecentsAnimation. + if (mAtmService.mWindowManager.mTaskSnapshotController != null + && !task.isAnimatingByRecents()) { final ArraySet<Task> tasks = Sets.newArraySet(task); mAtmService.mWindowManager.mTaskSnapshotController.snapshotTasks(tasks); mAtmService.mWindowManager.mTaskSnapshotController diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index ecee46e895d0..e584d8cf45dd 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -114,6 +114,7 @@ import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_ import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; import static com.android.server.wm.IdentifierProto.USER_ID; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.Task.ActivityState.PAUSED; import static com.android.server.wm.Task.ActivityState.PAUSING; import static com.android.server.wm.Task.ActivityState.RESUMED; @@ -3661,14 +3662,9 @@ class Task extends WindowContainer<WindowContainer> { super.setInitialSurfaceControlProperties(b); } - boolean isTaskAnimating() { - final RecentsAnimationController recentsAnim = mWmService.getRecentsAnimationController(); - if (recentsAnim != null) { - if (recentsAnim.isAnimatingTask(this)) { - return true; - } - } - return forAllTasks((t) -> { return t != this && t.isTaskAnimating(); }); + /** Checking if self or its child tasks are animated by recents animation. */ + boolean isAnimatingByRecents() { + return isAnimating(CHILDREN, ANIMATION_TYPE_RECENTS); } @Override diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 830ad5d6043b..da68ebbc4ecf 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -754,7 +754,7 @@ final class TaskDisplayArea extends DisplayArea<Task> { // The split screen divider anchor is located above the split screen window. mTmpLayerForSplitScreenDividerAnchor = layer++; } - if (s.isTaskAnimating() || s.isAppTransitioning()) { + if (s.isAnimatingByRecents() || s.isAppTransitioning()) { // The animation layer is located above the highest animating stack and no // higher. mTmpLayerForAnimationLayer = layer++; diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 01adb8b35c3b..3ce04aff5301 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -157,7 +157,6 @@ class TaskSnapshotController { if (shouldDisableSnapshots()) { return; } - // We need to take a snapshot of the task if and only if all activities of the task are // either closing or hidden. getClosingTasks(closingApps, mTmpTasks); @@ -445,10 +444,17 @@ class TaskSnapshotController { for (int i = closingApps.size() - 1; i >= 0; i--) { final ActivityRecord activity = closingApps.valueAt(i); final Task task = activity.getTask(); + if (task == null) continue; + // Since RecentsAnimation will handle task snapshot while switching apps with the + // best capture timing (e.g. IME window capture), + // No need additional task capture while task is controlled by RecentsAnimation. + if (task.isAnimatingByRecents()) { + mSkipClosingAppSnapshotTasks.add(task); + } // If the task of the app is not visible anymore, it means no other app in that task // is opening. Thus, the task is closing. - if (task != null && !task.isVisible() && !mSkipClosingAppSnapshotTasks.contains(task)) { + if (!task.isVisible() && !mSkipClosingAppSnapshotTasks.contains(task)) { outClosingTasks.add(task); } } @@ -571,7 +577,10 @@ class TaskSnapshotController { synchronized (mService.mGlobalLock) { mTmpTasks.clear(); mService.mRoot.forAllTasks(task -> { - if (task.isVisible()) { + // Since RecentsAnimation will handle task snapshot while switching apps + // with the best capture timing (e.g. IME window capture), No need + // additional task capture while task is controlled by RecentsAnimation. + if (task.isVisible() && !task.isAnimatingByRecents()) { mTmpTasks.add(task); } }); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index 7fb7d40f0bd2..2985796d005f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -476,6 +476,26 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { assertFalse(wallpaperWindowToken.hasFixedRotationTransform()); } + @Test + public void testIsAnimatingByRecents() { + final ActivityRecord homeActivity = createHomeActivity(); + final Task rootTask = createTaskStackOnDisplay(mDefaultDisplay); + final Task childTask = createTaskInStack(rootTask, 0 /* userId */); + final Task leafTask = createTaskInStack(childTask, 0 /* userId */); + spyOn(leafTask); + doReturn(true).when(leafTask).isVisible(); + + initializeRecentsAnimationController(mController, homeActivity); + + // Verify RecentsAnimationController will animate visible leaf task by default. + verify(mController).addAnimation(eq(leafTask), anyBoolean(), anyBoolean(), eq(null)); + assertTrue(leafTask.isAnimatingByRecents()); + + // Make sure isAnimatingByRecents will also return true when it called by the parent task. + assertTrue(rootTask.isAnimatingByRecents()); + assertTrue(childTask.isAnimatingByRecents()); + } + private ActivityRecord createHomeActivity() { final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService) .setStack(mRootHomeTask) |