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

Commit 381743d2 authored by Chavi Weingarten's avatar Chavi Weingarten Committed by Android (Google) Code Review
Browse files

Merge "Remove consumeNextDraw and replace with SurfaceSyncer" into tm-dev

parents e70333a5 a2e1f448
Loading
Loading
Loading
Loading
+9 −55
Original line number Diff line number Diff line
@@ -228,7 +228,6 @@ import java.util.List;
import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer;

/**
 * The top of a view hierarchy, implementing the needed protocol between View
@@ -827,8 +826,6 @@ public final class ViewRootImpl implements ViewParent,
     */
    private long mRtLastAttemptedDrawFrameNum = 0;

    private Consumer<SurfaceControl.Transaction> mBLASTDrawConsumer;

    private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks;

    private long mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
@@ -3492,36 +3489,24 @@ public final class ViewRootImpl implements ViewParent,
    }

    private void createSyncIfNeeded() {
        // Started a sync already.
        if (mLastSyncId != -1) {
        // Started a sync already or there's nothing needing to sync
        if (mLastSyncId != -1 || !mReportNextDraw) {
            return;
        }

        Consumer<Transaction> syncConsumer = null;
        final int seqId = mSyncSeqId;

        if (mBLASTDrawConsumer != null) {
            syncConsumer = mBLASTDrawConsumer;
            mBLASTDrawConsumer = null;
        } else if (mReportNextDraw) {
            syncConsumer = transaction -> {
                mSurfaceChangedTransaction.merge(transaction);
                reportDrawFinished(seqId);
            };
        }

        if (syncConsumer != null) {
            final Consumer<Transaction> capturedSyncConsumer = syncConsumer;
        mLastSyncId = mSurfaceSyncer.setupSync(transaction -> {
            // Callback will be invoked on executor thread so post to main thread.
                mHandler.postAtFrontOfQueue(() -> capturedSyncConsumer.accept(transaction));
            mHandler.postAtFrontOfQueue(() -> {
                mSurfaceChangedTransaction.merge(transaction);
                reportDrawFinished(seqId);
            });
        });
        if (DEBUG_BLAST) {
            Log.d(mTag, "Setup new sync id=" + mLastSyncId);
        }
        mSurfaceSyncer.addToSync(mLastSyncId, mSyncTarget);
    }
    }

    private void notifyContentCatpureEvents() {
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureEvents");
@@ -10774,37 +10759,6 @@ public final class ViewRootImpl implements ViewParent,
                showControl, transformationApplied, callback);
    }

    /**
     * Redirect the next draw of this ViewRoot (from the UI thread perspective)
     * to the passed in consumer. This can be used to create P2P synchronization
     * between ViewRoot's however it comes with many caveats.
     *
     * 1. You MUST consume the transaction, by either applying it immediately or
     *    merging it in to another transaction. The threading model doesn't
     *    allow you to hold in the passed transaction.
     * 2. If you merge it in to another transaction, this ViewRootImpl will be
     *    paused until you finally apply that transaction and it receives
     *    the callback from SF. If you lose track of the transaction you will
     *    ANR the app.
     * 3. Only one person can consume the transaction at a time, if you already
     *    have a pending consumer for this frame, the function will return false
     * 4. Someone else may have requested to consume the next frame, in which case
     *    this function will return false and you will not receive a callback.
     * 5. This function does not trigger drawing so even if it returns true you
     *    may not receive a callback unless there is some other UI thread work
     *    to trigger drawing. If it returns true, and a draw occurs, the callback
     *    will be called (Though again watch out for the null transaction case!)
     * 6. This function must be called on the UI thread. The consumer will likewise
     *    be called on the UI thread.
     */
    public boolean consumeNextDraw(Consumer<SurfaceControl.Transaction> consume) {
       if (mBLASTDrawConsumer != null) {
           return false;
       }
       mBLASTDrawConsumer = consume;
       return true;
    }

    boolean wasRelayoutRequested() {
        return mRelayoutRequested;
    }
+7 −31
Original line number Diff line number Diff line
package com.android.systemui.animation

import android.app.ActivityManager
import android.view.SurfaceControl
import android.view.View
import android.view.ViewRootImpl
import android.window.SurfaceSyncer

/** A util class to synchronize 2 view roots. */
// TODO(b/200284684): Remove this class.
object ViewRootSync {
    // TODO(b/217621394): Remove special handling for low-RAM devices after animation sync is fixed
    private val forceDisableSynchronization = ActivityManager.isLowRamDeviceStatic()
    private var surfaceSyncer: SurfaceSyncer? = null

    /**
     * Synchronize the next draw between the view roots of [view] and [otherView], then run [then].
@@ -33,35 +33,11 @@ object ViewRootSync {
            return
        }

        // Consume the next frames of both view roots to make sure the ghost view is drawn at
        // exactly the same time as when the touch surface is made invisible.
        var remainingTransactions = 0
        val mergedTransactions = SurfaceControl.Transaction()

        fun onTransaction(transaction: SurfaceControl.Transaction?) {
            remainingTransactions--
            transaction?.let { mergedTransactions.merge(it) }

            if (remainingTransactions == 0) {
                mergedTransactions.apply()
                then()
            }
        }

        fun consumeNextDraw(viewRootImpl: ViewRootImpl) {
            if (viewRootImpl.consumeNextDraw(::onTransaction)) {
                remainingTransactions++

                // Make sure we trigger a traversal.
                viewRootImpl.view.invalidate()
            }
        }

        consumeNextDraw(view.viewRootImpl)
        consumeNextDraw(otherView.viewRootImpl)

        if (remainingTransactions == 0) {
            then()
        surfaceSyncer = SurfaceSyncer().apply {
            val syncId = setupSync(Runnable { then() })
            addToSync(syncId, view)
            addToSync(syncId, otherView)
            markSyncReady(syncId)
        }
    }