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

Commit 170c6841 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Finish sync for activities under a drawn shared starting window

If a task contains multiple activities and the top one is translucent,
the task may not report sync finish even if the top activity is ready.
Because the activity behind is also visible, then the sync group still
needs to wait for it. But if the snapshot starting window has drawn,
the task should be covered by it. Then all visible activities belonging
to the task can be considered as ready to start transition.

This can also cover the case of hot launch of embedded activities.

Bug: 296817251
Bug: 317833037
Test: atest SyncEngineTests#testFinishSyncByStartingWindow
Test: Activity A starts translucent activity B in the same task
      and the same process. B will call sleep 1s in onResume.
      Return to Home and start the task of A. The transition
      should start in a short time by the starting window.
Change-Id: I3261f6b2137303ab3df16c836fc4c9dda6dfe338
parent b017819a
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -2507,7 +2507,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A

        ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SnapshotStartingData");
        mStartingData = new SnapshotStartingData(mWmService, snapshot, typeParams);
        if (task.forAllLeafTaskFragments(TaskFragment::isEmbedded)) {
        if ((!mStyleFillsParent && task.getChildCount() > 1)
                || task.forAllLeafTaskFragments(TaskFragment::isEmbedded)) {
            // Case 1:
            // If it is moving a Task{[0]=main activity, [1]=translucent activity} to front, use
            // shared starting window so that the transition doesn't need to wait for the activity
            // behind the translucent activity. Also, onFirstWindowDrawn will check all visible
            // activities are drawn in the task to remove the snapshot starting window.
            // Case 2:
            // Associate with the task so if this activity is resized by task fragment later, the
            // starting window can keep the same bounds as the task.
            associateStartingDataWithTask();
@@ -10642,6 +10649,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A

    @Override
    boolean isSyncFinished(BLASTSyncEngine.SyncGroup group) {
        if (task != null && task.mSharedStartingData != null) {
            final WindowState startingWin = task.topStartingWindow();
            if (startingWin != null && startingWin.isSyncFinished(group)) {
                // The sync is ready if a drawn starting window covered the task.
                return true;
            }
        }
        if (!super.isSyncFinished(group)) return false;
        if (mDisplayContent != null && mDisplayContent.mUnknownAppVisibilityController
                .isVisibilityUnknown(this)) {
+6 −5
Original line number Diff line number Diff line
@@ -1411,12 +1411,13 @@ class Task extends TaskFragment {
        return isUidPresent;
    }

    ActivityRecord topActivityContainsStartingWindow() {
        if (getParent() == null) {
            return null;
    WindowState topStartingWindow() {
        return getWindow(w -> w.mAttrs.type == TYPE_APPLICATION_STARTING);
    }
        return getActivity((r) -> r.getWindow(window ->
                window.getBaseType() == TYPE_APPLICATION_STARTING) != null);

    ActivityRecord topActivityContainsStartingWindow() {
        final WindowState startingWindow = topStartingWindow();
        return startingWindow != null ? startingWindow.mActivityRecord : null;
    }

    /**
+20 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.wm;

import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -136,6 +137,25 @@ public class SyncEngineTests extends WindowTestsBase {
        assertTrue(r.isSyncFinished(r.getSyncGroup()));
    }

    @Test
    public void testFinishSyncByStartingWindow() {
        final ActivityRecord taskRoot = new ActivityBuilder(mAtm).setCreateTask(true).build();
        final Task task = taskRoot.getTask();
        final ActivityRecord translucentTop = new ActivityBuilder(mAtm).setTask(task)
                .setActivityTheme(android.R.style.Theme_Translucent).build();
        createWindow(null, TYPE_BASE_APPLICATION, taskRoot, "win");
        final WindowState startingWindow = createWindow(null, TYPE_APPLICATION_STARTING,
                translucentTop, "starting");
        startingWindow.mStartingData = new SnapshotStartingData(mWm, null, 0);
        task.mSharedStartingData = startingWindow.mStartingData;
        task.prepareSync();

        final BLASTSyncEngine.SyncGroup group = mock(BLASTSyncEngine.SyncGroup.class);
        assertFalse(task.isSyncFinished(group));
        startingWindow.onSyncFinishedDrawing();
        assertTrue(task.isSyncFinished(group));
    }

    @Test
    public void testInvisibleSyncCallback() {
        TestWindowContainer mockWC = new TestWindowContainer(mWm, true /* waiter */);