diff --git a/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java b/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java index 0fe692c49c6c7..afc3ac9ae640d 100644 --- a/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java +++ b/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java @@ -24,9 +24,9 @@ import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager.LayoutParams; +import androidx.core.view.WindowCompat; import io.flutter.Log; import io.flutter.plugin.common.PluginRegistry; -import io.flutter.plugin.platform.PlatformPlugin; import io.flutter.util.Preconditions; import io.flutter.view.FlutterMain; import io.flutter.view.FlutterNativeView; @@ -141,7 +141,7 @@ public void onCreate(Bundle savedInstanceState) { Window window = activity.getWindow(); window.addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(0x40000000); - window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI); + WindowCompat.setDecorFitsSystemWindows(window, false); } String[] args = getArgsFromIntent(activity.getIntent()); diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java index cee5b20b46e8e..8c5d65aaf5bd1 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java @@ -38,6 +38,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.core.content.res.ResourcesCompat; +import androidx.core.view.WindowCompat; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleRegistry; @@ -581,7 +582,7 @@ private void configureStatusBarForFullscreenFlutterExperience() { Window window = getWindow(); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(0x40000000); - window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI); + WindowCompat.setDecorFitsSystemWindows(window, false); } } diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java index e699c2abeef93..5deee67c156f0 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java @@ -38,6 +38,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.core.content.res.ResourcesCompat; +import androidx.core.view.WindowCompat; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import io.flutter.Log; @@ -45,7 +46,6 @@ import io.flutter.embedding.engine.FlutterEngine; import io.flutter.embedding.engine.FlutterShellArgs; import io.flutter.embedding.engine.plugins.util.GeneratedPluginRegister; -import io.flutter.plugin.platform.PlatformPlugin; /** * A Flutter {@code Activity} that is based upon {@link FragmentActivity}. @@ -493,7 +493,7 @@ private void configureStatusBarForFullscreenFlutterExperience() { Window window = getWindow(); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(0x40000000); - window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI); + WindowCompat.setDecorFitsSystemWindows(window, false); } } diff --git a/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java b/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java index 59733b29bd0b0..586d8de4e50a0 100644 --- a/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java +++ b/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java @@ -20,6 +20,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import androidx.core.view.WindowCompat; +import androidx.core.view.WindowInsetsCompat; import androidx.core.view.WindowInsetsControllerCompat; import io.flutter.Log; import io.flutter.embedding.engine.systemchannels.PlatformChannel; @@ -28,14 +30,13 @@ /** Android implementation of the platform plugin. */ public class PlatformPlugin { - public static final int DEFAULT_SYSTEM_UI = - View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; private final Activity activity; private final PlatformChannel platformChannel; private final PlatformPluginDelegate platformPluginDelegate; private PlatformChannel.SystemChromeStyle currentTheme; - private int mEnabledOverlays; + private PlatformChannel.SystemUiMode currentSystemUiMode; + private List currentOverlays; private static final String TAG = "PlatformPlugin"; /** @@ -141,7 +142,7 @@ public PlatformPlugin( this.platformChannel.setPlatformMessageHandler(mPlatformMessageHandler); this.platformPluginDelegate = delegate; - mEnabledOverlays = DEFAULT_SYSTEM_UI; + currentSystemUiMode = PlatformChannel.SystemUiMode.EDGE_TO_EDGE; } /** @@ -240,87 +241,83 @@ public void onSystemUiVisibilityChange(int visibility) { private void setSystemChromeEnabledSystemUIMode(PlatformChannel.SystemUiMode systemUiMode) { int enabledOverlays; - if (systemUiMode == PlatformChannel.SystemUiMode.LEAN_BACK - && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + Window window = activity.getWindow(); + View view = window.getDecorView(); + WindowInsetsControllerCompat windowInsetsControllerCompat = + new WindowInsetsControllerCompat(window, view); + + if (systemUiMode == PlatformChannel.SystemUiMode.LEAN_BACK) { // LEAN BACK - // Available starting at SDK 16 + // Available starting at SDK 20, due to the backwards compatibility provided by the + // WindowInsetsControllerCompat class for setting the behavior of system bars. // Should not show overlays, tap to reveal overlays, needs onChange callback // When the overlays come in on tap, the app does not receive the gesture and does not know // the system overlay has changed. The overlays cannot be dismissed, so adding the callback // support will allow users to restore the system ui and dismiss the overlays. // Not compatible with top/bottom overlays enabled. - enabledOverlays = - View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN; - } else if (systemUiMode == PlatformChannel.SystemUiMode.IMMERSIVE - && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + windowInsetsControllerCompat.setSystemBarsBehavior( + WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH); + windowInsetsControllerCompat.hide(WindowInsetsCompat.Type.systemBars()); + WindowCompat.setDecorFitsSystemWindows(window, false); + } else if (systemUiMode == PlatformChannel.SystemUiMode.IMMERSIVE) { // IMMERSIVE - // Available starting at 19 + // Available starting at SDK 20, due to the backwards compatibility provided by the + // WindowInsetsControllerCompat class for setting the behavior of system bars. // Should not show overlays, swipe from edges to reveal overlays, needs onChange callback // When the overlays come in on swipe, the app does not receive the gesture and does not know // the system overlay has changed. The overlays cannot be dismissed, so adding callback // support will allow users to restore the system ui and dismiss the overlays. // Not compatible with top/bottom overlays enabled. - enabledOverlays = - View.SYSTEM_UI_FLAG_IMMERSIVE - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN; - } else if (systemUiMode == PlatformChannel.SystemUiMode.IMMERSIVE_STICKY - && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + windowInsetsControllerCompat.setSystemBarsBehavior( + WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE); + windowInsetsControllerCompat.hide(WindowInsetsCompat.Type.systemBars()); + WindowCompat.setDecorFitsSystemWindows(window, false); + } else if (systemUiMode == PlatformChannel.SystemUiMode.IMMERSIVE_STICKY) { // STICKY IMMERSIVE - // Available starting at 19 + // Available starting at SDK 20, due to the backwards compatibility provided by the + // WindowInsetsControllerCompat class for setting the behavior of system bars. // Should not show overlays, swipe from edges to reveal overlays. The app will also receive // the swipe gesture. The overlays cannot be dismissed, so adding callback support will // allow users to restore the system ui and dismiss the overlays. // Not compatible with top/bottom overlays enabled. - enabledOverlays = - View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN; + windowInsetsControllerCompat.setSystemBarsBehavior( + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE); + windowInsetsControllerCompat.hide(WindowInsetsCompat.Type.systemBars()); + WindowCompat.setDecorFitsSystemWindows(window, false); } else if (systemUiMode == PlatformChannel.SystemUiMode.EDGE_TO_EDGE && Build.VERSION.SDK_INT >= 29) { // EDGE TO EDGE - // Available starting at 29 - // SDK 29 and up will apply a translucent body scrim behind 2/3 button navigation bars + // Available starting at SDK 29. See issue for context: + // https://github.com/flutter/flutter/issues/89774. + // Will apply a translucent body scrim behind 2/3 button navigation bars // to ensure contrast with buttons on the nav and status bars, unless the contrast is not // enforced in the overlay styling. - enabledOverlays = - View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; + WindowCompat.setDecorFitsSystemWindows(window, false); } else { // When none of the conditions are matched, return without updating the system UI overlays. return; } - - mEnabledOverlays = enabledOverlays; - updateSystemUiOverlays(); + currentSystemUiMode = systemUiMode; } private void setSystemChromeEnabledSystemUIOverlays( List overlaysToShow) { + Window window = activity.getWindow(); + View view = window.getDecorView(); + WindowInsetsControllerCompat windowInsetsControllerCompat = + new WindowInsetsControllerCompat(window, view); + // Start by assuming we want to hide all system overlays (like an immersive // game). - int enabledOverlays = - DEFAULT_SYSTEM_UI - | View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; - - // The SYSTEM_UI_FLAG_IMMERSIVE_STICKY flag was introduced in API 19, so we - // apply it - // if desired, and if the current Android version is 19 or greater. - if (overlaysToShow.size() == 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - enabledOverlays |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + windowInsetsControllerCompat.hide(WindowInsetsCompat.Type.systemBars()); + WindowCompat.setDecorFitsSystemWindows(window, false); + + // We apply sticky immersive mode if desired. Available starting at SDK 20. + if (overlaysToShow.size() == 0) { + currentSystemUiMode = PlatformChannel.SystemUiMode.IMMERSIVE_STICKY; + + windowInsetsControllerCompat.setSystemBarsBehavior( + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE); } // Re-add any desired system overlays. @@ -328,17 +325,14 @@ private void setSystemChromeEnabledSystemUIOverlays( PlatformChannel.SystemUiOverlay overlayToShow = overlaysToShow.get(i); switch (overlayToShow) { case TOP_OVERLAYS: - enabledOverlays &= ~View.SYSTEM_UI_FLAG_FULLSCREEN; + windowInsetsControllerCompat.show(WindowInsetsCompat.Type.statusBars()); break; case BOTTOM_OVERLAYS: - enabledOverlays &= ~View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; - enabledOverlays &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; + windowInsetsControllerCompat.show(WindowInsetsCompat.Type.navigationBars()); break; } } - - mEnabledOverlays = enabledOverlays; - updateSystemUiOverlays(); + currentOverlays = overlaysToShow; } /** @@ -350,8 +344,11 @@ private void setSystemChromeEnabledSystemUIOverlays( * PlatformPlugin}. */ public void updateSystemUiOverlays() { - activity.getWindow().getDecorView().setSystemUiVisibility(mEnabledOverlays); - if (currentTheme != null) { + setSystemChromeEnabledSystemUIMode(currentSystemUiMode); + + if (currentOverlays != null) { + setSystemChromeEnabledSystemUIOverlays(currentOverlays); + } else if (currentTheme != null) { setSystemChromeSystemUIOverlayStyle(currentTheme); } } diff --git a/shell/platform/android/test/io/flutter/plugin/platform/PlatformPluginTest.java b/shell/platform/android/test/io/flutter/plugin/platform/PlatformPluginTest.java index 3800ddfbff98e..c94eaa262712a 100644 --- a/shell/platform/android/test/io/flutter/plugin/platform/PlatformPluginTest.java +++ b/shell/platform/android/test/io/flutter/plugin/platform/PlatformPluginTest.java @@ -13,6 +13,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.annotation.TargetApi; import android.app.Activity; import android.content.ClipData; import android.content.ClipboardManager; @@ -24,6 +25,8 @@ import android.view.Window; import android.view.WindowInsetsController; import androidx.activity.OnBackPressedCallback; +import androidx.core.view.WindowInsetsCompat; +import androidx.core.view.WindowInsetsControllerCompat; import androidx.fragment.app.FragmentActivity; import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.embedding.engine.systemchannels.PlatformChannel.Brightness; @@ -31,6 +34,8 @@ import io.flutter.embedding.engine.systemchannels.PlatformChannel.SystemChromeStyle; import io.flutter.plugin.platform.PlatformPlugin.PlatformPluginDelegate; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Test; import org.junit.runner.RunWith; @@ -313,7 +318,7 @@ public void setStatusBarIconBrightness() { @Config(sdk = 29) @Test - public void setSystemUiMode() { + public void setSystemUiModeLegacy() { View fakeDecorView = mock(View.class); Window fakeWindow = mock(Window.class); when(fakeWindow.getDecorView()).thenReturn(fakeDecorView); @@ -325,41 +330,45 @@ public void setSystemUiMode() { if (Build.VERSION.SDK_INT >= 28) { platformPlugin.mPlatformMessageHandler.showSystemUiMode( PlatformChannel.SystemUiMode.LEAN_BACK); + + verify(fakeDecorView).setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN); + verify(fakeDecorView).setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); verify(fakeDecorView) .setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN); + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); platformPlugin.mPlatformMessageHandler.showSystemUiMode( PlatformChannel.SystemUiMode.IMMERSIVE); - verify(fakeDecorView) + + verify(fakeDecorView).setSystemUiVisibility(View.SYSTEM_UI_FLAG_IMMERSIVE); + verify(fakeDecorView, times(2)).setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN); + verify(fakeDecorView, times(2)).setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); + verify(fakeDecorView, times(2)) .setSystemUiVisibility( - View.SYSTEM_UI_FLAG_IMMERSIVE - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE + View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN); + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); platformPlugin.mPlatformMessageHandler.showSystemUiMode( PlatformChannel.SystemUiMode.IMMERSIVE_STICKY); - verify(fakeDecorView) + + verify(fakeDecorView).setSystemUiVisibility(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + verify(fakeDecorView, times(3)).setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN); + verify(fakeDecorView, times(3)).setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); + verify(fakeDecorView, times(3)) .setSystemUiVisibility( - View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE + View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_FULLSCREEN); + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); } if (Build.VERSION.SDK_INT >= 29) { platformPlugin.mPlatformMessageHandler.showSystemUiMode( PlatformChannel.SystemUiMode.EDGE_TO_EDGE); - verify(fakeDecorView) + + verify(fakeDecorView, times(4)) .setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION @@ -367,6 +376,134 @@ public void setSystemUiMode() { } } + @TargetApi(30) + @Test + public void setSystemUiMode() { + View fakeDecorView = mock(View.class); + Window fakeWindow = mock(Window.class); + when(fakeWindow.getDecorView()).thenReturn(fakeDecorView); + Activity fakeActivity = mock(Activity.class); + when(fakeActivity.getWindow()).thenReturn(fakeWindow); + PlatformChannel fakePlatformChannel = mock(PlatformChannel.class); + PlatformPlugin platformPlugin = new PlatformPlugin(fakeActivity, fakePlatformChannel); + WindowInsetsController fakeWindowInsetsController = mock(WindowInsetsController.class); + when(fakeWindow.getInsetsController()).thenReturn(fakeWindowInsetsController); + + platformPlugin.mPlatformMessageHandler.showSystemUiMode(PlatformChannel.SystemUiMode.LEAN_BACK); + + verify(fakeWindowInsetsController) + .setSystemBarsBehavior(WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH); + verify(fakeWindowInsetsController).hide(WindowInsetsCompat.Type.systemBars()); + verify(fakeWindow).setDecorFitsSystemWindows(false); + + platformPlugin.mPlatformMessageHandler.showSystemUiMode(PlatformChannel.SystemUiMode.IMMERSIVE); + + verify(fakeWindowInsetsController) + .setSystemBarsBehavior(WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE); + verify(fakeWindowInsetsController, times(2)).hide(WindowInsetsCompat.Type.systemBars()); + verify(fakeWindow, times(2)).setDecorFitsSystemWindows(false); + + platformPlugin.mPlatformMessageHandler.showSystemUiMode( + PlatformChannel.SystemUiMode.IMMERSIVE_STICKY); + + verify(fakeWindowInsetsController) + .setSystemBarsBehavior(WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE); + verify(fakeWindowInsetsController, times(3)).hide(WindowInsetsCompat.Type.systemBars()); + verify(fakeWindow, times(3)).setDecorFitsSystemWindows(false); + + platformPlugin.mPlatformMessageHandler.showSystemUiMode( + PlatformChannel.SystemUiMode.EDGE_TO_EDGE); + + verify(fakeWindow, times(4)).setDecorFitsSystemWindows(false); + } + + @Config(sdk = 29) + @Test + public void showSystemOverlaysLegacy() { + View fakeDecorView = mock(View.class); + Window fakeWindow = mock(Window.class); + when(fakeWindow.getDecorView()).thenReturn(fakeDecorView); + int fakeSetFlags = + View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; + Activity fakeActivity = mock(Activity.class); + when(fakeActivity.getWindow()).thenReturn(fakeWindow); + PlatformChannel fakePlatformChannel = mock(PlatformChannel.class); + PlatformPlugin platformPlugin = new PlatformPlugin(fakeActivity, fakePlatformChannel); + + platformPlugin.mPlatformMessageHandler.showSystemOverlays( + new ArrayList()); + + verify(fakeDecorView).setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN); + verify(fakeDecorView).setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); + verify(fakeDecorView) + .setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + + verify(fakeDecorView).setSystemUiVisibility(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + verify(fakeDecorView).setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN); + verify(fakeDecorView).setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); + verify(fakeDecorView) + .setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + + when(fakeDecorView.getSystemUiVisibility()).thenReturn(fakeSetFlags); + platformPlugin.mPlatformMessageHandler.showSystemOverlays( + new ArrayList( + Arrays.asList( + PlatformChannel.SystemUiOverlay.TOP_OVERLAYS, + PlatformChannel.SystemUiOverlay.BOTTOM_OVERLAYS))); + + verify(fakeDecorView).setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN); + verify(fakeDecorView).setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); + verify(fakeDecorView) + .setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + + verify(fakeDecorView).setSystemUiVisibility(fakeSetFlags &= ~View.SYSTEM_UI_FLAG_FULLSCREEN); + verify(fakeDecorView) + .setSystemUiVisibility(fakeSetFlags &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); + } + + @TargetApi(30) + @Test + public void showSystemOverlays() { + View fakeDecorView = mock(View.class); + Window fakeWindow = mock(Window.class); + when(fakeWindow.getDecorView()).thenReturn(fakeDecorView); + Activity fakeActivity = mock(Activity.class); + when(fakeActivity.getWindow()).thenReturn(fakeWindow); + PlatformChannel fakePlatformChannel = mock(PlatformChannel.class); + PlatformPlugin platformPlugin = new PlatformPlugin(fakeActivity, fakePlatformChannel); + WindowInsetsController fakeWindowInsetsController = mock(WindowInsetsController.class); + when(fakeWindow.getInsetsController()).thenReturn(fakeWindowInsetsController); + + platformPlugin.mPlatformMessageHandler.showSystemOverlays( + new ArrayList()); + + verify(fakeWindowInsetsController) + .setSystemBarsBehavior(WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE); + verify(fakeWindowInsetsController).hide(WindowInsetsCompat.Type.systemBars()); + + platformPlugin.mPlatformMessageHandler.showSystemOverlays( + new ArrayList( + Arrays.asList( + PlatformChannel.SystemUiOverlay.TOP_OVERLAYS, + PlatformChannel.SystemUiOverlay.BOTTOM_OVERLAYS))); + + verify(fakeWindowInsetsController).show(WindowInsetsCompat.Type.statusBars()); + verify(fakeWindowInsetsController).show(WindowInsetsCompat.Type.navigationBars()); + } + @Config(sdk = 28) @Test public void doNotEnableEdgeToEdgeOnOlderSdk() {