From b3a676f5a523ff3977a9b8f9d6cd49a389ed3be8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rulong=20Chen=EF=BC=88=E9=99=88=E6=B1=9D=E9=BE=99=EF=BC=89?= Date: Wed, 12 Jul 2023 15:57:59 +0800 Subject: [PATCH 1/2] Enabling the host application to control the timing of attaching the |FlutterView| to the engine. --- .../embedding/android/FlutterActivity.java | 13 +++++++++ .../FlutterActivityAndFragmentDelegate.java | 18 ++++++++++-- .../embedding/android/FlutterFragment.java | 13 +++++++++ ...lutterActivityAndFragmentDelegateTest.java | 28 +++++++++++++++++++ .../android/FlutterAndroidComponentTest.java | 5 ++++ 5 files changed, 75 insertions(+), 2 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java index 5ec47c5831a09..22c57e31128b8 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java @@ -1407,6 +1407,19 @@ public boolean shouldDispatchAppLifecycleState() { return true; } + /** + * Whether to manually attach the {@link FlutterView} to the engine by the host application. + * + *

Returning {@code true} means that the responsibility of attaching the {@link FlutterView} to + * the engine will be taken over by the host application. + * + *

Defaults to {@code false}. + */ + @Override + public boolean shouldAttachToEngineManually() { + return false; + } + @Override public boolean popSystemNavigator() { // Hook for subclass. No-op if returns false. diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java index 1e59b74e03bbb..dd102ce6c665c 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java @@ -390,8 +390,10 @@ View onCreateView( // Add listener to be notified when Flutter renders its first frame. flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener); - Log.v(TAG, "Attaching FlutterEngine to FlutterView."); - flutterView.attachToFlutterEngine(flutterEngine); + if (!host.shouldAttachToEngineManually()) { + Log.v(TAG, "Attaching FlutterEngine to FlutterView."); + flutterView.attachToFlutterEngine(flutterEngine); + } flutterView.setId(flutterViewId); if (shouldDelayFirstAndroidViewDraw) { @@ -1171,5 +1173,17 @@ PlatformPlugin providePlatformPlugin( * while return {@code true} means the engine dispatches these events. */ boolean shouldDispatchAppLifecycleState(); + + /** + * Whether to manually attach the {@link FlutterView} to the engine by the host application. + * + *

In the add-to-app scenario where multiple {@link FlutterView} share the same {@link + * FlutterEngine}, the host application desires to determine the timing of attaching the {@link + * FlutterView} to the engine, for example, during the {@code onResume} instead of the {@code + * onCreateView}. + * + *

Defaults to {@code false}. + */ + boolean shouldAttachToEngineManually(); } } diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java index b521c73882f0d..34eab5678b80b 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java @@ -1645,6 +1645,19 @@ public boolean shouldDispatchAppLifecycleState() { return true; } + /** + * Whether to manually attach the {@link FlutterView} to the engine by the host application. + * + *

Returning {@code true} means that the responsibility of attaching the {@link FlutterView} to + * the engine will be taken over by the host application. + * + *

Defaults to {@code false}. + */ + @Override + public boolean shouldAttachToEngineManually() { + return false; + } + /** * {@inheritDoc} * diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java index 3cb5d2dd6665f..c9d23853de579 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java @@ -2,9 +2,11 @@ import static android.content.ComponentCallbacks2.*; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNotNull; @@ -88,6 +90,7 @@ public void setup() { when(mockHost.shouldHandleDeeplinking()).thenReturn(false); when(mockHost.shouldDestroyEngineWithHost()).thenReturn(true); when(mockHost.shouldDispatchAppLifecycleState()).thenReturn(true); + when(mockHost.shouldAttachToEngineManually()).thenReturn(false); } @Test @@ -1241,6 +1244,31 @@ public void usesFlutterEngineGroup() { assertEquals(engineUnderTest, mockFlutterEngine); } + @Test + public void itDoesAttachFlutterViewToEngine() { + // ---- Test setup ---- + // Create the real object that we're testing. + FlutterActivityAndFragmentDelegate delegate = new FlutterActivityAndFragmentDelegate(mockHost); + delegate.onAttach(ctx); + delegate.onCreateView(null, null, null, 0, true); + + // --- Execute the behavior under test --- + assertTrue(delegate.flutterView.isAttachedToFlutterEngine()); + } + + @Test + public void itDoesNotAttachFlutterViewToEngine() { + // ---- Test setup ---- + // Create the real object that we're testing. + when(mockHost.shouldAttachToEngineManually()).thenReturn(true); + FlutterActivityAndFragmentDelegate delegate = new FlutterActivityAndFragmentDelegate(mockHost); + delegate.onAttach(ctx); + delegate.onCreateView(null, null, null, 0, true); + + // --- Execute the behavior under test --- + assertFalse(delegate.flutterView.isAttachedToFlutterEngine()); + } + /** * Creates a mock {@link io.flutter.embedding.engine.FlutterEngine}. * diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java index d569c64c36203..8afb2a465b755 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java @@ -389,6 +389,11 @@ public boolean shouldDispatchAppLifecycleState() { return true; } + @Override + public boolean shouldAttachToEngineManually() { + return false; + } + @Override public void onFlutterSurfaceViewCreated(@NonNull FlutterSurfaceView flutterSurfaceView) {} From a0e86deba80b98cae7153e710e04e37b8273045e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rulong=20Chen=EF=BC=88=E9=99=88=E6=B1=9D=E9=BE=99=EF=BC=89?= Date: Tue, 15 Aug 2023 11:51:00 +0800 Subject: [PATCH 2/2] rename --- .../flutter/embedding/android/FlutterActivity.java | 12 ++++++------ .../android/FlutterActivityAndFragmentDelegate.java | 8 ++++---- .../flutter/embedding/android/FlutterFragment.java | 12 ++++++------ .../FlutterActivityAndFragmentDelegateTest.java | 4 ++-- .../android/FlutterAndroidComponentTest.java | 4 ++-- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java index 22c57e31128b8..acdfc1ca3aca5 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java @@ -1408,16 +1408,16 @@ public boolean shouldDispatchAppLifecycleState() { } /** - * Whether to manually attach the {@link FlutterView} to the engine by the host application. + * Whether to automatically attach the {@link FlutterView} to the engine. * - *

Returning {@code true} means that the responsibility of attaching the {@link FlutterView} to - * the engine will be taken over by the host application. + *

Returning {@code false} means that the task of attaching the {@link FlutterView} to the + * engine will be taken over by the host application. * - *

Defaults to {@code false}. + *

Defaults to {@code true}. */ @Override - public boolean shouldAttachToEngineManually() { - return false; + public boolean attachToEngineAutomatically() { + return true; } @Override diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java index dd102ce6c665c..9596dc6cc4a26 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java @@ -390,7 +390,7 @@ View onCreateView( // Add listener to be notified when Flutter renders its first frame. flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener); - if (!host.shouldAttachToEngineManually()) { + if (host.attachToEngineAutomatically()) { Log.v(TAG, "Attaching FlutterEngine to FlutterView."); flutterView.attachToFlutterEngine(flutterEngine); } @@ -1175,15 +1175,15 @@ PlatformPlugin providePlatformPlugin( boolean shouldDispatchAppLifecycleState(); /** - * Whether to manually attach the {@link FlutterView} to the engine by the host application. + * Whether to automatically attach the {@link FlutterView} to the engine. * *

In the add-to-app scenario where multiple {@link FlutterView} share the same {@link * FlutterEngine}, the host application desires to determine the timing of attaching the {@link * FlutterView} to the engine, for example, during the {@code onResume} instead of the {@code * onCreateView}. * - *

Defaults to {@code false}. + *

Defaults to {@code true}. */ - boolean shouldAttachToEngineManually(); + boolean attachToEngineAutomatically(); } } diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java index 34eab5678b80b..586d60c9c6980 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java @@ -1646,16 +1646,16 @@ public boolean shouldDispatchAppLifecycleState() { } /** - * Whether to manually attach the {@link FlutterView} to the engine by the host application. + * Whether to automatically attach the {@link FlutterView} to the engine. * - *

Returning {@code true} means that the responsibility of attaching the {@link FlutterView} to - * the engine will be taken over by the host application. + *

Returning {@code false} means that the task of attaching the {@link FlutterView} to the + * engine will be taken over by the host application. * - *

Defaults to {@code false}. + *

Defaults to {@code true}. */ @Override - public boolean shouldAttachToEngineManually() { - return false; + public boolean attachToEngineAutomatically() { + return true; } /** diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java index c9d23853de579..86b5acfac06b9 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java @@ -90,7 +90,7 @@ public void setup() { when(mockHost.shouldHandleDeeplinking()).thenReturn(false); when(mockHost.shouldDestroyEngineWithHost()).thenReturn(true); when(mockHost.shouldDispatchAppLifecycleState()).thenReturn(true); - when(mockHost.shouldAttachToEngineManually()).thenReturn(false); + when(mockHost.attachToEngineAutomatically()).thenReturn(true); } @Test @@ -1260,7 +1260,7 @@ public void itDoesAttachFlutterViewToEngine() { public void itDoesNotAttachFlutterViewToEngine() { // ---- Test setup ---- // Create the real object that we're testing. - when(mockHost.shouldAttachToEngineManually()).thenReturn(true); + when(mockHost.attachToEngineAutomatically()).thenReturn(false); FlutterActivityAndFragmentDelegate delegate = new FlutterActivityAndFragmentDelegate(mockHost); delegate.onAttach(ctx); delegate.onCreateView(null, null, null, 0, true); diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java index 8afb2a465b755..64cf15d0404d2 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterAndroidComponentTest.java @@ -390,8 +390,8 @@ public boolean shouldDispatchAppLifecycleState() { } @Override - public boolean shouldAttachToEngineManually() { - return false; + public boolean attachToEngineAutomatically() { + return true; } @Override