Fix Android platform view resize and direction in nested layouts. (flutter/engine#33645)
This commit is contained in:
@@ -222,7 +222,6 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
|
||||
layoutParams.topMargin = physicalTop;
|
||||
layoutParams.leftMargin = physicalLeft;
|
||||
wrapperView.setLayoutParams(layoutParams);
|
||||
wrapperView.setLayoutDirection(request.direction);
|
||||
|
||||
final View view = platformView.getView();
|
||||
if (view == null) {
|
||||
@@ -232,6 +231,8 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
|
||||
throw new IllegalStateException(
|
||||
"The Android view returned from PlatformView#getView() was already added to a parent view.");
|
||||
}
|
||||
view.setLayoutParams(new FrameLayout.LayoutParams(physicalWidth, physicalHeight));
|
||||
view.setLayoutDirection(request.direction);
|
||||
wrapperView.addView(view);
|
||||
wrapperView.setOnDescendantFocusChangeListener(
|
||||
(v, hasFocus) -> {
|
||||
@@ -301,8 +302,9 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
|
||||
public PlatformViewsChannel.PlatformViewBufferSize resize(
|
||||
@NonNull PlatformViewsChannel.PlatformViewResizeRequest request) {
|
||||
final int viewId = request.viewId;
|
||||
final PlatformView platformView = platformViews.get(viewId);
|
||||
final PlatformViewWrapper view = viewWrappers.get(viewId);
|
||||
if (view == null) {
|
||||
if (platformView == null || view == null) {
|
||||
Log.e(TAG, "Resizing unknown platform view with id: " + viewId);
|
||||
return null;
|
||||
}
|
||||
@@ -321,12 +323,18 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
|
||||
view.setBufferSize(newWidth, newHeight);
|
||||
}
|
||||
|
||||
final FrameLayout.LayoutParams layoutParams =
|
||||
(FrameLayout.LayoutParams) view.getLayoutParams();
|
||||
layoutParams.width = newWidth;
|
||||
layoutParams.height = newHeight;
|
||||
view.setLayoutParams(layoutParams);
|
||||
final ViewGroup.LayoutParams viewWrapperLayoutParams = view.getLayoutParams();
|
||||
viewWrapperLayoutParams.width = newWidth;
|
||||
viewWrapperLayoutParams.height = newHeight;
|
||||
view.setLayoutParams(viewWrapperLayoutParams);
|
||||
|
||||
final View embeddedView = platformView.getView();
|
||||
if (embeddedView != null) {
|
||||
final ViewGroup.LayoutParams embeddedViewLayoutParams = embeddedView.getLayoutParams();
|
||||
embeddedViewLayoutParams.width = newWidth;
|
||||
embeddedViewLayoutParams.height = newHeight;
|
||||
embeddedView.setLayoutParams(embeddedViewLayoutParams);
|
||||
}
|
||||
return new PlatformViewsChannel.PlatformViewBufferSize(
|
||||
toLogicalPixels(view.getBufferWidth()), toLogicalPixels(view.getBufferHeight()));
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.ViewParent;
|
||||
import android.widget.FrameLayout;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import io.flutter.embedding.android.FlutterImageView;
|
||||
@@ -41,10 +42,12 @@ import io.flutter.view.TextureRegistry;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
@@ -149,6 +152,65 @@ public class PlatformViewsControllerTest {
|
||||
verify(viewFactory, times(1)).create(any(), eq(platformViewId), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
|
||||
public void createPlatformViewMessage__setsAndroidViewLayoutDirection() {
|
||||
PlatformViewsController platformViewsController = new PlatformViewsController();
|
||||
platformViewsController.setSoftwareRendering(true);
|
||||
|
||||
int platformViewId = 0;
|
||||
assertNull(platformViewsController.getPlatformViewById(platformViewId));
|
||||
|
||||
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);
|
||||
|
||||
FlutterJNI jni = new FlutterJNI();
|
||||
attach(jni, platformViewsController);
|
||||
|
||||
// Simulate create call from the framework.
|
||||
createPlatformView(
|
||||
jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ false);
|
||||
verify(androidView, times(1)).setLayoutDirection(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
|
||||
public void createPlatformViewMessage__setsAndroidViewSize() {
|
||||
PlatformViewsController platformViewsController = new PlatformViewsController();
|
||||
platformViewsController.setSoftwareRendering(true);
|
||||
|
||||
int platformViewId = 0;
|
||||
assertNull(platformViewsController.getPlatformViewById(platformViewId));
|
||||
|
||||
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);
|
||||
|
||||
FlutterJNI jni = new FlutterJNI();
|
||||
attach(jni, platformViewsController);
|
||||
|
||||
// Simulate create call from the framework.
|
||||
createPlatformView(
|
||||
jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ false);
|
||||
|
||||
ArgumentCaptor<FrameLayout.LayoutParams> layoutParamsCaptor =
|
||||
ArgumentCaptor.forClass(FrameLayout.LayoutParams.class);
|
||||
verify(androidView, times(2)).setLayoutParams(layoutParamsCaptor.capture());
|
||||
|
||||
List<FrameLayout.LayoutParams> capturedLayoutParams = layoutParamsCaptor.getAllValues();
|
||||
assertEquals(capturedLayoutParams.get(0).width, 1);
|
||||
assertEquals(capturedLayoutParams.get(0).height, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
|
||||
public void createPlatformViewMessage__throwsIfViewIsNull() {
|
||||
@@ -301,6 +363,43 @@ public class PlatformViewsControllerTest {
|
||||
assertEquals(ShadowFlutterJNI.getResponses().get(0).limit(), 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
|
||||
public void resizeAndroidView() {
|
||||
PlatformViewsController platformViewsController = new PlatformViewsController();
|
||||
platformViewsController.setSoftwareRendering(true);
|
||||
|
||||
int platformViewId = 0;
|
||||
assertNull(platformViewsController.getPlatformViewById(platformViewId));
|
||||
|
||||
PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
|
||||
PlatformView platformView = mock(PlatformView.class);
|
||||
final View androidView = mock(View.class);
|
||||
when(platformView.getView()).thenReturn(androidView);
|
||||
when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
|
||||
platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
|
||||
|
||||
FlutterJNI jni = new FlutterJNI();
|
||||
attach(jni, platformViewsController);
|
||||
|
||||
// Simulate create call from the framework.
|
||||
createPlatformView(
|
||||
jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ false);
|
||||
|
||||
reset(androidView);
|
||||
when(androidView.getLayoutParams()).thenReturn(new FrameLayout.LayoutParams(0, 0));
|
||||
|
||||
// Simulate a resize call from the framework.
|
||||
resize(jni, platformViewsController, platformViewId, 10.0, 20.0);
|
||||
|
||||
ArgumentCaptor<FrameLayout.LayoutParams> layoutParamsCaptor =
|
||||
ArgumentCaptor.forClass(FrameLayout.LayoutParams.class);
|
||||
verify(androidView, times(1)).setLayoutParams(layoutParamsCaptor.capture());
|
||||
|
||||
assertEquals(layoutParamsCaptor.getValue().width, 10);
|
||||
assertEquals(layoutParamsCaptor.getValue().height, 20);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
|
||||
public void disposeAndroidView__hybridComposition() {
|
||||
@@ -822,16 +921,15 @@ public class PlatformViewsControllerTest {
|
||||
int platformViewId,
|
||||
String viewType,
|
||||
boolean hybrid) {
|
||||
final Map<String, Object> platformViewCreateArguments = new HashMap<>();
|
||||
platformViewCreateArguments.put("hybrid", hybrid);
|
||||
platformViewCreateArguments.put("id", platformViewId);
|
||||
platformViewCreateArguments.put("viewType", viewType);
|
||||
platformViewCreateArguments.put("direction", 0);
|
||||
platformViewCreateArguments.put("width", 1.0);
|
||||
platformViewCreateArguments.put("height", 1.0);
|
||||
final Map<String, Object> args = new HashMap<>();
|
||||
args.put("hybrid", hybrid);
|
||||
args.put("id", platformViewId);
|
||||
args.put("viewType", viewType);
|
||||
args.put("direction", 0);
|
||||
args.put("width", 1.0);
|
||||
args.put("height", 1.0);
|
||||
|
||||
final MethodCall platformCreateMethodCall =
|
||||
new MethodCall("create", platformViewCreateArguments);
|
||||
final MethodCall platformCreateMethodCall = new MethodCall("create", args);
|
||||
|
||||
jni.handlePlatformMessage(
|
||||
"flutter/platform_views",
|
||||
@@ -845,16 +943,35 @@ public class PlatformViewsControllerTest {
|
||||
PlatformViewsController platformViewsController,
|
||||
int platformViewId,
|
||||
int direction) {
|
||||
final Map<String, Object> platformViewCreateArguments = new HashMap<>();
|
||||
platformViewCreateArguments.put("id", platformViewId);
|
||||
platformViewCreateArguments.put("direction", direction);
|
||||
final Map<String, Object> args = new HashMap<>();
|
||||
args.put("id", platformViewId);
|
||||
args.put("direction", direction);
|
||||
|
||||
final MethodCall platformCreateMethodCall =
|
||||
new MethodCall("setDirection", platformViewCreateArguments);
|
||||
final MethodCall platformSetDirectionMethodCall = new MethodCall("setDirection", args);
|
||||
|
||||
jni.handlePlatformMessage(
|
||||
"flutter/platform_views",
|
||||
encodeMethodCall(platformCreateMethodCall),
|
||||
encodeMethodCall(platformSetDirectionMethodCall),
|
||||
/*replyId=*/ 0,
|
||||
/*messageData=*/ 0);
|
||||
}
|
||||
|
||||
private static void resize(
|
||||
FlutterJNI jni,
|
||||
PlatformViewsController platformViewsController,
|
||||
int platformViewId,
|
||||
double width,
|
||||
double height) {
|
||||
final Map<String, Object> args = new HashMap<>();
|
||||
args.put("id", platformViewId);
|
||||
args.put("width", width);
|
||||
args.put("height", height);
|
||||
|
||||
final MethodCall platformResizeMethodCall = new MethodCall("resize", args);
|
||||
|
||||
jni.handlePlatformMessage(
|
||||
"flutter/platform_views",
|
||||
encodeMethodCall(platformResizeMethodCall),
|
||||
/*replyId=*/ 0,
|
||||
/*messageData=*/ 0);
|
||||
}
|
||||
@@ -862,12 +979,11 @@ public class PlatformViewsControllerTest {
|
||||
private static void disposePlatformView(
|
||||
FlutterJNI jni, PlatformViewsController platformViewsController, int platformViewId) {
|
||||
|
||||
final Map<String, Object> platformViewDisposeArguments = new HashMap<>();
|
||||
platformViewDisposeArguments.put("hybrid", true);
|
||||
platformViewDisposeArguments.put("id", platformViewId);
|
||||
final Map<String, Object> args = new HashMap<>();
|
||||
args.put("hybrid", true);
|
||||
args.put("id", platformViewId);
|
||||
|
||||
final MethodCall platformDisposeMethodCall =
|
||||
new MethodCall("dispose", platformViewDisposeArguments);
|
||||
final MethodCall platformDisposeMethodCall = new MethodCall("dispose", args);
|
||||
|
||||
jni.handlePlatformMessage(
|
||||
"flutter/platform_views",
|
||||
|
||||
Reference in New Issue
Block a user