capacitor-plugin-status-bar 2.0.2 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -42,62 +42,65 @@ public class StatusBar extends Plugin {
42
42
  private int currentStatusBarColor = Color.BLACK;
43
43
  private int currentNavBarColor = Color.BLACK;
44
44
 
45
- @Override
46
- public void load() {
47
- super.load();
48
- setupEdgeToEdgeBehavior();
49
- }
50
-
51
- private void setupEdgeToEdgeBehavior() {
52
- Activity activity = getActivity();
53
- if (activity == null)
54
- return;
55
-
56
- Window window = activity.getWindow();
57
- View decorView = window.getDecorView();
58
-
59
- WindowCompat.setDecorFitsSystemWindows(window, false);
60
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { // Android 14+
61
- ViewCompat.setOnApplyWindowInsetsListener(decorView, (v, insets) -> {
62
- ViewCompat.onApplyWindowInsets(v, insets);
63
- return insets;
64
- });
65
- }
66
- }
45
+ // Note: load() is not called since StatusBar is instantiated via new StatusBar()
46
+ // from StatusBarPlugin, not registered as a Capacitor plugin itself.
47
+ // All initialization happens via ensureEdgeToEdgeConfigured() called from StatusBarPlugin.load().
67
48
 
68
49
  /**
69
50
  * Ensures edge-to-edge is properly configured for Android 15+.
70
- * This fixes the keyboard extra space issue by properly handling IME insets
71
- * using the modern WindowInsets API instead of deprecated soft input modes.
51
+ * Sets up a unified insets listener on the decorView that handles both
52
+ * IME insets and overlay view sizing.
72
53
  *
73
54
  * @param activity The activity to configure
74
55
  */
75
56
  public void ensureEdgeToEdgeConfigured(Activity activity) {
76
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { // Android 15 (API 35)
77
- Window window = activity.getWindow();
78
- View decorView = window.getDecorView();
57
+ Window window = activity.getWindow();
58
+ View decorView = window.getDecorView();
79
59
 
80
- // Enable edge-to-edge mode for Android 15+
81
- WindowCompat.setDecorFitsSystemWindows(window, false);
60
+ // Enable edge-to-edge for ALL API levels.
61
+ // window.setStatusBarColor() is unreliable on many devices/OEMs,
62
+ // so we use overlay views to control bar colors consistently.
63
+ WindowCompat.setDecorFitsSystemWindows(window, false);
82
64
 
83
- ViewCompat.setOnApplyWindowInsetsListener(decorView, (v, insets) -> {
84
- androidx.core.graphics.Insets imeInsets = insets.getInsets(WindowInsetsCompat.Type.ime());
85
- androidx.core.graphics.Insets systemBarsInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars());
65
+ // Make native bar colors transparent so our overlays are the sole color source
66
+ window.setStatusBarColor(Color.TRANSPARENT);
67
+ window.setNavigationBarColor(Color.TRANSPARENT);
68
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
69
+ window.setStatusBarContrastEnforced(false);
70
+ window.setNavigationBarContrastEnforced(false);
71
+ }
86
72
 
87
- boolean isKeyboardVisible = imeInsets.bottom > 0;
88
- Log.d(TAG, "ensureEdgeToEdgeConfigured: IME visible=" + isKeyboardVisible
89
- + ", IME bottom=" + imeInsets.bottom
90
- + ", system bars bottom=" + systemBarsInsets.bottom);
73
+ // Single unified insets listener on decorView for overlay sizing
74
+ ViewCompat.setOnApplyWindowInsetsListener(decorView, (v, insets) -> {
75
+ // Size status bar overlay
76
+ int top = insets.getInsets(WindowInsetsCompat.Type.statusBars()).top;
77
+ View statusOverlay = ((ViewGroup) v).findViewWithTag(STATUS_BAR_OVERLAY_TAG);
78
+ if (statusOverlay != null) {
79
+ ViewGroup.LayoutParams params = statusOverlay.getLayoutParams();
80
+ if (params.height != top) {
81
+ params.height = top;
82
+ statusOverlay.setLayoutParams(params);
83
+ Log.d(TAG, "insetsListener: status bar overlay height=" + top);
84
+ }
85
+ }
91
86
 
92
- ViewCompat.onApplyWindowInsets(v, insets);
93
- return insets;
94
- });
87
+ // Size navigation bar overlay
88
+ int bottom = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;
89
+ View navOverlay = ((ViewGroup) v).findViewWithTag(NAV_BAR_OVERLAY_TAG);
90
+ if (navOverlay != null) {
91
+ ViewGroup.LayoutParams params = navOverlay.getLayoutParams();
92
+ if (params.height != bottom) {
93
+ params.height = bottom;
94
+ navOverlay.setLayoutParams(params);
95
+ Log.d(TAG, "insetsListener: nav bar overlay height=" + bottom);
96
+ }
97
+ }
95
98
 
96
- Log.d(TAG,
97
- "ensureEdgeToEdgeConfigured: Edge-to-edge enabled with WindowInsets API for Android 15+ (API 35+)");
98
- } else {
99
- Log.d(TAG, "ensureEdgeToEdgeConfigured: Android < 15, no action needed");
100
- }
99
+ ViewCompat.onApplyWindowInsets(v, insets);
100
+ return insets;
101
+ });
102
+
103
+ Log.d(TAG, "ensureEdgeToEdgeConfigured: edge-to-edge with overlay views, API=" + Build.VERSION.SDK_INT);
101
104
  }
102
105
 
103
106
  public void setOverlaysWebView(Activity activity, boolean overlay) {
@@ -195,11 +198,6 @@ public class StatusBar extends Plugin {
195
198
  Log.d(TAG, "setStyle: style=" + style + ", colorHex=" + colorHex);
196
199
  Window window = activity.getWindow();
197
200
 
198
- // Enable drawing of system bar backgrounds (required for color changes)
199
- window.addFlags(android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
200
- window.clearFlags(android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
201
- window.clearFlags(android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
202
-
203
201
  // Store the current style and color for later reapplication
204
202
  currentStyle = style;
205
203
  currentColorHex = colorHex;
@@ -384,16 +382,14 @@ public class StatusBar extends Plugin {
384
382
 
385
383
  private void applyStatusBarBackground(Activity activity, @ColorInt int color) {
386
384
  Log.d(TAG, "applyStatusBarBackground: color=#" + Integer.toHexString(color) + ", API=" + Build.VERSION.SDK_INT);
387
- // Use overlay approach for all API levels since edge-to-edge mode
388
- // (setDecorFitsSystemWindows=false) makes window.setStatusBarColor() ineffective
385
+ // Use overlay views for all API levels for consistent behavior
389
386
  ensureStatusBarOverlay(activity, color);
390
387
  }
391
388
 
392
389
  private void applyNavigationBarBackground(Activity activity, @ColorInt int color) {
393
390
  Log.d(TAG, "applyNavigationBarBackground: color=#" + Integer.toHexString(color) + ", API="
394
391
  + Build.VERSION.SDK_INT);
395
- // Use overlay approach for all API levels since edge-to-edge mode
396
- // (setDecorFitsSystemWindows=false) makes window.setNavigationBarColor() ineffective
392
+ // Use overlay views for all API levels for consistent behavior
397
393
  ensureNavBarOverlay(activity, color);
398
394
  }
399
395
 
@@ -401,52 +397,38 @@ public class StatusBar extends Plugin {
401
397
  Log.d(TAG, "ensureStatusBarOverlay: color=#" + Integer.toHexString(color));
402
398
  ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
403
399
  View existing = decorView.findViewWithTag(STATUS_BAR_OVERLAY_TAG);
400
+
401
+ // Get current status bar height synchronously for immediate sizing
402
+ int initialHeight = 0;
403
+ WindowInsetsCompat rootInsets = ViewCompat.getRootWindowInsets(decorView);
404
+ if (rootInsets != null) {
405
+ initialHeight = rootInsets.getInsets(WindowInsetsCompat.Type.statusBars()).top;
406
+ }
407
+
404
408
  if (existing == null) {
405
- Log.d(TAG, "ensureStatusBarOverlay: creating new overlay");
409
+ Log.d(TAG, "ensureStatusBarOverlay: creating new overlay, initialHeight=" + initialHeight);
406
410
  View overlay = new View(activity);
407
411
  overlay.setTag(STATUS_BAR_OVERLAY_TAG);
408
412
  overlay.setBackgroundColor(color);
409
413
 
410
414
  FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
411
415
  ViewGroup.LayoutParams.MATCH_PARENT,
412
- 0);
413
- lp.topMargin = 0;
416
+ initialHeight);
414
417
  overlay.setLayoutParams(lp);
415
418
 
416
- // Add to the top of the decor view
417
419
  decorView.addView(overlay);
418
-
419
- // Listen on decorView for reliable insets dispatch across all API levels,
420
- // then use WindowInsetsCompat.Type.statusBars() for accurate status-bar-only height
421
- ViewCompat.setOnApplyWindowInsetsListener(decorView, (v, windowInsets) -> {
422
- int top = windowInsets.getInsets(WindowInsetsCompat.Type.statusBars()).top;
423
- View statusOverlay = decorView.findViewWithTag(STATUS_BAR_OVERLAY_TAG);
424
- if (statusOverlay != null) {
425
- ViewGroup.LayoutParams params = statusOverlay.getLayoutParams();
426
- if (params.height != top) {
427
- params.height = top;
428
- statusOverlay.setLayoutParams(params);
429
- }
430
- }
431
-
432
- int bottom = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;
433
- View navOverlay = decorView.findViewWithTag(NAV_BAR_OVERLAY_TAG);
434
- if (navOverlay != null) {
435
- ViewGroup.LayoutParams params = navOverlay.getLayoutParams();
436
- if (params.height != bottom) {
437
- params.height = bottom;
438
- navOverlay.setLayoutParams(params);
439
- }
440
- }
441
-
442
- ViewCompat.onApplyWindowInsets(v, windowInsets);
443
- return windowInsets;
444
- });
420
+ // Sizing updates are handled by the unified listener in ensureEdgeToEdgeConfigured
445
421
  decorView.requestApplyInsets();
446
422
  } else {
447
423
  Log.d(TAG, "ensureStatusBarOverlay: updating existing overlay");
448
424
  existing.setBackgroundColor(color);
449
- decorView.requestApplyInsets();
425
+ // Update height if it was 0 (listener hadn't fired yet)
426
+ ViewGroup.LayoutParams params = existing.getLayoutParams();
427
+ if (params.height == 0 && initialHeight > 0) {
428
+ params.height = initialHeight;
429
+ existing.setLayoutParams(params);
430
+ Log.d(TAG, "ensureStatusBarOverlay: fixed height to " + initialHeight);
431
+ }
450
432
  }
451
433
  }
452
434
 
@@ -464,53 +446,39 @@ public class StatusBar extends Plugin {
464
446
  Log.d(TAG, "ensureNavBarOverlay: color=#" + Integer.toHexString(color));
465
447
  ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
466
448
  View existing = decorView.findViewWithTag(NAV_BAR_OVERLAY_TAG);
449
+
450
+ // Get current nav bar height synchronously for immediate sizing
451
+ int initialHeight = 0;
452
+ WindowInsetsCompat rootInsets = ViewCompat.getRootWindowInsets(decorView);
453
+ if (rootInsets != null) {
454
+ initialHeight = rootInsets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;
455
+ }
456
+
467
457
  if (existing == null) {
468
- Log.d(TAG, "ensureNavBarOverlay: creating new overlay");
458
+ Log.d(TAG, "ensureNavBarOverlay: creating new overlay, initialHeight=" + initialHeight);
469
459
  View overlay = new View(activity);
470
460
  overlay.setTag(NAV_BAR_OVERLAY_TAG);
471
461
  overlay.setBackgroundColor(color);
472
462
 
473
463
  FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
474
464
  ViewGroup.LayoutParams.MATCH_PARENT,
475
- 0);
465
+ initialHeight);
476
466
  lp.gravity = Gravity.BOTTOM;
477
467
  overlay.setLayoutParams(lp);
478
468
 
479
469
  decorView.addView(overlay);
480
-
481
- // Insets sizing is handled by the shared decorView listener in ensureStatusBarOverlay.
482
- // If status bar overlay was not created yet, set up the listener here.
483
- if (decorView.findViewWithTag(STATUS_BAR_OVERLAY_TAG) == null) {
484
- ViewCompat.setOnApplyWindowInsetsListener(decorView, (v, windowInsets) -> {
485
- int top = windowInsets.getInsets(WindowInsetsCompat.Type.statusBars()).top;
486
- View statusOverlay = decorView.findViewWithTag(STATUS_BAR_OVERLAY_TAG);
487
- if (statusOverlay != null) {
488
- ViewGroup.LayoutParams params = statusOverlay.getLayoutParams();
489
- if (params.height != top) {
490
- params.height = top;
491
- statusOverlay.setLayoutParams(params);
492
- }
493
- }
494
-
495
- int bottom = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;
496
- View navOverlay = decorView.findViewWithTag(NAV_BAR_OVERLAY_TAG);
497
- if (navOverlay != null) {
498
- ViewGroup.LayoutParams params = navOverlay.getLayoutParams();
499
- if (params.height != bottom) {
500
- params.height = bottom;
501
- navOverlay.setLayoutParams(params);
502
- }
503
- }
504
-
505
- ViewCompat.onApplyWindowInsets(v, windowInsets);
506
- return windowInsets;
507
- });
508
- }
470
+ // Sizing updates are handled by the unified listener in ensureEdgeToEdgeConfigured
509
471
  decorView.requestApplyInsets();
510
472
  } else {
511
473
  Log.d(TAG, "ensureNavBarOverlay: updating existing overlay");
512
474
  existing.setBackgroundColor(color);
513
- decorView.requestApplyInsets();
475
+ // Update height if it was 0 (listener hadn't fired yet)
476
+ ViewGroup.LayoutParams params = existing.getLayoutParams();
477
+ if (params.height == 0 && initialHeight > 0) {
478
+ params.height = initialHeight;
479
+ existing.setLayoutParams(params);
480
+ Log.d(TAG, "ensureNavBarOverlay: fixed height to " + initialHeight);
481
+ }
514
482
  }
515
483
  }
516
484
 
@@ -536,18 +504,15 @@ public class StatusBar extends Plugin {
536
504
  */
537
505
  private void makeStatusBarBackgroundTransparent(Activity activity) {
538
506
  Log.d(TAG, "makeStatusBarBackgroundTransparent: API=" + Build.VERSION.SDK_INT);
539
- Window window = activity.getWindow();
507
+ ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
540
508
 
541
- // Make overlay views transparent (used for all API levels)
542
- ViewGroup decorView = (ViewGroup) window.getDecorView();
543
509
  View statusBarOverlay = decorView.findViewWithTag(STATUS_BAR_OVERLAY_TAG);
544
- View navBarOverlay = decorView.findViewWithTag(NAV_BAR_OVERLAY_TAG);
545
-
546
510
  if (statusBarOverlay != null) {
547
511
  statusBarOverlay.setBackgroundColor(Color.TRANSPARENT);
548
512
  Log.d(TAG, "makeStatusBarBackgroundTransparent: status bar overlay made transparent");
549
513
  }
550
514
 
515
+ View navBarOverlay = decorView.findViewWithTag(NAV_BAR_OVERLAY_TAG);
551
516
  if (navBarOverlay != null) {
552
517
  navBarOverlay.setBackgroundColor(Color.TRANSPARENT);
553
518
  Log.d(TAG, "makeStatusBarBackgroundTransparent: navigation bar overlay made transparent");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-plugin-status-bar",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
4
4
  "description": "Capacitor plugin for managing the status bar style, visibility, and color on iOS and Android. Control overlay modes, background colors, and appearance for native mobile applications.",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",