Skip to content

Commit

Permalink
Partially remove setSystemUiVisibility() usages (flutter#31092)
Browse files Browse the repository at this point in the history
  • Loading branch information
camsim99 authored Feb 17, 2022
1 parent 0ca8e1a commit 68473fe
Show file tree
Hide file tree
Showing 5 changed files with 321 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -141,7 +141,14 @@ 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);
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);
}
}

String[] args = getArgsFromIntent(activity.getIntent());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -590,7 +591,14 @@ 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);
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);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@
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;
import io.flutter.embedding.android.FlutterActivityLaunchConfigs.BackgroundMode;
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;

/**
Expand Down Expand Up @@ -495,7 +495,14 @@ 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);
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);
}
}
}

Expand Down
190 changes: 139 additions & 51 deletions shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<PlatformChannel.SystemUiOverlay> currentOverlays;
private static final String TAG = "PlatformPlugin";

/**
Expand Down Expand Up @@ -140,8 +141,6 @@ public PlatformPlugin(
this.platformChannel = platformChannel;
this.platformChannel.setPlatformMessageHandler(mPlatformMessageHandler);
this.platformPluginDelegate = delegate;

mEnabledOverlays = DEFAULT_SYSTEM_UI;
}

/**
Expand Down Expand Up @@ -238,17 +237,75 @@ 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
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (systemUiMode == PlatformChannel.SystemUiMode.LEAN_BACK) {
// LEAN BACK
// 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.
// Available starting at SDK 16. Implemented for APIs 16-19 here.
enabledOverlays =
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
Expand All @@ -258,12 +315,8 @@ private void setSystemChromeEnabledSystemUIMode(PlatformChannel.SystemUiMode sys
} else if (systemUiMode == PlatformChannel.SystemUiMode.IMMERSIVE
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// IMMERSIVE
// 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.
// Available starting at SDK 19. Implemented for API 19 here. Earlier versions will not be
// affected by this.
enabledOverlays =
View.SYSTEM_UI_FLAG_IMMERSIVE
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
Expand All @@ -274,56 +327,78 @@ private void setSystemChromeEnabledSystemUIMode(PlatformChannel.SystemUiMode sys
} else if (systemUiMode == PlatformChannel.SystemUiMode.IMMERSIVE_STICKY
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// STICKY IMMERSIVE
// 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.
// Available starting at SDK 19. Implemented for API 19 here. Earlier versions will not be
// affected by this.
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;
} 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;
}

mEnabledOverlays = enabledOverlays;
updateSystemUiOverlays();
activity.getWindow().getDecorView().setSystemUiVisibility(enabledOverlays);
}

private void setSystemChromeEnabledSystemUIOverlays(
List<PlatformChannel.SystemUiOverlay> overlaysToShow) {
// Start by assuming we want to hide all system overlays (like an immersive
// game).
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;
}

private void setSystemChromeEnabledSystemUIOverlaysLegacy(
List<PlatformChannel.SystemUiOverlay> overlaysToShow) {
int enabledOverlays =
DEFAULT_SYSTEM_UI
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| 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.
// apply it if desired.
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) {
Expand All @@ -336,9 +411,7 @@ private void setSystemChromeEnabledSystemUIOverlays(
break;
}
}

mEnabledOverlays = enabledOverlays;
updateSystemUiOverlays();
activity.getWindow().getDecorView().setSystemUiVisibility(enabledOverlays);
}

/**
Expand All @@ -350,9 +423,24 @@ private void setSystemChromeEnabledSystemUIOverlays(
* PlatformPlugin}.
*/
public void updateSystemUiOverlays() {
activity.getWindow().getDecorView().setSystemUiVisibility(mEnabledOverlays);
if (currentTheme != null) {
setSystemChromeSystemUIOverlayStyle(currentTheme);
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);
}
}
}
}
}

Expand Down
Loading

0 comments on commit 68473fe

Please sign in to comment.