diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java index 57630cc9e6a8ef9c2d0c64c1a35591334cd4f0af..1291d5db05c965e36dd1055016104019898f6ae0 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java @@ -676,7 +676,8 @@ public class FlutterJNI { // Called by native. // TODO(mattcarroll): determine if message is nonull or nullable @SuppressWarnings("unused") - private void handlePlatformMessage( + @VisibleForTesting + public void handlePlatformMessage( @NonNull final String channel, byte[] message, final int replyId) { if (platformMessageHandler != null) { platformMessageHandler.handleMessageFromDart(channel, message, replyId); diff --git a/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java b/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java index a6a38dd2351978f6881474bfaae392eab07c413a..e418bdc42dec400d96c0f98e35336dc0a48c9256 100644 --- a/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java +++ b/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java @@ -524,6 +524,10 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega @Override public View getPlatformViewById(Integer id) { + // Hybrid composition. + if (platformViews.get(id) != null) { + return platformViews.get(id); + } VirtualDisplayController controller = vdControllers.get(id); if (controller == null) { return null; @@ -641,7 +645,8 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega } } - private void initializePlatformViewIfNeeded(int viewId) { + @VisibleForTesting + void initializePlatformViewIfNeeded(int viewId) { if (platformViews.get(viewId) != null) { return; } diff --git a/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsControllerTest.java b/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsControllerTest.java index 46e9a9d19668c90e393d6d4ed7af787a4382da19..2b31333ab1349f4716f4dd903989495563e24273 100644 --- a/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsControllerTest.java +++ b/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsControllerTest.java @@ -3,16 +3,30 @@ package io.flutter.plugin.platform; import static io.flutter.embedding.engine.systemchannels.PlatformViewsChannel.PlatformViewTouch; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.content.Context; +import android.content.res.AssetManager; import android.view.MotionEvent; import android.view.View; +import io.flutter.embedding.android.FlutterView; import io.flutter.embedding.android.MotionEventTracker; +import io.flutter.embedding.engine.FlutterJNI; +import io.flutter.embedding.engine.dart.DartExecutor; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.StandardMethodCodec; +import java.nio.ByteBuffer; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -186,4 +200,54 @@ public class PlatformViewsControllerTest { assertNotEquals(resolvedEvent.getAction(), frameWorkTouch.action); assertEquals(resolvedEvent.getAction(), original.getAction()); } + + @Test + public void getPlatformViewById__hybridComposition() { + PlatformViewsController platformViewsController = new PlatformViewsController(); + + int platformViewId = 0; + assertNull(platformViewsController.getPlatformViewById(platformViewId)); + + FlutterJNI jni = new FlutterJNI(); + AssetManager assetManager = mock(AssetManager.class); + Context context = RuntimeEnvironment.application.getApplicationContext(); + + DartExecutor executor = new DartExecutor(jni, assetManager); + executor.onAttachedToJNI(); + platformViewsController.attach(context, null, executor); + platformViewsController.attachToView(mock(FlutterView.class)); + + PlatformViewFactory viewFactory = mock(PlatformViewFactory.class); + PlatformView platformView = mock(PlatformView.class); + View androidView = mock(View.class); + when(platformView.getView()).thenReturn(androidView); + when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView); + + platformViewsController.getRegistry().registerViewFactory("testType", viewFactory); + + // Simulate create call from the framework. + Map platformViewCreateArguments = new HashMap<>(); + platformViewCreateArguments.put("hybrid", true); + platformViewCreateArguments.put("id", platformViewId); + platformViewCreateArguments.put("viewType", "testType"); + platformViewCreateArguments.put("direction", 0); + MethodCall platformCreateMethodCall = new MethodCall("create", platformViewCreateArguments); + + jni.handlePlatformMessage( + "flutter/platform_views", encodeMethodCall(platformCreateMethodCall), /*replyId=*/ 0); + + platformViewsController.initializePlatformViewIfNeeded(platformViewId); + + View resultAndroidView = platformViewsController.getPlatformViewById(platformViewId); + assertNotNull(resultAndroidView); + assertEquals(resultAndroidView, androidView); + } + + private static byte[] encodeMethodCall(MethodCall call) { + ByteBuffer buffer = StandardMethodCodec.INSTANCE.encodeMethodCall(call); + buffer.rewind(); + byte[] dest = new byte[buffer.remaining()]; + buffer.get(dest); + return dest; + } }