9
9
import static junit .framework .TestCase .assertTrue ;
10
10
import static org .mockito .ArgumentMatchers .any ;
11
11
import static org .mockito .ArgumentMatchers .anyInt ;
12
+ import static org .mockito .Mockito .clearInvocations ;
12
13
import static org .mockito .Mockito .doNothing ;
13
14
import static org .mockito .Mockito .doReturn ;
14
15
import static org .mockito .Mockito .mock ;
36
37
import android .view .DisplayCutout ;
37
38
import android .view .Surface ;
38
39
import android .view .View ;
39
- import android .view .ViewGroup ;
40
40
import android .view .WindowInsets ;
41
41
import android .view .WindowManager ;
42
42
import android .widget .FrameLayout ;
69
69
import org .robolectric .annotation .Implementation ;
70
70
import org .robolectric .annotation .Implements ;
71
71
import org .robolectric .shadows .ShadowDisplay ;
72
+ import org .robolectric .shadows .ShadowViewGroup ;
72
73
73
74
@ Config (manifest = Config .NONE )
74
75
@ RunWith (AndroidJUnit4 .class )
@@ -83,6 +84,8 @@ public class FlutterViewTest {
83
84
public void setUp () {
84
85
MockitoAnnotations .openMocks (this );
85
86
when (mockFlutterJni .isAttached ()).thenReturn (true );
87
+ // Uncomment the following line to enable logging output in test.
88
+ // ShadowLog.stream = System.out;
86
89
}
87
90
88
91
@ SuppressWarnings ("deprecation" )
@@ -937,6 +940,92 @@ public void ViewportMetrics_initializedPhysicalTouchSlop() {
937
940
assertFalse (-1 == viewportMetricsCaptor .getValue ().physicalTouchSlop );
938
941
}
939
942
943
+ @ SuppressWarnings ("deprecation" )
944
+ // Robolectric.setupActivity
945
+ // TODO(reidbaker): https://github.com/flutter/flutter/issues/133151
946
+ // This test uses the API 30+ Algorithm for window insets. The legacy algorithm is
947
+ // set to -1 values, so it is clear if the wrong algorithm is used.
948
+ @ Test
949
+ @ TargetApi (30 )
950
+ @ Config (sdk = 30 )
951
+ public void setPaddingTopToZeroForFullscreenMode () {
952
+ FlutterView flutterView = new FlutterView (Robolectric .setupActivity (Activity .class ));
953
+ FlutterEngine flutterEngine = spy (new FlutterEngine (ctx , mockFlutterLoader , mockFlutterJni ));
954
+ FlutterRenderer flutterRenderer = spy (new FlutterRenderer (mockFlutterJni ));
955
+ when (flutterEngine .getRenderer ()).thenReturn (flutterRenderer );
956
+
957
+ // When we attach a new FlutterView to the engine without any system insets, the viewport
958
+ // metrics
959
+ // default to 0.
960
+ flutterView .attachToFlutterEngine (flutterEngine );
961
+ ArgumentCaptor <FlutterRenderer .ViewportMetrics > viewportMetricsCaptor =
962
+ ArgumentCaptor .forClass (FlutterRenderer .ViewportMetrics .class );
963
+ verify (flutterRenderer ).setViewportMetrics (viewportMetricsCaptor .capture ());
964
+ assertEquals (0 , viewportMetricsCaptor .getValue ().viewPaddingTop );
965
+
966
+ // Then we simulate the system applying a window inset.
967
+ WindowInsets windowInsets =
968
+ new WindowInsets .Builder ()
969
+ .setInsets (
970
+ android .view .WindowInsets .Type .navigationBars ()
971
+ | android .view .WindowInsets .Type .statusBars (),
972
+ Insets .of (100 , 100 , 100 , 100 ))
973
+ .build ();
974
+ flutterView .onApplyWindowInsets (windowInsets );
975
+
976
+ // Verify.
977
+ verify (flutterRenderer , times (3 )).setViewportMetrics (viewportMetricsCaptor .capture ());
978
+ validateViewportMetricPadding (viewportMetricsCaptor , 100 , 100 , 100 , 100 );
979
+ }
980
+
981
+ @ SuppressWarnings ("deprecation" )
982
+ // Robolectric.setupActivity
983
+ // TODO(reidbaker): https://github.com/flutter/flutter/issues/133151
984
+ // This test uses the pre-API 30 Algorithm for window insets.
985
+ @ Test
986
+ @ TargetApi (28 )
987
+ @ Config (
988
+ sdk = 28 ,
989
+ shadows = {
990
+ FlutterViewTest .ShadowFullscreenView .class ,
991
+ })
992
+ public void setPaddingTopToZeroForFullscreenModeLegacy () {
993
+ FlutterView flutterView = spy (new FlutterView (ctx ));
994
+ FlutterEngine flutterEngine = spy (new FlutterEngine (ctx , mockFlutterLoader , mockFlutterJni ));
995
+ FlutterRenderer flutterRenderer = spy (new FlutterRenderer (mockFlutterJni ));
996
+ when (flutterEngine .getRenderer ()).thenReturn (flutterRenderer );
997
+
998
+ // When we attach a new FlutterView to the engine without any system insets, the viewport
999
+ // metrics
1000
+ // default to 0.
1001
+ flutterView .attachToFlutterEngine (flutterEngine );
1002
+ ArgumentCaptor <FlutterRenderer .ViewportMetrics > viewportMetricsCaptor =
1003
+ ArgumentCaptor .forClass (FlutterRenderer .ViewportMetrics .class );
1004
+ verify (flutterRenderer ).setViewportMetrics (viewportMetricsCaptor .capture ());
1005
+ assertEquals (0 , viewportMetricsCaptor .getValue ().viewPaddingTop );
1006
+ clearInvocations (flutterRenderer );
1007
+ // Then we simulate the system applying a window inset.
1008
+ WindowInsets windowInsets = mock (WindowInsets .class );
1009
+ mockSystemWindowInsets (windowInsets , 100 , 100 , 100 , 100 );
1010
+ flutterView .onApplyWindowInsets (windowInsets );
1011
+
1012
+ // Verify.
1013
+ verify (flutterRenderer , times (1 )).setViewportMetrics (viewportMetricsCaptor .capture ());
1014
+ validateViewportMetricPadding (viewportMetricsCaptor , 100 , 100 , 100 , 0 );
1015
+ clearInvocations (flutterRenderer );
1016
+
1017
+ // Validation when fullscreen
1018
+ when (flutterView .getWindowSystemUiVisibility ()).thenReturn (View .SYSTEM_UI_FLAG_FULLSCREEN );
1019
+
1020
+ // Then we simulate the system applying a window inset.
1021
+ mockSystemWindowInsets (windowInsets , 100 , 100 , 100 , 100 );
1022
+ flutterView .onApplyWindowInsets (windowInsets );
1023
+
1024
+ // Verify.
1025
+ verify (flutterRenderer , times (1 )).setViewportMetrics (viewportMetricsCaptor .capture ());
1026
+ validateViewportMetricPadding (viewportMetricsCaptor , 100 , 0 , 100 , 0 );
1027
+ }
1028
+
940
1029
@ SuppressWarnings ("deprecation" )
941
1030
private void setExpectedDisplayRotation (int rotation ) {
942
1031
ShadowDisplay display =
@@ -976,17 +1065,12 @@ private void mockSystemGestureInsetsIfNeed(WindowInsets windowInsets) {
976
1065
/*
977
1066
* A custom shadow that reports fullscreen flag for system UI visibility
978
1067
*/
979
- @ Implements (View .class )
1068
+ @ Implements (FrameLayout .class )
980
1069
@ SuppressWarnings ("deprecation" )
981
- public static class ShadowFullscreenView {
1070
+ public static class ShadowFullscreenView extends ShadowViewGroup {
982
1071
@ Implementation
983
1072
public int getWindowSystemUiVisibility () {
984
1073
return View .SYSTEM_UI_FLAG_FULLSCREEN ;
985
1074
}
986
1075
}
987
-
988
- // ViewGroup is the first shadow in the type hierarchy for FlutterView. Shadows need to mimic
989
- // production classes' view hierarchy.
990
- @ Implements (ViewGroup .class )
991
- public static class ShadowFullscreenViewGroup extends ShadowFullscreenView {}
992
1076
}
0 commit comments