Fix resize crash in Android virtual display (flutter/engine#37329)
In the Virtual Display codepath for Android platform views, resize completes asynchronously. Currently it is attempting to access the Context in the completion handler, but there is no guarantee that it is still present at that point, leading to possible null pointer crashes. This adds a check for the current state of the Context, and uses a fallback if it's not available. Fixes https://github.com/flutter/flutter/issues/114095
This commit is contained in:
@@ -314,6 +314,7 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
|
||||
final int viewId = request.viewId;
|
||||
|
||||
if (usesVirtualDisplay(viewId)) {
|
||||
final float originalDisplayDensity = getDisplayDensity();
|
||||
final VirtualDisplayController vdController = vdControllers.get(viewId);
|
||||
// Resizing involved moving the platform view to a new virtual display. Doing so
|
||||
// potentially results in losing an active input connection. To make sure we preserve
|
||||
@@ -325,10 +326,15 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
|
||||
physicalHeight,
|
||||
() -> {
|
||||
unlockInputConnection(vdController);
|
||||
// Converting back to logic pixels requires a context, which may no longer be
|
||||
// available. If that happens, assume the same logic/physical relationship as
|
||||
// was present when the request arrived.
|
||||
final float displayDensity =
|
||||
context == null ? originalDisplayDensity : getDisplayDensity();
|
||||
onComplete.run(
|
||||
new PlatformViewsChannel.PlatformViewBufferSize(
|
||||
toLogicalPixels(vdController.getBufferWidth()),
|
||||
toLogicalPixels(vdController.getBufferHeight())));
|
||||
toLogicalPixels(vdController.getBufferWidth(), displayDensity),
|
||||
toLogicalPixels(vdController.getBufferHeight(), displayDensity)));
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -1002,8 +1008,12 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
|
||||
return (int) Math.round(logicalPixels * getDisplayDensity());
|
||||
}
|
||||
|
||||
private int toLogicalPixels(double physicalPixels, float displayDensity) {
|
||||
return (int) Math.round(physicalPixels / displayDensity);
|
||||
}
|
||||
|
||||
private int toLogicalPixels(double physicalPixels) {
|
||||
return (int) Math.round(physicalPixels / getDisplayDensity());
|
||||
return toLogicalPixels(physicalPixels, getDisplayDensity());
|
||||
}
|
||||
|
||||
private void diposeAllViews() {
|
||||
|
||||
@@ -124,6 +124,32 @@ public class PlatformViewsControllerTest {
|
||||
assertEquals(presentation.isShowing(), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
|
||||
public void virtualDisplay_handlesResizeResponseWithoutContext() {
|
||||
final int platformViewId = 0;
|
||||
FlutterView fakeFlutterView = new FlutterView(ApplicationProvider.getApplicationContext());
|
||||
VirtualDisplayController fakeVdController = mock(VirtualDisplayController.class);
|
||||
PlatformViewsController platformViewsController = new PlatformViewsController();
|
||||
platformViewsController.vdControllers.put(platformViewId, fakeVdController);
|
||||
|
||||
platformViewsController.attachToView(fakeFlutterView);
|
||||
|
||||
FlutterJNI jni = new FlutterJNI();
|
||||
attach(jni, platformViewsController);
|
||||
|
||||
resize(jni, platformViewsController, platformViewId, 10.0, 20.0);
|
||||
|
||||
ArgumentCaptor<Runnable> resizeCallbackCaptor = ArgumentCaptor.forClass(Runnable.class);
|
||||
verify(fakeVdController, times(1)).resize(anyInt(), anyInt(), resizeCallbackCaptor.capture());
|
||||
|
||||
// Simulate a detach call before the resize completes.
|
||||
platformViewsController.detach();
|
||||
|
||||
// Trigger the callback to ensure that it doesn't crash.
|
||||
resizeCallbackCaptor.getValue().run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void itUsesActionEventTypeFromFrameworkEventForVirtualDisplays() {
|
||||
MotionEventTracker motionEventTracker = MotionEventTracker.getInstance();
|
||||
|
||||
Reference in New Issue
Block a user