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

Commit a532d89f authored by Nick Chameyev's avatar Nick Chameyev Committed by Android (Google) Code Review
Browse files

Merge "[Fold/unfold] Wait for the present fence of Shell transition's start transaction" into main

parents e3dcd019 39e7fdc5
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -29,6 +29,16 @@ flag {
  }
}

flag {
  name: "wait_for_present_fence_on_display_switch"
  namespace: "windowing_frontend"
  description: "Wait for start transaction's present fence when folding/unfolding"
  bug: "370719724"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}

flag {
  name: "enforce_edge_to_edge"
  is_exported: true
+2 −2
Original line number Diff line number Diff line
@@ -294,7 +294,7 @@ class DeferredDisplayUpdater {
                getCurrentDisplayChange(fromRotation, startBounds);
        displayChange.setPhysicalDisplayChanged(true);

        transition.addTransactionCompletedListener(this::continueScreenUnblocking);
        transition.addTransactionPresentedListener(this::continueScreenUnblocking);
        mDisplayContent.mTransitionController.requestStartTransition(transition,
                /* startTask= */ null, /* remoteTransition= */ null, displayChange);

@@ -366,7 +366,7 @@ class DeferredDisplayUpdater {

    /**
     * Continues the screen unblocking flow, could be called either on a binder thread as
     * a result of surface transaction completed listener or from {@link WindowManagerService#mH}
     * a result of surface transaction presented listener or from {@link WindowManagerService#mH}
     * handler in case of timeout
     */
    private void continueScreenUnblocking() {
+57 −12
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.hardware.SyncFence.SIGNAL_TIME_PENDING;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
@@ -95,6 +96,7 @@ import android.content.pm.ActivityInfo;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.hardware.SyncFence;
import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
@@ -134,6 +136,7 @@ import com.android.window.flags.Flags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -265,8 +268,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
     */
    private ArrayList<Task> mTransientHideTasks;

    private static final Duration TRANSACTION_PRESENTED_TIMEOUT = Duration.ofSeconds(1);

    @VisibleForTesting
    ArrayList<Runnable> mTransactionCompletedListeners = null;
    ArrayList<Runnable> mTransactionPresentedListeners = null;

    private ArrayList<Runnable> mTransitionEndedListeners = null;

@@ -1911,13 +1916,17 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
        commitVisibleActivities(transaction);
        commitVisibleWallpapers(transaction);

        if (mTransactionCompletedListeners != null) {
            for (int i = 0; i < mTransactionCompletedListeners.size(); i++) {
                final Runnable listener = mTransactionCompletedListeners.get(i);
                transaction.addTransactionCompletedListener(Runnable::run,
                        (stats) -> listener.run());
        if (mTransactionPresentedListeners != null) {
            final List<Runnable> transactionPresentedListeners =
                    new ArrayList<>(mTransactionPresentedListeners);

            addTransactionPresentedCallback(transaction, () -> {
                for (int i = 0; i < transactionPresentedListeners.size(); i++) {
                    transactionPresentedListeners.get(i).run();
                }
            mTransactionCompletedListeners = null;
            });

            mTransactionPresentedListeners = null;
        }

        // Fall-back to the default display if there isn't one participating.
@@ -2266,11 +2275,11 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
     * Adds a listener that will be executed after the start transaction of this transition
     * is presented on the screen, the listener will be executed on a binder thread
     */
    void addTransactionCompletedListener(Runnable listener) {
        if (mTransactionCompletedListeners == null) {
            mTransactionCompletedListeners = new ArrayList<>();
    void addTransactionPresentedListener(Runnable listener) {
        if (mTransactionPresentedListeners == null) {
            mTransactionPresentedListeners = new ArrayList<>();
        }
        mTransactionCompletedListeners.add(listener);
        mTransactionPresentedListeners.add(listener);
    }

    /**
@@ -2287,6 +2296,42 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
        mTransitionEndedListeners.add(listener);
    }

    private void addTransactionPresentedCallback(SurfaceControl.Transaction transaction,
            Runnable onPresented) {
        transaction.addTransactionCompletedListener(Runnable::run,
                (stats) -> {
                    if (com.android.window.flags.Flags.waitForPresentFenceOnDisplaySwitch()) {
                        final SyncFence fence = stats.getPresentFence();
                        waitForPresentFence(fence, onPresented);
                    } else {
                        onPresented.run();
                    }
                });
    }

    private void waitForPresentFence(SyncFence fence, Runnable onPresented) {
        try {
            if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
                Trace.beginSection("Awaiting for the present fence");
            }

            fence.await(TRANSACTION_PRESENTED_TIMEOUT);
        } finally {
            if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
                Trace.endSection();
            }

            onPresented.run();

            final long signalTime = fence.getSignalTime();
            if (signalTime == SIGNAL_TIME_PENDING) {
                Slog.e(TAG, "Timeout occurred when waiting for the transaction "
                        + "to be presented");
            }
            fence.close();
        }
    }

    /**
     * Checks if the transition contains order changes.
     *
+6 −6
Original line number Diff line number Diff line
@@ -231,7 +231,7 @@ public class DisplayContentDeferredUpdateTests extends WindowTestsBase {

        when(mDisplayContent.mTransitionController.inTransition()).thenReturn(false);
        final Transition transition = captureRequestedTransition().getValue();
        makeTransitionTransactionCompleted(transition);
        makeTransitionTransactionPresented(transition);

        // Verify that screen is unblocked as start transaction of the transition
        // has been completed
@@ -308,7 +308,7 @@ public class DisplayContentDeferredUpdateTests extends WindowTestsBase {
        // Mark start transactions as presented
        when(mDisplayContent.mTransitionController.inTransition()).thenReturn(false);
        captureRequestedTransition().getAllValues().forEach(
                this::makeTransitionTransactionCompleted);
                this::makeTransitionTransactionPresented);

        // Verify that the default screen unblocker is sent only after start transaction
        // of the Shell transition is presented
@@ -355,10 +355,10 @@ public class DisplayContentDeferredUpdateTests extends WindowTestsBase {
        return callbackCaptor;
    }

    private void makeTransitionTransactionCompleted(Transition transition) {
        if (transition.mTransactionCompletedListeners != null) {
            for (int i = 0; i < transition.mTransactionCompletedListeners.size(); i++) {
                final Runnable listener = transition.mTransactionCompletedListeners.get(i);
    private void makeTransitionTransactionPresented(Transition transition) {
        if (transition.mTransactionPresentedListeners != null) {
            for (int i = 0; i < transition.mTransactionPresentedListeners.size(); i++) {
                final Runnable listener = transition.mTransactionPresentedListeners.get(i);
                listener.run();
            }
        }