77import static org .mockito .Mockito .*;
88import static org .robolectric .Shadows .shadowOf ;
99
10+ import android .app .Presentation ;
1011import android .content .Context ;
1112import android .content .MutableContextWrapper ;
1213import android .content .res .AssetManager ;
14+ import android .graphics .Canvas ;
1315import android .graphics .SurfaceTexture ;
1416import android .util .SparseArray ;
1517import android .view .MotionEvent ;
5355import org .robolectric .annotation .Config ;
5456import org .robolectric .annotation .Implementation ;
5557import org .robolectric .annotation .Implements ;
58+ import org .robolectric .shadows .ShadowDialog ;
59+ import org .robolectric .shadows .ShadowSurface ;
5660import org .robolectric .shadows .ShadowSurfaceView ;
5761
5862@ Config (manifest = Config .NONE )
@@ -505,7 +509,8 @@ public void createHybridPlatformViewMessage__throwsIfViewIsNull() {
505509 }
506510
507511 @ Test
508- @ Config (shadows = {ShadowFlutterJNI .class , ShadowPlatformTaskQueue .class })
512+ @ Config (
513+ shadows = {ShadowFlutterJNI .class , ShadowPlatformTaskQueue .class , ShadowPresentation .class })
509514 public void onDetachedFromJNI_clearsPlatformViewContext () {
510515 PlatformViewsController platformViewsController = new PlatformViewsController ();
511516
@@ -536,7 +541,8 @@ public void onDetachedFromJNI_clearsPlatformViewContext() {
536541 }
537542
538543 @ Test
539- @ Config (shadows = {ShadowFlutterJNI .class , ShadowPlatformTaskQueue .class })
544+ @ Config (
545+ shadows = {ShadowFlutterJNI .class , ShadowPlatformTaskQueue .class , ShadowPresentation .class })
540546 public void onPreEngineRestart_clearsPlatformViewContext () {
541547 PlatformViewsController platformViewsController = new PlatformViewsController ();
542548
@@ -740,7 +746,12 @@ public void disposeAndroidView__hybridComposition() {
740746 }
741747
742748 @ Test
743- @ Config (shadows = {ShadowFlutterJNI .class , ShadowPlatformTaskQueue .class })
749+ @ Config (
750+ shadows = {
751+ ShadowFlutterJNI .class ,
752+ ShadowReleasedSurface .class ,
753+ ShadowPlatformTaskQueue .class
754+ })
744755 public void disposeNullAndroidView () {
745756 PlatformViewsController platformViewsController = new PlatformViewsController ();
746757
@@ -760,6 +771,20 @@ public void disposeNullAndroidView() {
760771 attach (jni , platformViewsController );
761772
762773 // Simulate create call from the framework.
774+ // Before Robolectric 4.8, Surface#lockHardwareCanvas will throw exception at
775+ // PlatformViewWrapper#setTexture, because Robolectric doesn't support to shadow
776+ // Surface#lockHardwareCanvas, and it uses real Android logic with native pointer address is 0.
777+ // This failure will ensure embeddedView's parent is null, because
778+ // PlatformViewsController#createForTextureLayer will fail because of previous mentioned error,
779+ // and PlatformViewsController#createForTextureLayer will not add embeddedView to wrapperView.
780+ // So this test can pass. From Robolectric 4.8, it supports to shadow Surface#lockHardwareCanvas
781+ // and it can pass with default true valid value, and
782+ // PlatformViewsController#createForTextureLayer will run correctly and add embeddedView to
783+ // wrapperView, and initializePlatformViewIfNeeded will fail because embeddedView's parent is
784+ // not null. So adding a new shadow class called ShadowReleasedSurface to simulate previous
785+ // Surface#lockHardwareCanvas failure to ensure this test can work with Robolectric 4.8 and
786+ // later versions. But it is just a workaround, the root cause is this test case depends on
787+ // just-failure behavior of Surface#lockHardwareCanvas in old Robolectric.
763788 createPlatformView (
764789 jni , platformViewsController , platformViewId , "testType" , /* hybrid=*/ false );
765790 platformViewsController .initializePlatformViewIfNeeded (platformViewId );
@@ -1388,6 +1413,50 @@ public void dispatch(Runnable runnable) {
13881413 }
13891414 }
13901415
1416+ /**
1417+ * The shadow class of {@link Surface} to simulate released surface.
1418+ *
1419+ * <p>This shadow class's usage is restricted, not for normal purpose.
1420+ */
1421+ @ Implements (Surface .class )
1422+ public static class ShadowReleasedSurface extends ShadowSurface {
1423+ public ShadowReleasedSurface () {}
1424+
1425+ @ Implementation
1426+ @ Override
1427+ protected Canvas lockHardwareCanvas () {
1428+ throw new IllegalStateException ("Surface has already been released." );
1429+ }
1430+ }
1431+
1432+ /**
1433+ * The shadow class of {@link Presentation} to simulate Presentation showing logic.
1434+ *
1435+ * <p>Robolectric doesn't support VirtualDisplay creating correctly now, so this shadow class is
1436+ * used to simulate custom logic for Presentation.
1437+ */
1438+ @ Implements (Presentation .class )
1439+ public static class ShadowPresentation extends ShadowDialog {
1440+ private boolean isShowing = false ;
1441+
1442+ public ShadowPresentation () {}
1443+
1444+ @ Implementation
1445+ protected void show () {
1446+ isShowing = true ;
1447+ }
1448+
1449+ @ Implementation
1450+ protected void dismiss () {
1451+ isShowing = false ;
1452+ }
1453+
1454+ @ Implementation
1455+ protected boolean isShowing () {
1456+ return isShowing ;
1457+ }
1458+ }
1459+
13911460 @ Implements (FlutterJNI .class )
13921461 public static class ShadowFlutterJNI {
13931462 private static SparseArray <ByteBuffer > replies = new SparseArray <>();
0 commit comments