Loading core/java/android/view/ViewRootImpl.java +43 −0 Original line number Original line Diff line number Diff line Loading @@ -211,6 +211,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.io.StringWriter; import java.lang.ref.WeakReference; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.ArrayList; import java.util.function.Consumer; import java.util.HashSet; import java.util.HashSet; import java.util.LinkedList; import java.util.LinkedList; import java.util.List; import java.util.List; Loading Loading @@ -742,6 +743,8 @@ public final class ViewRootImpl implements ViewParent, */ */ private long mRtLastAttemptedDrawFrameNum = 0; private long mRtLastAttemptedDrawFrameNum = 0; private Consumer<SurfaceControl.Transaction> mBLASTDrawConsumer; private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks; private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks; private long mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS; private long mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS; Loading Loading @@ -3259,6 +3262,9 @@ public final class ViewRootImpl implements ViewParent, } } boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible; boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible; if (mBLASTDrawConsumer != null) { useBlastSync = true; } if (!cancelDraw) { if (!cancelDraw) { if (mPendingTransitions != null && mPendingTransitions.size() > 0) { if (mPendingTransitions != null && mPendingTransitions.size() > 0) { Loading Loading @@ -3977,6 +3983,9 @@ public final class ViewRootImpl implements ViewParent, Log.d(mTag, "Creating frameCompleteCallback"); Log.d(mTag, "Creating frameCompleteCallback"); } } final Consumer<SurfaceControl.Transaction> blastSyncConsumer = mBLASTDrawConsumer; mBLASTDrawConsumer = null; mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(() -> { mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(() -> { long frameNr = mBlastBufferQueue.getLastAcquiredFrameNum(); long frameNr = mBlastBufferQueue.getLastAcquiredFrameNum(); if (DEBUG_BLAST) { if (DEBUG_BLAST) { Loading @@ -4002,6 +4011,9 @@ public final class ViewRootImpl implements ViewParent, mHandler.postAtFrontOfQueue(() -> { mHandler.postAtFrontOfQueue(() -> { if (useBlastSync) { if (useBlastSync) { mSurfaceChangedTransaction.merge(tmpTransaction); mSurfaceChangedTransaction.merge(tmpTransaction); if (blastSyncConsumer != null) { blastSyncConsumer.accept(mSurfaceChangedTransaction); } } } if (reportNextDraw) { if (reportNextDraw) { Loading Loading @@ -10457,4 +10469,35 @@ public final class ViewRootImpl implements ViewParent, listener.onBufferTransformHintChanged(hint); listener.onBufferTransformHintChanged(hint); } } } } /** * 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; } } } Loading
core/java/android/view/ViewRootImpl.java +43 −0 Original line number Original line Diff line number Diff line Loading @@ -211,6 +211,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.io.StringWriter; import java.lang.ref.WeakReference; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.ArrayList; import java.util.function.Consumer; import java.util.HashSet; import java.util.HashSet; import java.util.LinkedList; import java.util.LinkedList; import java.util.List; import java.util.List; Loading Loading @@ -742,6 +743,8 @@ public final class ViewRootImpl implements ViewParent, */ */ private long mRtLastAttemptedDrawFrameNum = 0; private long mRtLastAttemptedDrawFrameNum = 0; private Consumer<SurfaceControl.Transaction> mBLASTDrawConsumer; private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks; private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks; private long mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS; private long mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS; Loading Loading @@ -3259,6 +3262,9 @@ public final class ViewRootImpl implements ViewParent, } } boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible; boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible; if (mBLASTDrawConsumer != null) { useBlastSync = true; } if (!cancelDraw) { if (!cancelDraw) { if (mPendingTransitions != null && mPendingTransitions.size() > 0) { if (mPendingTransitions != null && mPendingTransitions.size() > 0) { Loading Loading @@ -3977,6 +3983,9 @@ public final class ViewRootImpl implements ViewParent, Log.d(mTag, "Creating frameCompleteCallback"); Log.d(mTag, "Creating frameCompleteCallback"); } } final Consumer<SurfaceControl.Transaction> blastSyncConsumer = mBLASTDrawConsumer; mBLASTDrawConsumer = null; mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(() -> { mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(() -> { long frameNr = mBlastBufferQueue.getLastAcquiredFrameNum(); long frameNr = mBlastBufferQueue.getLastAcquiredFrameNum(); if (DEBUG_BLAST) { if (DEBUG_BLAST) { Loading @@ -4002,6 +4011,9 @@ public final class ViewRootImpl implements ViewParent, mHandler.postAtFrontOfQueue(() -> { mHandler.postAtFrontOfQueue(() -> { if (useBlastSync) { if (useBlastSync) { mSurfaceChangedTransaction.merge(tmpTransaction); mSurfaceChangedTransaction.merge(tmpTransaction); if (blastSyncConsumer != null) { blastSyncConsumer.accept(mSurfaceChangedTransaction); } } } if (reportNextDraw) { if (reportNextDraw) { Loading Loading @@ -10457,4 +10469,35 @@ public final class ViewRootImpl implements ViewParent, listener.onBufferTransformHintChanged(hint); listener.onBufferTransformHintChanged(hint); } } } } /** * 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; } } }