@@ -2029,8 +2029,10 @@ public void sendAppPrivateCommand_hasData() throws JSONException {
20292029 @ Test
20302030 @ TargetApi (30 )
20312031 @ Config (sdk = 30 )
2032- public void ime_windowInsetsSync () {
2033- FlutterView testView = new FlutterView (Robolectric .setupActivity (Activity .class ));
2032+ public void ime_windowInsetsSync_notLaidOutBehindNavigation_excludesNavigationBars () {
2033+ FlutterView testView = spy (new FlutterView (Robolectric .setupActivity (Activity .class )));
2034+ when (testView .getWindowSystemUiVisibility ()).thenReturn (View .SYSTEM_UI_FLAG_LAYOUT_STABLE );
2035+
20342036 TextInputChannel textInputChannel = new TextInputChannel (mock (DartExecutor .class ));
20352037 TextInputPlugin textInputPlugin =
20362038 new TextInputPlugin (testView , textInputChannel , mock (PlatformViewsController .class ));
@@ -2046,76 +2048,136 @@ public void ime_windowInsetsSync() {
20462048 List <WindowInsetsAnimation > animationList = new ArrayList ();
20472049 animationList .add (animation );
20482050
2051+ ArgumentCaptor <FlutterRenderer .ViewportMetrics > viewportMetricsCaptor =
2052+ ArgumentCaptor .forClass (FlutterRenderer .ViewportMetrics .class );
2053+
20492054 WindowInsets .Builder builder = new WindowInsets .Builder ();
2050- WindowInsets noneInsets = builder .build ();
20512055
2052- // imeInsets0, 1, and 2 contain unique IME bottom insets, and are used
2053- // to distinguish which insets were sent at each stage.
2056+ // Set the initial insets and verify that they were set and the bottom view inset is correct
2057+ imeSyncCallback .getInsetsListener ().onApplyWindowInsets (testView , builder .build ());
2058+
2059+ verify (flutterRenderer , atLeast (1 )).setViewportMetrics (viewportMetricsCaptor .capture ());
2060+ assertEquals (0 , viewportMetricsCaptor .getValue ().viewInsetBottom );
2061+
2062+ // Call onPrepare and set the lastWindowInsets - these should be stored for the end of the
2063+ // animation instead of being applied immediately
2064+ imeSyncCallback .getAnimationCallback ().onPrepare (animation );
20542065 builder .setInsets (WindowInsets .Type .ime (), Insets .of (0 , 0 , 0 , 100 ));
2055- builder .setInsets (WindowInsets .Type .navigationBars (), Insets .of (10 , 10 , 10 , 40 ));
2056- WindowInsets imeInsets0 = builder .build ();
2066+ builder .setInsets (WindowInsets .Type .navigationBars (), Insets .of (0 , 0 , 0 , 0 ));
2067+ imeSyncCallback .getInsetsListener ().onApplyWindowInsets (testView , builder .build ());
2068+
2069+ verify (flutterRenderer , atLeast (1 )).setViewportMetrics (viewportMetricsCaptor .capture ());
2070+ assertEquals (0 , viewportMetricsCaptor .getValue ().viewInsetBottom );
2071+
2072+ // Call onStart and apply new insets - these should be ignored completely
2073+ imeSyncCallback .getAnimationCallback ().onStart (animation , null );
2074+ builder .setInsets (WindowInsets .Type .ime (), Insets .of (0 , 0 , 0 , 50 ));
2075+ builder .setInsets (WindowInsets .Type .navigationBars (), Insets .of (0 , 0 , 0 , 40 ));
2076+ imeSyncCallback .getInsetsListener ().onApplyWindowInsets (testView , builder .build ());
20572077
2058- builder .setInsets (WindowInsets .Type .ime (), Insets .of (0 , 0 , 0 , 30 ));
2059- builder .setInsets (WindowInsets .Type .navigationBars (), Insets .of (10 , 10 , 10 , 40 ));
2060- WindowInsets imeInsets1 = builder .build ();
2078+ verify (flutterRenderer , atLeast (1 )).setViewportMetrics (viewportMetricsCaptor .capture ());
2079+ assertEquals (0 , viewportMetricsCaptor .getValue ().viewInsetBottom );
2080+
2081+ // Progress the animation and ensure that the navigation bar insets have been subtracted
2082+ // from the IME insets
2083+ builder .setInsets (WindowInsets .Type .ime (), Insets .of (0 , 0 , 0 , 25 ));
2084+ builder .setInsets (WindowInsets .Type .navigationBars (), Insets .of (0 , 0 , 0 , 40 ));
2085+ imeSyncCallback .getAnimationCallback ().onProgress (builder .build (), animationList );
2086+
2087+ verify (flutterRenderer , atLeast (1 )).setViewportMetrics (viewportMetricsCaptor .capture ());
2088+ assertEquals (0 , viewportMetricsCaptor .getValue ().viewInsetBottom );
20612089
20622090 builder .setInsets (WindowInsets .Type .ime (), Insets .of (0 , 0 , 0 , 50 ));
2063- builder .setInsets (WindowInsets .Type .navigationBars (), Insets .of (10 , 10 , 10 , 40 ));
2064- WindowInsets imeInsets2 = builder .build ();
2091+ builder .setInsets (WindowInsets .Type .navigationBars (), Insets .of (0 , 0 , 0 , 40 ));
2092+ imeSyncCallback .getAnimationCallback ().onProgress (builder .build (), animationList );
2093+
2094+ verify (flutterRenderer , atLeast (1 )).setViewportMetrics (viewportMetricsCaptor .capture ());
2095+ assertEquals (10 , viewportMetricsCaptor .getValue ().viewInsetBottom );
2096+
2097+ // End the animation and ensure that the bottom insets match the lastWindowInsets that we set
2098+ // during onPrepare
2099+ imeSyncCallback .getAnimationCallback ().onEnd (animation );
2100+
2101+ verify (flutterRenderer , atLeast (1 )).setViewportMetrics (viewportMetricsCaptor .capture ());
2102+ assertEquals (100 , viewportMetricsCaptor .getValue ().viewInsetBottom );
2103+ }
2104+
2105+ @ Test
2106+ @ TargetApi (30 )
2107+ @ Config (sdk = 30 )
2108+ public void ime_windowInsetsSync_laidOutBehindNavigation_includesNavigationBars () {
2109+ FlutterView testView = spy (new FlutterView (Robolectric .setupActivity (Activity .class )));
2110+ when (testView .getWindowSystemUiVisibility ())
2111+ .thenReturn (
2112+ View .SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View .SYSTEM_UI_FLAG_HIDE_NAVIGATION );
2113+
2114+ TextInputChannel textInputChannel = new TextInputChannel (mock (DartExecutor .class ));
2115+ TextInputPlugin textInputPlugin =
2116+ new TextInputPlugin (testView , textInputChannel , mock (PlatformViewsController .class ));
2117+ ImeSyncDeferringInsetsCallback imeSyncCallback = textInputPlugin .getImeSyncCallback ();
2118+ FlutterEngine flutterEngine = spy (new FlutterEngine (ctx , mockFlutterLoader , mockFlutterJni ));
2119+ FlutterRenderer flutterRenderer = spy (new FlutterRenderer (mockFlutterJni ));
2120+ when (flutterEngine .getRenderer ()).thenReturn (flutterRenderer );
2121+ testView .attachToFlutterEngine (flutterEngine );
20652122
2066- builder .setInsets (WindowInsets .Type .ime (), Insets .of (0 , 0 , 0 , 200 ));
2067- builder .setInsets (WindowInsets .Type .navigationBars (), Insets .of (10 , 10 , 10 , 0 ));
2068- WindowInsets deferredInsets = builder .build ();
2123+ WindowInsetsAnimation animation = mock (WindowInsetsAnimation .class );
2124+ when (animation .getTypeMask ()).thenReturn (WindowInsets .Type .ime ());
2125+
2126+ List <WindowInsetsAnimation > animationList = new ArrayList ();
2127+ animationList .add (animation );
20692128
20702129 ArgumentCaptor <FlutterRenderer .ViewportMetrics > viewportMetricsCaptor =
20712130 ArgumentCaptor .forClass (FlutterRenderer .ViewportMetrics .class );
20722131
2073- imeSyncCallback .getInsetsListener ().onApplyWindowInsets (testView , deferredInsets );
2074- imeSyncCallback .getInsetsListener ().onApplyWindowInsets (testView , noneInsets );
2132+ WindowInsets .Builder builder = new WindowInsets .Builder ();
2133+
2134+ // Set the initial insets and verify that they were set and the bottom view inset is correct
2135+ imeSyncCallback .getInsetsListener ().onApplyWindowInsets (testView , builder .build ());
20752136
20762137 verify (flutterRenderer , atLeast (1 )).setViewportMetrics (viewportMetricsCaptor .capture ());
2077- assertEquals (0 , viewportMetricsCaptor .getValue ().viewPaddingBottom );
2078- assertEquals (0 , viewportMetricsCaptor .getValue ().viewPaddingTop );
20792138 assertEquals (0 , viewportMetricsCaptor .getValue ().viewInsetBottom );
2080- assertEquals (0 , viewportMetricsCaptor .getValue ().viewInsetTop );
20812139
2140+ // Call onPrepare and set the lastWindowInsets - these should be stored for the end of the
2141+ // animation instead of being applied immediately
20822142 imeSyncCallback .getAnimationCallback ().onPrepare (animation );
2083- imeSyncCallback .getInsetsListener ().onApplyWindowInsets (testView , deferredInsets );
2143+ builder .setInsets (WindowInsets .Type .ime (), Insets .of (0 , 0 , 0 , 100 ));
2144+ builder .setInsets (WindowInsets .Type .navigationBars (), Insets .of (0 , 0 , 0 , 0 ));
2145+ imeSyncCallback .getInsetsListener ().onApplyWindowInsets (testView , builder .build ());
2146+
2147+ verify (flutterRenderer , atLeast (1 )).setViewportMetrics (viewportMetricsCaptor .capture ());
2148+ assertEquals (0 , viewportMetricsCaptor .getValue ().viewInsetBottom );
2149+
2150+ // Call onStart and apply new insets - these should be ignored completely
20842151 imeSyncCallback .getAnimationCallback ().onStart (animation , null );
2085- // Only the final state call is saved, extra calls are passed on.
2086- imeSyncCallback .getInsetsListener ().onApplyWindowInsets (testView , imeInsets2 );
2152+ builder .setInsets (WindowInsets .Type .ime (), Insets .of (0 , 0 , 0 , 50 ));
2153+ builder .setInsets (WindowInsets .Type .navigationBars (), Insets .of (0 , 0 , 0 , 40 ));
2154+ imeSyncCallback .getInsetsListener ().onApplyWindowInsets (testView , builder .build ());
20872155
20882156 verify (flutterRenderer , atLeast (1 )).setViewportMetrics (viewportMetricsCaptor .capture ());
2089- // No change, as deferredInset is stored to be passed in onEnd()
2090- assertEquals (0 , viewportMetricsCaptor .getValue ().viewPaddingBottom );
2091- assertEquals (0 , viewportMetricsCaptor .getValue ().viewPaddingTop );
20922157 assertEquals (0 , viewportMetricsCaptor .getValue ().viewInsetBottom );
2093- assertEquals (0 , viewportMetricsCaptor .getValue ().viewInsetTop );
20942158
2095- imeSyncCallback .getAnimationCallback ().onProgress (imeInsets0 , animationList );
2159+ // Progress the animation and ensure that the navigation bar insets have not been
2160+ // subtracted from the IME insets
2161+ builder .setInsets (WindowInsets .Type .ime (), Insets .of (0 , 0 , 0 , 25 ));
2162+ builder .setInsets (WindowInsets .Type .navigationBars (), Insets .of (0 , 0 , 0 , 40 ));
2163+ imeSyncCallback .getAnimationCallback ().onProgress (builder .build (), animationList );
20962164
20972165 verify (flutterRenderer , atLeast (1 )).setViewportMetrics (viewportMetricsCaptor .capture ());
2098- assertEquals (0 , viewportMetricsCaptor .getValue ().viewPaddingBottom );
2099- assertEquals (10 , viewportMetricsCaptor .getValue ().viewPaddingTop );
2100- assertEquals (60 , viewportMetricsCaptor .getValue ().viewInsetBottom );
2101- assertEquals (0 , viewportMetricsCaptor .getValue ().viewInsetTop );
2166+ assertEquals (25 , viewportMetricsCaptor .getValue ().viewInsetBottom );
21022167
2103- imeSyncCallback .getAnimationCallback ().onProgress (imeInsets1 , animationList );
2168+ builder .setInsets (WindowInsets .Type .ime (), Insets .of (0 , 0 , 0 , 50 ));
2169+ builder .setInsets (WindowInsets .Type .navigationBars (), Insets .of (0 , 0 , 0 , 40 ));
2170+ imeSyncCallback .getAnimationCallback ().onProgress (builder .build (), animationList );
21042171
21052172 verify (flutterRenderer , atLeast (1 )).setViewportMetrics (viewportMetricsCaptor .capture ());
2106- assertEquals (0 , viewportMetricsCaptor .getValue ().viewPaddingBottom );
2107- assertEquals (10 , viewportMetricsCaptor .getValue ().viewPaddingTop );
2108- assertEquals (0 , viewportMetricsCaptor .getValue ().viewInsetBottom ); // Cannot be negative
2109- assertEquals (0 , viewportMetricsCaptor .getValue ().viewInsetTop );
2173+ assertEquals (50 , viewportMetricsCaptor .getValue ().viewInsetBottom );
21102174
2175+ // End the animation and ensure that the bottom insets match the lastWindowInsets that we set
2176+ // during onPrepare
21112177 imeSyncCallback .getAnimationCallback ().onEnd (animation );
21122178
21132179 verify (flutterRenderer , atLeast (1 )).setViewportMetrics (viewportMetricsCaptor .capture ());
2114- // Values should be of deferredInsets, not imeInsets2
2115- assertEquals (0 , viewportMetricsCaptor .getValue ().viewPaddingBottom );
2116- assertEquals (10 , viewportMetricsCaptor .getValue ().viewPaddingTop );
2117- assertEquals (200 , viewportMetricsCaptor .getValue ().viewInsetBottom );
2118- assertEquals (0 , viewportMetricsCaptor .getValue ().viewInsetTop );
2180+ assertEquals (100 , viewportMetricsCaptor .getValue ().viewInsetBottom );
21192181 }
21202182
21212183 @ Test
0 commit comments