diff --git a/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder_2.cc b/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder_2.cc index d1a7d19ebca..defcd11467d 100644 --- a/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder_2.cc +++ b/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder_2.cc @@ -83,7 +83,8 @@ void AndroidExternalViewEmbedder2::SubmitFlutterView( jni_facade->hidePlatformView2(view_id); } - jni_facade->applyTransaction(); + jni_facade->swapTransaction(); + jni_facade->onEndFrame2(); })); views_visible_last_frame_.clear(); return; @@ -170,13 +171,12 @@ void AndroidExternalViewEmbedder2::SubmitFlutterView( slices = std::move(slices_), views_visible_last_frame = views_visible_last_frame_, overlay_layer_has_content_this_frame_]() mutable -> void { - jni_facade->swapTransaction(); - if (overlay_layer_has_content_this_frame_) { ShowOverlayLayerIfNeeded(); } else { HideOverlayLayerIfNeeded(); } + jni_facade->swapTransaction(); for (int64_t view_id : composition_order) { DlRect view_rect = GetViewRect(view_id, view_params); diff --git a/engine/src/flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController2.java b/engine/src/flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController2.java index a5b4cbad9b7..cee347b0b1e 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController2.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController2.java @@ -608,9 +608,8 @@ public class PlatformViewsController2 implements PlatformViewsAccessibilityDeleg if (overlaySurfaceControl == null) { return; } - SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); + SurfaceControl.Transaction tx = createTransaction(); tx.setVisibility(overlaySurfaceControl, /*visible=*/ true); - tx.apply(); } @RequiresApi(API_LEVELS.API_34) @@ -618,9 +617,8 @@ public class PlatformViewsController2 implements PlatformViewsAccessibilityDeleg if (overlaySurfaceControl == null) { return; } - SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); + SurfaceControl.Transaction tx = createTransaction(); tx.setVisibility(overlaySurfaceControl, /*visible=*/ false); - tx.apply(); } public boolean isHcppEnabled() { diff --git a/engine/src/flutter/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsController2Test.java b/engine/src/flutter/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsController2Test.java index 3df7d5ee7e7..0b532a37dc2 100644 --- a/engine/src/flutter/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsController2Test.java +++ b/engine/src/flutter/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsController2Test.java @@ -14,8 +14,10 @@ import android.content.res.AssetManager; import android.graphics.SurfaceTexture; import android.media.Image; import android.util.SparseArray; +import android.view.AttachedSurfaceControl; import android.view.MotionEvent; import android.view.Surface; +import android.view.SurfaceControl; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; @@ -506,6 +508,51 @@ public class PlatformViewsController2Test { verify(platformView, times(1)).dispose(); } + // Class member variable + private SurfaceControl.Transaction mCapturedTx; + + @Test + @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class}) + public void showOverlaySurfaceDefersTransactionUntilEndFrame() { + + PlatformViewsController2 controller = + new PlatformViewsController2() { + @Override + public SurfaceControl.Transaction createTransaction() { + // Call super to ensure the real transaction is added to the private + // 'pendingTransactions' list + SurfaceControl.Transaction realTx = super.createTransaction(); + // Spy on it so we can verify calls like 'apply()' + mCapturedTx = spy(realTx); + return mCapturedTx; + } + }; + + PlatformViewRegistryImpl registry = new PlatformViewRegistryImpl(); + controller.setRegistry(registry); + + // Mocks + FlutterView mockFlutterView = mock(FlutterView.class); + AttachedSurfaceControl mockAttachedSurfaceControl = mock(AttachedSurfaceControl.class); + + when(mockFlutterView.getRootSurfaceControl()).thenReturn(mockAttachedSurfaceControl); + when(mockAttachedSurfaceControl.buildReparentTransaction(any())) + .thenReturn(new SurfaceControl.Transaction()); + + controller.attachToView(mockFlutterView); + controller.createOverlaySurface(); + + controller.showOverlaySurface(); + assertNotNull("Transaction should have been created", mCapturedTx); + verify(mCapturedTx, never()).apply(); + + controller.swapTransactions(); + controller.onEndFrame(); + + verify(mockAttachedSurfaceControl, times(1)) + .applyTransactionOnDraw(any(SurfaceControl.Transaction.class)); + } + private static ByteBuffer encodeMethodCall(MethodCall call) { final ByteBuffer buffer = StandardMethodCodec.INSTANCE.encodeMethodCall(call); buffer.rewind();