Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 73aab1dc authored by Ming-Shin Lu's avatar Ming-Shin Lu
Browse files

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
parent ae31181f
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -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
+4 −8
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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++;
+12 −3
Original line number Diff line number Diff line
@@ -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);
                        }
                    });
+20 −0
Original line number Diff line number Diff line
@@ -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)