From 4b9fc4c1a552f4e456aabcbb887c26bc73aa81f3 Mon Sep 17 00:00:00 2001 From: Michael Klimushyn Date: Mon, 14 Oct 2019 14:03:25 -0700 Subject: [PATCH] Fire PlatformViewController FlutterView callbacks (flutter/engine#13015) Fixes a bug where `PlatformViewController` was not being notified of `FlutterView` attachment changes. --- .../flutter/shell/platform/android/BUILD.gn | 1 + .../embedding/android/FlutterView.java | 4 ++ .../embedding/engine/FlutterEngine.java | 11 +++- .../flutter/embedding/engine/FlutterJNI.java | 2 +- .../engine/renderer/FlutterRenderer.java | 2 +- .../android/io/flutter/view/FlutterView.java | 3 +- .../test/io/flutter/FlutterTestSuite.java | 2 + .../embedding/android/FlutterViewTest.java | 58 +++++++++++++++++++ 8 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 engine/src/flutter/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java diff --git a/engine/src/flutter/shell/platform/android/BUILD.gn b/engine/src/flutter/shell/platform/android/BUILD.gn index c2f3d1f41e3..bfd6f47d507 100644 --- a/engine/src/flutter/shell/platform/android/BUILD.gn +++ b/engine/src/flutter/shell/platform/android/BUILD.gn @@ -417,6 +417,7 @@ action("robolectric_tests") { "test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java", "test/io/flutter/embedding/android/FlutterActivityTest.java", "test/io/flutter/embedding/android/FlutterFragmentTest.java", + "test/io/flutter/embedding/android/FlutterViewTest.java", "test/io/flutter/embedding/engine/FlutterEngineCacheTest.java", "test/io/flutter/embedding/engine/FlutterJNITest.java", "test/io/flutter/embedding/engine/RenderingComponentTest.java", diff --git a/engine/src/flutter/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/engine/src/flutter/shell/platform/android/io/flutter/embedding/android/FlutterView.java index c6936c97f5a..2d10a20dba1 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -633,6 +633,8 @@ public class FlutterView extends FrameLayout { sendLocalesToFlutter(getResources().getConfiguration()); sendViewportMetricsToFlutter(); + flutterEngine.getPlatformViewsController().attachToView(this); + // Notify engine attachment listeners of the attachment. for (FlutterEngineAttachmentListener listener : flutterEngineAttachmentListeners) { listener.onFlutterEngineAttachedToFlutterView(flutterEngine); @@ -668,6 +670,8 @@ public class FlutterView extends FrameLayout { listener.onFlutterEngineDetachedFromFlutterView(); } + flutterEngine.getPlatformViewsController().detachFromView(); + // Disconnect the FlutterEngine's PlatformViewsController from the AccessibilityBridge. flutterEngine.getPlatformViewsController().detachAccessibiltyBridge(); diff --git a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java index 42b0129d729..5a4ec289ccf 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java @@ -143,14 +143,19 @@ public class FlutterEngine implements LifecycleOwner { * and {@link FlutterLoader#ensureInitializationComplete(Context, String[])}. */ public FlutterEngine(@NonNull Context context) { - this(context, FlutterLoader.getInstance()); + this(context, FlutterLoader.getInstance(), new FlutterJNI()); } - /* package */ FlutterEngine(@NonNull Context context, @NonNull FlutterLoader flutterLoader) { + /** + * Constructs a new {@code FlutterEngine}. See {@link #FlutterEngine(Context)}. + * + * {@code flutterJNI} should be a new instance that has never been attached to an engine before. + */ + public FlutterEngine(@NonNull Context context, @NonNull FlutterLoader flutterLoader, @NonNull FlutterJNI flutterJNI) { + this.flutterJNI = flutterJNI; flutterLoader.startInitialization(context); flutterLoader.ensureInitializationComplete(context, null); - this.flutterJNI = new FlutterJNI(); flutterJNI.addEngineLifecycleListener(engineLifecycleListener); attachToJni(); diff --git a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java index 3ab1745d44c..2bd663f0310 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java @@ -121,7 +121,7 @@ public class FlutterJNI { // TODO(mattcarroll): add javadocs @UiThread - public static native boolean nativeGetIsSoftwareRenderingEnabled(); + public native boolean nativeGetIsSoftwareRenderingEnabled(); @Nullable // TODO(mattcarroll): add javadocs diff --git a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java index 306535a547a..a6675964e6b 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java @@ -281,7 +281,7 @@ public class FlutterRenderer implements TextureRegistry { // TODO(mattcarroll): describe the native behavior that this invokes public boolean isSoftwareRenderingEnabled() { - return FlutterJNI.nativeGetIsSoftwareRenderingEnabled(); + return flutterJNI.nativeGetIsSoftwareRenderingEnabled(); } // TODO(mattcarroll): describe the native behavior that this invokes diff --git a/engine/src/flutter/shell/platform/android/io/flutter/view/FlutterView.java b/engine/src/flutter/shell/platform/android/io/flutter/view/FlutterView.java index d1037170e19..1546be7daec 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/view/FlutterView.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/view/FlutterView.java @@ -38,7 +38,6 @@ import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -162,7 +161,7 @@ public class FlutterView extends SurfaceView implements BinaryMessenger, Texture dartExecutor = mNativeView.getDartExecutor(); flutterRenderer = new FlutterRenderer(mNativeView.getFlutterJNI()); - mIsSoftwareRenderingEnabled = FlutterJNI.nativeGetIsSoftwareRenderingEnabled(); + mIsSoftwareRenderingEnabled = mNativeView.getFlutterJNI().nativeGetIsSoftwareRenderingEnabled(); mMetrics = new ViewportMetrics(); mMetrics.devicePixelRatio = context.getResources().getDisplayMetrics().density; setFocusable(true); diff --git a/engine/src/flutter/shell/platform/android/test/io/flutter/FlutterTestSuite.java b/engine/src/flutter/shell/platform/android/test/io/flutter/FlutterTestSuite.java index 59980291db4..b400fb5625e 100644 --- a/engine/src/flutter/shell/platform/android/test/io/flutter/FlutterTestSuite.java +++ b/engine/src/flutter/shell/platform/android/test/io/flutter/FlutterTestSuite.java @@ -10,6 +10,7 @@ import org.junit.runners.Suite.SuiteClasses; import io.flutter.embedding.android.FlutterActivityTest; import io.flutter.embedding.android.FlutterFragmentTest; +import io.flutter.embedding.android.FlutterViewTest; import io.flutter.embedding.engine.FlutterEngineCacheTest; import io.flutter.embedding.engine.FlutterJNITest; import io.flutter.embedding.engine.RenderingComponentTest; @@ -28,6 +29,7 @@ import io.flutter.util.PreconditionsTest; FlutterFragmentTest.class, FlutterJNITest.class, FlutterRendererTest.class, + FlutterViewTest.class, PlatformChannelTest.class, PreconditionsTest.class, RenderingComponentTest.class, diff --git a/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java b/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java new file mode 100644 index 00000000000..fe87fc8954d --- /dev/null +++ b/engine/src/flutter/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java @@ -0,0 +1,58 @@ +package io.flutter.embedding.android; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.flutter.embedding.engine.FlutterJNI; +import io.flutter.embedding.engine.loader.FlutterLoader; +import io.flutter.plugin.platform.PlatformViewsController; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import io.flutter.embedding.engine.FlutterEngine; + +@Config(manifest = Config.NONE) +@RunWith(RobolectricTestRunner.class) +public class FlutterViewTest { + @Mock FlutterJNI mockFlutterJni; + @Mock FlutterLoader mockFlutterLoader; + @Spy PlatformViewsController platformViewsController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(mockFlutterJni.isAttached()).thenReturn(true); + } + + @Test + public void attachToFlutterEngine_alertsPlatformViews() { + FlutterView flutterView = new FlutterView(RuntimeEnvironment.application); + FlutterEngine flutterEngine = spy(new FlutterEngine(RuntimeEnvironment.application, mockFlutterLoader, mockFlutterJni)); + when(flutterEngine.getPlatformViewsController()).thenReturn(platformViewsController); + + flutterView.attachToFlutterEngine(flutterEngine); + + verify(platformViewsController, times(1)).attachToView(flutterView); + } + + @Test + public void detachFromFlutterEngine_alertsPlatformViews() { + FlutterView flutterView = new FlutterView(RuntimeEnvironment.application); + FlutterEngine flutterEngine = spy(new FlutterEngine(RuntimeEnvironment.application, mockFlutterLoader, mockFlutterJni)); + when(flutterEngine.getPlatformViewsController()).thenReturn(platformViewsController); + + flutterView.attachToFlutterEngine(flutterEngine); + flutterView.detachFromFlutterEngine(); + + verify(platformViewsController, times(1)).detachFromView(); + } +}