Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit c9f6b47

Browse files
committed
Set system bar appearance using WindowInsetsControllerCompat instead of the deprecated View#setSystemUiVisibility
The deprecated APIs conflict with Android 12's `SplashScreenView#remove` behavior causing light status bar icon on light background.
1 parent 5ed6b7f commit c9f6b47

4 files changed

Lines changed: 118 additions & 8 deletions

File tree

shell/platform/android/io/flutter/plugin/platform/PlatformPlugin.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import androidx.annotation.NonNull;
2121
import androidx.annotation.Nullable;
2222
import androidx.annotation.VisibleForTesting;
23+
import androidx.core.view.WindowInsetsControllerCompat;
2324
import io.flutter.Log;
2425
import io.flutter.embedding.engine.systemchannels.PlatformChannel;
2526
import java.io.FileNotFoundException;
@@ -364,7 +365,8 @@ private void setSystemChromeSystemUIOverlayStyle(
364365
PlatformChannel.SystemChromeStyle systemChromeStyle) {
365366
Window window = activity.getWindow();
366367
View view = window.getDecorView();
367-
int flags = view.getSystemUiVisibility();
368+
WindowInsetsControllerCompat windowInsetsControllerCompat
369+
= new WindowInsetsControllerCompat(window, view);
368370

369371
// SYSTEM STATUS BAR -------------------------------------------------------------------
370372
// You can't change the color of the system status bar until SDK 21, and you can't change the
@@ -376,12 +378,15 @@ private void setSystemChromeSystemUIOverlayStyle(
376378
if (Build.VERSION.SDK_INT >= 23) {
377379
if (systemChromeStyle.statusBarIconBrightness != null) {
378380
switch (systemChromeStyle.statusBarIconBrightness) {
381+
// Dark icon color.
379382
case DARK:
380-
// View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
381-
flags |= 0x2000;
383+
// Light background color.
384+
windowInsetsControllerCompat.setAppearanceLightStatusBars(true);
382385
break;
386+
// Light icon color.
383387
case LIGHT:
384-
flags &= ~0x2000;
388+
// Dark background color.
389+
windowInsetsControllerCompat.setAppearanceLightStatusBars(false);
385390
break;
386391
}
387392
}
@@ -407,12 +412,15 @@ private void setSystemChromeSystemUIOverlayStyle(
407412
if (Build.VERSION.SDK_INT >= 26) {
408413
if (systemChromeStyle.systemNavigationBarIconBrightness != null) {
409414
switch (systemChromeStyle.systemNavigationBarIconBrightness) {
415+
// Dark icon color.
410416
case DARK:
411-
// View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
412-
flags |= 0x10;
417+
// Light background color.
418+
windowInsetsControllerCompat.setAppearanceLightNavigationBars(true);
413419
break;
420+
// Light icon color.
414421
case LIGHT:
415-
flags &= ~0x10;
422+
// Dark background color.
423+
windowInsetsControllerCompat.setAppearanceLightNavigationBars(false);
416424
break;
417425
}
418426
}
@@ -437,7 +445,6 @@ private void setSystemChromeSystemUIOverlayStyle(
437445
systemChromeStyle.systemNavigationBarContrastEnforced);
438446
}
439447

440-
view.setSystemUiVisibility(flags);
441448
currentTheme = systemChromeStyle;
442449
}
443450

shell/platform/android/test/io/flutter/plugin/platform/PlatformPluginTest.java

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
import android.os.Build;
2121
import android.view.View;
2222
import android.view.Window;
23+
import android.view.WindowInsetsControllerCompat;
24+
import android.view.WindowInsetsControllerCompat.APPEARANCE_LIGHT_NAVIGATION_BARS;
25+
import android.view.WindowInsetsControllerCompat.APPEARANCE_LIGHT_STATUS_BARS;
2326
import androidx.activity.OnBackPressedCallback;
2427
import androidx.fragment.app.FragmentActivity;
2528
import io.flutter.embedding.engine.systemchannels.PlatformChannel;
@@ -190,6 +193,97 @@ public void setNavigationBarDividerColor() {
190193
}
191194
}
192195

196+
@Config(sdk = 30)
197+
@Test
198+
public void setNavigationBarIconBrightness() {
199+
View fakeDecorView = mock(View.class);
200+
WindowInsetsController fakeWindowInsetsController = mock(WindowInsetsController.class);
201+
Window fakeWindow = mock(Window.class);
202+
when(fakeWindow.getDecorView()).thenReturn(fakeDecorView);
203+
when(fakeWindow.getInsetsController()).thenReturn(fakeWindowInsetsController);
204+
Activity fakeActivity = mock(Activity.class);
205+
when(fakeActivity.getWindow()).thenReturn(fakeWindow);
206+
PlatformChannel fakePlatformChannel = mock(PlatformChannel.class);
207+
PlatformPlugin platformPlugin = new PlatformPlugin(fakeActivity, fakePlatformChannel);
208+
209+
if (Build.VERSION.SDK_INT >= 30) {
210+
SystemChromeStyle style =
211+
new SystemChromeStyle(
212+
null, // statusBarColor
213+
Brightness.LIGHT, // statusBarIconBrightness
214+
null, // systemStatusBarContrastEnforced
215+
null, // systemNavigationBarColor
216+
null, // systemNavigationBarIconBrightness
217+
null, // systemNavigationBarDividerColor
218+
null); // systemNavigationBarContrastEnforced
219+
220+
platformPlugin.mPlatformMessageHandler.setSystemUiOverlayStyle(style);
221+
222+
verify(fakeWindowInsetsController).setSystemBarsAppearance(
223+
0, APPEARANCE_LIGHT_NAVIGATION_BARS);
224+
225+
SystemChromeStyle style =
226+
new SystemChromeStyle(
227+
null, // statusBarColor
228+
Brightness.DARK, // statusBarIconBrightness
229+
null, // systemStatusBarContrastEnforced
230+
null, // systemNavigationBarColor
231+
null, // systemNavigationBarIconBrightness
232+
null, // systemNavigationBarDividerColor
233+
null); // systemNavigationBarContrastEnforced
234+
235+
platformPlugin.mPlatformMessageHandler.setSystemUiOverlayStyle(style);
236+
237+
verify(fakeWindowInsetsController).setSystemBarsAppearance(
238+
APPEARANCE_LIGHT_NAVIGATION_BARS, APPEARANCE_LIGHT_NAVIGATION_BARS);
239+
}
240+
}
241+
242+
@Config(sdk = 30)
243+
@Test
244+
public void setStatusBarIconBrightness() {
245+
View fakeDecorView = mock(View.class);
246+
WindowInsetsController fakeWindowInsetsController = mock(WindowInsetsController.class);
247+
Window fakeWindow = mock(Window.class);
248+
when(fakeWindow.getDecorView()).thenReturn(fakeDecorView);
249+
when(fakeWindow.getInsetsController()).thenReturn(fakeWindowInsetsController);
250+
Activity fakeActivity = mock(Activity.class);
251+
when(fakeActivity.getWindow()).thenReturn(fakeWindow);
252+
PlatformChannel fakePlatformChannel = mock(PlatformChannel.class);
253+
PlatformPlugin platformPlugin = new PlatformPlugin(fakeActivity, fakePlatformChannel);
254+
255+
if (Build.VERSION.SDK_INT >= 30) {
256+
SystemChromeStyle style =
257+
new SystemChromeStyle(
258+
null, // statusBarColor
259+
null, // statusBarIconBrightness
260+
null, // systemStatusBarContrastEnforced
261+
null, // systemNavigationBarColor
262+
Brightness.LIGHT, // systemNavigationBarIconBrightness
263+
null, // systemNavigationBarDividerColor
264+
null); // systemNavigationBarContrastEnforced
265+
266+
platformPlugin.mPlatformMessageHandler.setSystemUiOverlayStyle(style);
267+
268+
verify(fakeWindowInsetsController).setSystemBarsAppearance(0, APPEARANCE_LIGHT_STATUS_BARS);
269+
270+
SystemChromeStyle style =
271+
new SystemChromeStyle(
272+
null, // statusBarColor
273+
null, // statusBarIconBrightness
274+
null, // systemStatusBarContrastEnforced
275+
null, // systemNavigationBarColor
276+
Brightness.DARK, // systemNavigationBarIconBrightness
277+
null, // systemNavigationBarDividerColor
278+
null); // systemNavigationBarContrastEnforced
279+
280+
platformPlugin.mPlatformMessageHandler.setSystemUiOverlayStyle(style);
281+
282+
verify(fakeWindowInsetsController).setSystemBarsAppearance(
283+
APPEARANCE_LIGHT_STATUS_BARS, APPEARANCE_LIGHT_STATUS_BARS);
284+
}
285+
}
286+
193287
@Config(sdk = 29)
194288
@Test
195289
public void setSystemUiMode() {

tools/androidx/files.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,13 @@
4949
"androidx.annotation.UiThread",
5050
"androidx.annotation.VisibleForTesting"
5151
]
52+
},
53+
{
54+
"url": "https://maven.google.com/androidx/core/core/1.6.0/core-1.6.0-sources.jar",
55+
"out_file_name": "androidx_core.jar",
56+
"maven_dependency": "androidx.core:core:1.6.0",
57+
"provides": [
58+
"androidx.core.view.WindowInsetsControllerCompat"
59+
]
5260
}
5361
]

tools/cipd/android_embedding_bundle/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ android {
4141

4242
dependencies {
4343
embedding "androidx.annotation:annotation:1.1.0"
44+
embedding "androidx.core:core:1.6.0"
4445
embedding "androidx.fragment:fragment:1.1.0"
4546

4647
def lifecycle_version = "2.2.0"

0 commit comments

Comments
 (0)