From 4e727ff5d768d5973d945e1ef2cb91f9dc3a6336 Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Mon, 14 Mar 2022 10:06:40 -0700 Subject: [PATCH 1/2] Revert "Undo Deletion in #31092 (#31661)" This reverts commit 1e5b26b549e5e43f4056a2e08709e189f9721929. --- .../plugin/platform/PlatformPlugin.java | 4 -- .../plugin/platform/PlatformPluginTest.java | 39 ------------------- 2 files changed, 43 deletions(-) diff --git a/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java b/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java index a46213c0f777f..16084fb879e87 100644 --- a/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java +++ b/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java @@ -445,10 +445,6 @@ public void updateSystemUiOverlays() { } } } - - if (currentTheme != null) { - setSystemChromeSystemUIOverlayStyle(currentTheme); - } } private void restoreSystemChromeSystemUIOverlays() { 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 b44d67011d919..ea8448363ca23 100644 --- a/shell/platform/android/test/io/flutter/plugin/platform/PlatformPluginTest.java +++ b/shell/platform/android/test/io/flutter/plugin/platform/PlatformPluginTest.java @@ -6,8 +6,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.anyBoolean; -import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -507,43 +505,6 @@ public void showSystemOverlays() { verify(fakeWindowInsetsController).show(WindowInsetsCompat.Type.navigationBars()); } - @Config(sdk = 30) - @Test - public void verifyUpdateSystemUiOverlaysAppliesCurrentTheme() { - 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); - - // Style that requires usage of all system bar APIs used in PlatformPlugin to update overlay - // style - SystemChromeStyle testStyle = - new SystemChromeStyle( - 0XFF000000, Brightness.LIGHT, true, 0XFFC70039, Brightness.LIGHT, 0XFF006DB3, true); - - platformPlugin.updateSystemUiOverlays(); - - verify(fakeWindow, never()).setStatusBarColor(anyInt()); - verify(fakeWindow, never()).setNavigationBarColor(anyInt()); - verify(fakeWindow, never()).setNavigationBarDividerColor(anyInt()); - verify(fakeWindow, never()).setStatusBarContrastEnforced(anyBoolean()); - verify(fakeWindow, never()).setNavigationBarContrastEnforced(anyBoolean()); - - platformPlugin.mPlatformMessageHandler.setSystemUiOverlayStyle(testStyle); - platformPlugin.updateSystemUiOverlays(); - - verify(fakeWindow, times(2)).setStatusBarColor(0xFF000000); - verify(fakeWindow, times(2)).setNavigationBarColor(0XFFC70039); - verify(fakeWindow, times(2)).setNavigationBarDividerColor(0XFF006DB3); - verify(fakeWindow, times(2)).setStatusBarContrastEnforced(true); - verify(fakeWindow, times(2)).setNavigationBarContrastEnforced(true); - } - @Config(sdk = 28) @Test public void doNotEnableEdgeToEdgeOnOlderSdk() { From c9373e43e910527f47393cf311aee4d06f7048cf Mon Sep 17 00:00:00 2001 From: Emmanuel Garcia Date: Mon, 14 Mar 2022 10:07:00 -0700 Subject: [PATCH 2/2] Revert "Partially remove setSystemUiVisibility() usages (#31092)" This reverts commit 68473fe574a79096aa87c48fc5630dc1c3f40119. --- .../flutter/app/FlutterActivityDelegate.java | 11 +- .../embedding/android/FlutterActivity.java | 10 +- .../android/FlutterFragmentActivity.java | 11 +- .../plugin/platform/PlatformPlugin.java | 190 +++++------------- .../plugin/platform/PlatformPluginTest.java | 172 ++-------------- 5 files changed, 73 insertions(+), 321 deletions(-) diff --git a/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java b/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java index d0bd885197dda..0fe692c49c6c7 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,14 +141,7 @@ public void onCreate(Bundle savedInstanceState) { Window window = activity.getWindow(); window.addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(0x40000000); - WindowCompat.setDecorFitsSystemWindows(window, false); - if (Build.VERSION.SDK_INT < 30) { - // This ensures that the navigation bar is not hidden for APIs < 30, - // as dictated by the implementation of WindowCompat. - View view = window.getDecorView(); - view.setSystemUiVisibility( - view.getSystemUiVisibility() & ~View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); - } + window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI); } 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 9b6b6eed181d1..552550b51f060 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java @@ -38,7 +38,6 @@ 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; @@ -591,14 +590,7 @@ private void configureStatusBarForFullscreenFlutterExperience() { Window window = getWindow(); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(0x40000000); - WindowCompat.setDecorFitsSystemWindows(window, false); - if (Build.VERSION.SDK_INT < 30) { - // This ensures that the navigation bar is not hidden for APIs < 30, - // as dictated by the implementation of WindowCompat. - View view = window.getDecorView(); - view.setSystemUiVisibility( - view.getSystemUiVisibility() & ~View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); - } + window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI); } } diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java index 50382659ed370..d7c8515b4869d 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java @@ -38,7 +38,6 @@ 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; @@ -46,6 +45,7 @@ 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; import io.flutter.util.ViewUtils; /** @@ -495,14 +495,7 @@ private void configureStatusBarForFullscreenFlutterExperience() { Window window = getWindow(); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(0x40000000); - WindowCompat.setDecorFitsSystemWindows(window, false); - if (Build.VERSION.SDK_INT < 30) { - // This ensures that the navigation bar is not hidden for APIs < 30, - // as dictated by the implementation of WindowCompat. - View view = window.getDecorView(); - view.setSystemUiVisibility( - view.getSystemUiVisibility() & ~View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); - } + window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI); } } diff --git a/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java b/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java index 16084fb879e87..a1d38ba0720db 100644 --- a/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java +++ b/shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java @@ -20,8 +20,6 @@ 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; @@ -30,13 +28,14 @@ /** 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 PlatformChannel.SystemUiMode currentSystemUiMode; - private List currentOverlays; + private int mEnabledOverlays; private static final String TAG = "PlatformPlugin"; /** @@ -143,6 +142,8 @@ public PlatformPlugin( this.platformChannel = platformChannel; this.platformChannel.setPlatformMessageHandler(mPlatformMessageHandler); this.platformPluginDelegate = delegate; + + mEnabledOverlays = DEFAULT_SYSTEM_UI; } /** @@ -240,75 +241,17 @@ public void onSystemUiVisibilityChange(int visibility) { } private void setSystemChromeEnabledSystemUIMode(PlatformChannel.SystemUiMode systemUiMode) { - if (Build.VERSION.SDK_INT <= 19) { - // As of API 30, the Android APIs for overlays/insets provides backwards compatibility back - // through API 19. Since Flutter currently supports API 19, the legacy code is used for - // that case. - setSystemChromeEnabledSystemUIModeLegacy(systemUiMode); - } else { - 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. Implemented for API 20+ here. - // 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. - 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 SDK 19. Implemented for API 20+ here. - // 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. - 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 SDK 19. Implemented for API 20+ here. - // 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. - 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 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. - WindowCompat.setDecorFitsSystemWindows(window, false); - } else { - // When none of the conditions are matched, return without updating the system UI overlays. - return; - } - } - currentSystemUiMode = systemUiMode; - } - - private void setSystemChromeEnabledSystemUIModeLegacy(PlatformChannel.SystemUiMode systemUiMode) { int enabledOverlays; - if (systemUiMode == PlatformChannel.SystemUiMode.LEAN_BACK) { + if (systemUiMode == PlatformChannel.SystemUiMode.LEAN_BACK + && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { // LEAN BACK - // Available starting at SDK 16. Implemented for APIs 16-19 here. + // Available starting at SDK 16 + // 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 @@ -318,8 +261,12 @@ private void setSystemChromeEnabledSystemUIModeLegacy(PlatformChannel.SystemUiMo } else if (systemUiMode == PlatformChannel.SystemUiMode.IMMERSIVE && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // IMMERSIVE - // Available starting at SDK 19. Implemented for API 19 here. Earlier versions will not be - // affected by this. + // Available starting at 19 + // 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 @@ -330,8 +277,11 @@ private void setSystemChromeEnabledSystemUIModeLegacy(PlatformChannel.SystemUiMo } else if (systemUiMode == PlatformChannel.SystemUiMode.IMMERSIVE_STICKY && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // STICKY IMMERSIVE - // Available starting at SDK 19. Implemented for API 19 here. Earlier versions will not be - // affected by this. + // Available starting at 19 + // 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 @@ -339,69 +289,44 @@ private void setSystemChromeEnabledSystemUIModeLegacy(PlatformChannel.SystemUiMo | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN; + } 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 + // 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; } else { + // When none of the conditions are matched, return without updating the system UI overlays. return; } - activity.getWindow().getDecorView().setSystemUiVisibility(enabledOverlays); - } - - private void setSystemChromeEnabledSystemUIOverlays( - List overlaysToShow) { - if (Build.VERSION.SDK_INT <= 19) { - // As of API 30, the Android APIs for overlays/insets provides backwards compatibility back - // through API 19. Since Flutter currently supports API 19, the legacy code is used - // for that case. - setSystemChromeEnabledSystemUIOverlaysLegacy(overlaysToShow); - } else { - 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). - 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. - for (int i = 0; i < overlaysToShow.size(); ++i) { - PlatformChannel.SystemUiOverlay overlayToShow = overlaysToShow.get(i); - switch (overlayToShow) { - case TOP_OVERLAYS: - windowInsetsControllerCompat.show(WindowInsetsCompat.Type.statusBars()); - break; - case BOTTOM_OVERLAYS: - windowInsetsControllerCompat.show(WindowInsetsCompat.Type.navigationBars()); - break; - } - } - } - currentOverlays = overlaysToShow; + mEnabledOverlays = enabledOverlays; + updateSystemUiOverlays(); } - private void setSystemChromeEnabledSystemUIOverlaysLegacy( + private void setSystemChromeEnabledSystemUIOverlays( List overlaysToShow) { + // Start by assuming we want to hide all system overlays (like an immersive + // game). int enabledOverlays = - View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + 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. + // 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) { - currentSystemUiMode = PlatformChannel.SystemUiMode.IMMERSIVE_STICKY; enabledOverlays |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; } + // Re-add any desired system overlays. for (int i = 0; i < overlaysToShow.size(); ++i) { PlatformChannel.SystemUiOverlay overlayToShow = overlaysToShow.get(i); switch (overlayToShow) { @@ -414,7 +339,9 @@ private void setSystemChromeEnabledSystemUIOverlaysLegacy( break; } } - activity.getWindow().getDecorView().setSystemUiVisibility(enabledOverlays); + + mEnabledOverlays = enabledOverlays; + updateSystemUiOverlays(); } /** @@ -426,24 +353,9 @@ private void setSystemChromeEnabledSystemUIOverlaysLegacy( * PlatformPlugin}. */ public void updateSystemUiOverlays() { - if (currentOverlays != null) { - setSystemChromeEnabledSystemUIOverlays(currentOverlays); - - if (currentOverlays.size() > 0) { - if (currentSystemUiMode != null) { - setSystemChromeEnabledSystemUIMode(currentSystemUiMode); - } else { - Window window = activity.getWindow(); - WindowCompat.setDecorFitsSystemWindows(window, false); - if (Build.VERSION.SDK_INT < 30) { - // This ensures that the navigation bar is not hidden for APIs < 30, - // as dictated by the implementation of WindowCompat. - View view = window.getDecorView(); - view.setSystemUiVisibility( - view.getSystemUiVisibility() & ~View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); - } - } - } + activity.getWindow().getDecorView().setSystemUiVisibility(mEnabledOverlays); + 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 ea8448363ca23..2a04684aa6ab2 100644 --- a/shell/platform/android/test/io/flutter/plugin/platform/PlatformPluginTest.java +++ b/shell/platform/android/test/io/flutter/plugin/platform/PlatformPluginTest.java @@ -13,7 +13,6 @@ 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; @@ -25,8 +24,6 @@ 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 androidx.test.ext.junit.runners.AndroidJUnit4; import io.flutter.embedding.engine.systemchannels.PlatformChannel; @@ -35,8 +32,6 @@ 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; @@ -318,9 +313,7 @@ public void setStatusBarIconBrightness() { @Config(sdk = 29) @Test - public void setSystemUiModeLegacy() { - // This test reflects the behavior under the hood of the Android overlay/inset APIs used for API - // 20-29 in the plugin. + public void setSystemUiMode() { View fakeDecorView = mock(View.class); Window fakeWindow = mock(Window.class); when(fakeWindow.getDecorView()).thenReturn(fakeDecorView); @@ -332,42 +325,41 @@ public void setSystemUiModeLegacy() { 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_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN); platformPlugin.mPlatformMessageHandler.showSystemUiMode( PlatformChannel.SystemUiMode.IMMERSIVE); - 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)) + verify(fakeDecorView) .setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_STABLE + 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_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN); platformPlugin.mPlatformMessageHandler.showSystemUiMode( PlatformChannel.SystemUiMode.IMMERSIVE_STICKY); - 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)) + verify(fakeDecorView) .setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_STABLE + 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_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN); } if (Build.VERSION.SDK_INT >= 29) { platformPlugin.mPlatformMessageHandler.showSystemUiMode( PlatformChannel.SystemUiMode.EDGE_TO_EDGE); - verify(fakeDecorView, times(4)) + verify(fakeDecorView) .setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION @@ -375,136 +367,6 @@ public void setSystemUiModeLegacy() { } } - @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() { - // This test reflects the behavior under the hood of the Android overlay/inset APIs used for API - // 20-29 in the plugin. - 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() {