capacitor-plugin-status-bar 2.0.9 → 2.0.11
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.
|
@@ -21,7 +21,6 @@ import androidx.core.view.WindowInsetsCompat;
|
|
|
21
21
|
|
|
22
22
|
import com.getcapacitor.Plugin;
|
|
23
23
|
|
|
24
|
-
|
|
25
24
|
/**
|
|
26
25
|
* Android Status Bar utilities with Android 10-15+ (API 29-35+) support.
|
|
27
26
|
* Supports:
|
|
@@ -42,9 +41,11 @@ public class CapacitorStatusBar extends Plugin {
|
|
|
42
41
|
private int currentStatusBarColor = Color.BLACK;
|
|
43
42
|
private int currentNavBarColor = Color.BLACK;
|
|
44
43
|
|
|
45
|
-
// Note: load() is not called since CapacitorStatusBar is instantiated via new
|
|
44
|
+
// Note: load() is not called since CapacitorStatusBar is instantiated via new
|
|
45
|
+
// CapacitorStatusBar()
|
|
46
46
|
// from CapacitorStatusBarPlugin, not registered as a Capacitor plugin itself.
|
|
47
|
-
// All initialization happens via ensureEdgeToEdgeConfigured() called from
|
|
47
|
+
// All initialization happens via ensureEdgeToEdgeConfigured() called from
|
|
48
|
+
// CapacitorStatusBarPlugin.load().
|
|
48
49
|
|
|
49
50
|
/**
|
|
50
51
|
* Ensures edge-to-edge is properly configured for Android 15+.
|
|
@@ -59,12 +60,15 @@ public class CapacitorStatusBar extends Plugin {
|
|
|
59
60
|
|
|
60
61
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
61
62
|
// Android 12+ (API 31+): enable edge-to-edge layout.
|
|
62
|
-
// The nav bar uses overlay views because gesture navigation ignores
|
|
63
|
+
// The nav bar uses overlay views because gesture navigation ignores
|
|
64
|
+
// setNavigationBarColor().
|
|
63
65
|
// The status bar still uses setStatusBarColor() reliably on API 31–34;
|
|
64
|
-
// overlay is only needed on API 35+ where edge-to-edge is enforced and the
|
|
66
|
+
// overlay is only needed on API 35+ where edge-to-edge is enforced and the
|
|
67
|
+
// native API is a no-op.
|
|
65
68
|
WindowCompat.setDecorFitsSystemWindows(window, false);
|
|
66
69
|
|
|
67
|
-
// Set a transparent baseline; setStyle() will apply the actual color via
|
|
70
|
+
// Set a transparent baseline; setStyle() will apply the actual color via
|
|
71
|
+
// setStatusBarColor()
|
|
68
72
|
// (API 31-34) or the status bar overlay (API 35+).
|
|
69
73
|
window.setStatusBarColor(Color.TRANSPARENT);
|
|
70
74
|
window.setNavigationBarColor(Color.TRANSPARENT);
|
|
@@ -104,8 +108,10 @@ public class CapacitorStatusBar extends Plugin {
|
|
|
104
108
|
Log.d(TAG, "ensureEdgeToEdgeConfigured: edge-to-edge with overlay views, API=" + Build.VERSION.SDK_INT);
|
|
105
109
|
} else {
|
|
106
110
|
// Android < 12 (API < 31): Only disable contrast enforcement.
|
|
107
|
-
// Do NOT call setDecorFitsSystemWindows(false), create overlay views, or set
|
|
108
|
-
//
|
|
111
|
+
// Do NOT call setDecorFitsSystemWindows(false), create overlay views, or set
|
|
112
|
+
// insets listener.
|
|
113
|
+
// This avoids conflicts with plugins like
|
|
114
|
+
// @capawesome/capacitor-android-edge-to-edge-support.
|
|
109
115
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
110
116
|
window.setStatusBarContrastEnforced(false);
|
|
111
117
|
window.setNavigationBarContrastEnforced(false);
|
|
@@ -157,57 +163,42 @@ public class CapacitorStatusBar extends Plugin {
|
|
|
157
163
|
showNavigationBar(activity, true);
|
|
158
164
|
}
|
|
159
165
|
|
|
160
|
-
public void hideStatusBar(Activity activity
|
|
161
|
-
Log.d(TAG, "hideStatusBar: animation=" + animation + ", API=" + Build.VERSION.SDK_INT);
|
|
166
|
+
public void hideStatusBar(Activity activity) {
|
|
162
167
|
Window window = activity.getWindow();
|
|
163
168
|
View decorView = window.getDecorView();
|
|
164
169
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if ("fade".equals(animationType)) {
|
|
168
|
-
// Fade mode: Make background transparent without removing status bar and
|
|
169
|
-
// navigation bar
|
|
170
|
-
Log.d(TAG, "hideStatusBar: fade mode - making backgrounds transparent");
|
|
171
|
-
makeStatusBarBackgroundTransparent(activity);
|
|
172
|
-
hideNavigationBar(activity, "fade");
|
|
173
|
-
} else if ("slide".equals(animationType)) {
|
|
174
|
-
// Slide mode: Hide status bar and navigation bar completely (current behavior)
|
|
175
|
-
Log.d(TAG, "hideStatusBar: slide mode - hiding bars completely");
|
|
170
|
+
// Slide mode: Hide status bar and navigation bar completely (current behavior)
|
|
171
|
+
Log.d(TAG, "hideStatusBar: slide mode - hiding bars completely");
|
|
176
172
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
} else {
|
|
188
|
-
Log.w(TAG, "hideStatusBar: WindowInsetsController is null");
|
|
189
|
-
}
|
|
173
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
174
|
+
// API 30+ (Android 11+) - Use WindowInsetsController
|
|
175
|
+
WindowInsetsController controller = window.getInsetsController();
|
|
176
|
+
if (controller != null) {
|
|
177
|
+
Log.d(TAG, "hideStatusBar: hiding system bars (API 30+)");
|
|
178
|
+
// Hide both status and navigation bars together
|
|
179
|
+
controller.hide(WindowInsets.Type.systemBars());
|
|
180
|
+
// Set behavior for immersive mode (user can swipe to reveal temporarily)
|
|
181
|
+
controller.setSystemBarsBehavior(
|
|
182
|
+
WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
|
|
190
183
|
} else {
|
|
191
|
-
|
|
192
|
-
// necessary)
|
|
193
|
-
Log.d(TAG, "hideStatusBar: hiding using system UI flags (API 29)");
|
|
194
|
-
// Use immersive sticky mode with proper layout flags for Android 10
|
|
195
|
-
decorView.setSystemUiVisibility(
|
|
196
|
-
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
|
197
|
-
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
|
198
|
-
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
|
199
|
-
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
|
200
|
-
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
|
201
|
-
| View.SYSTEM_UI_FLAG_FULLSCREEN);
|
|
184
|
+
Log.w(TAG, "hideStatusBar: WindowInsetsController is null");
|
|
202
185
|
}
|
|
203
|
-
|
|
204
|
-
// Make the overlay backgrounds transparent so content shows through
|
|
205
|
-
makeStatusBarBackgroundTransparent(activity);
|
|
206
186
|
} else {
|
|
207
|
-
//
|
|
208
|
-
|
|
209
|
-
|
|
187
|
+
// API 29 (Android 10) - Use system UI visibility flags (deprecated but
|
|
188
|
+
// necessary)
|
|
189
|
+
Log.d(TAG, "hideStatusBar: hiding using system UI flags (API 29)");
|
|
190
|
+
// Use immersive sticky mode with proper layout flags for Android 10
|
|
191
|
+
decorView.setSystemUiVisibility(
|
|
192
|
+
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
|
193
|
+
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
|
194
|
+
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
|
195
|
+
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
|
196
|
+
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
|
197
|
+
| View.SYSTEM_UI_FLAG_FULLSCREEN);
|
|
210
198
|
}
|
|
199
|
+
|
|
200
|
+
// Make the overlay backgrounds transparent so content shows through
|
|
201
|
+
makeStatusBarBackgroundTransparent(activity);
|
|
211
202
|
}
|
|
212
203
|
|
|
213
204
|
public void setStyle(Activity activity, String style, @Nullable String colorHex) {
|
|
@@ -262,7 +253,8 @@ public class CapacitorStatusBar extends Plugin {
|
|
|
262
253
|
}
|
|
263
254
|
|
|
264
255
|
// Set icon appearance AFTER background operations.
|
|
265
|
-
// On Android 13 (API 33), applyStatusBarBackground triggers
|
|
256
|
+
// On Android 13 (API 33), applyStatusBarBackground triggers
|
|
257
|
+
// requestApplyInsets()
|
|
266
258
|
// which causes the WindowInsetsController to reset setSystemBarsAppearance.
|
|
267
259
|
// Calling setLightStatusBarIcons last ensures the icon style is not overridden.
|
|
268
260
|
setLightStatusBarIcons(window, lightBackground);
|
|
@@ -291,7 +283,8 @@ public class CapacitorStatusBar extends Plugin {
|
|
|
291
283
|
* Returns the insets for status bar, navigation bar, and notch areas.
|
|
292
284
|
*
|
|
293
285
|
* @param activity The activity to get the insets from
|
|
294
|
-
* @return A map containing top, bottom, left, and right inset values in dp
|
|
286
|
+
* @return A map containing top, bottom, left, and right inset values in dp
|
|
287
|
+
* (density-independent pixels)
|
|
295
288
|
*/
|
|
296
289
|
public java.util.Map<String, Integer> getSafeAreaInsets(Activity activity) {
|
|
297
290
|
Log.d(TAG, "getSafeAreaInsets");
|
|
@@ -302,10 +295,12 @@ public class CapacitorStatusBar extends Plugin {
|
|
|
302
295
|
WindowInsetsCompat windowInsets = ViewCompat.getRootWindowInsets(decorView);
|
|
303
296
|
|
|
304
297
|
if (windowInsets != null) {
|
|
305
|
-
// Use WindowInsetsCompat for accurate, type-specific insets across all API
|
|
298
|
+
// Use WindowInsetsCompat for accurate, type-specific insets across all API
|
|
299
|
+
// levels
|
|
306
300
|
androidx.core.graphics.Insets statusBars = windowInsets.getInsets(WindowInsetsCompat.Type.statusBars());
|
|
307
301
|
androidx.core.graphics.Insets navBars = windowInsets.getInsets(WindowInsetsCompat.Type.navigationBars());
|
|
308
|
-
androidx.core.graphics.Insets displayCutout = windowInsets
|
|
302
|
+
androidx.core.graphics.Insets displayCutout = windowInsets
|
|
303
|
+
.getInsets(WindowInsetsCompat.Type.displayCutout());
|
|
309
304
|
|
|
310
305
|
int topPx = Math.max(statusBars.top, displayCutout.top);
|
|
311
306
|
int bottomPx = Math.max(navBars.bottom, displayCutout.bottom);
|
|
@@ -500,11 +495,14 @@ public class CapacitorStatusBar extends Plugin {
|
|
|
500
495
|
private void applyStatusBarBackground(Activity activity, @ColorInt int color) {
|
|
501
496
|
Log.d(TAG, "applyStatusBarBackground: color=#" + Integer.toHexString(color) + ", API=" + Build.VERSION.SDK_INT);
|
|
502
497
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
|
|
503
|
-
// Android 15+ (API 35+): edge-to-edge is enforced, setStatusBarColor() is a
|
|
498
|
+
// Android 15+ (API 35+): edge-to-edge is enforced, setStatusBarColor() is a
|
|
499
|
+
// no-op
|
|
504
500
|
ensureStatusBarOverlay(activity, color);
|
|
505
501
|
} else {
|
|
506
|
-
// API 29–34: setStatusBarColor() works reliably for the status bar on all
|
|
507
|
-
//
|
|
502
|
+
// API 29–34: setStatusBarColor() works reliably for the status bar on all
|
|
503
|
+
// navigation modes.
|
|
504
|
+
// Note: gesture navigation only ignores setNavigationBarColor(), not
|
|
505
|
+
// setStatusBarColor().
|
|
508
506
|
activity.getWindow().setStatusBarColor(color);
|
|
509
507
|
}
|
|
510
508
|
}
|
|
@@ -512,11 +510,15 @@ public class CapacitorStatusBar extends Plugin {
|
|
|
512
510
|
private void applyNavigationBarBackground(Activity activity, @ColorInt int color) {
|
|
513
511
|
Log.d(TAG, "applyNavigationBarBackground: color=#" + Integer.toHexString(color) + ", API="
|
|
514
512
|
+ Build.VERSION.SDK_INT);
|
|
515
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.
|
|
516
|
-
// Android
|
|
513
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
|
|
514
|
+
// Android 15+ (API 35+): edge-to-edge enforced, setNavigationBarColor() is a
|
|
515
|
+
// no-op
|
|
517
516
|
ensureNavBarOverlay(activity, color);
|
|
518
517
|
} else {
|
|
519
|
-
//
|
|
518
|
+
// API 29–34: setNavigationBarColor() works for button navigation.
|
|
519
|
+
// Gesture navigation ignores it (system enforces transparency for gesture
|
|
520
|
+
// handles),
|
|
521
|
+
// but in that case there is no visible nav bar to color anyway.
|
|
520
522
|
activity.getWindow().setNavigationBarColor(color);
|
|
521
523
|
}
|
|
522
524
|
}
|
|
@@ -545,7 +547,8 @@ public class CapacitorStatusBar extends Plugin {
|
|
|
545
547
|
overlay.setLayoutParams(lp);
|
|
546
548
|
|
|
547
549
|
decorView.addView(overlay);
|
|
548
|
-
// Sizing updates are handled by the unified listener in
|
|
550
|
+
// Sizing updates are handled by the unified listener in
|
|
551
|
+
// ensureEdgeToEdgeConfigured
|
|
549
552
|
decorView.requestApplyInsets();
|
|
550
553
|
} else {
|
|
551
554
|
Log.d(TAG, "ensureStatusBarOverlay: updating existing overlay");
|
|
@@ -595,7 +598,8 @@ public class CapacitorStatusBar extends Plugin {
|
|
|
595
598
|
overlay.setLayoutParams(lp);
|
|
596
599
|
|
|
597
600
|
decorView.addView(overlay);
|
|
598
|
-
// Sizing updates are handled by the unified listener in
|
|
601
|
+
// Sizing updates are handled by the unified listener in
|
|
602
|
+
// ensureEdgeToEdgeConfigured
|
|
599
603
|
decorView.requestApplyInsets();
|
|
600
604
|
} else {
|
|
601
605
|
Log.d(TAG, "ensureNavBarOverlay: updating existing overlay");
|
|
@@ -621,9 +625,9 @@ public class CapacitorStatusBar extends Plugin {
|
|
|
621
625
|
}
|
|
622
626
|
|
|
623
627
|
private void applyWindowBackground(Activity activity, @ColorInt int color) {
|
|
624
|
-
Log.d(TAG, "applyWindowBackground:
|
|
628
|
+
Log.d(TAG, "applyWindowBackground: body is always transparent; status/nav bars use overlays/native APIs");
|
|
625
629
|
View decorView = activity.getWindow().getDecorView();
|
|
626
|
-
decorView.setBackgroundColor(
|
|
630
|
+
decorView.setBackgroundColor(Color.TRANSPARENT);
|
|
627
631
|
}
|
|
628
632
|
|
|
629
633
|
/**
|
|
@@ -647,17 +651,8 @@ public class CapacitorStatusBar extends Plugin {
|
|
|
647
651
|
navBarOverlay.setBackgroundColor(Color.TRANSPARENT);
|
|
648
652
|
Log.d(TAG, "makeStatusBarBackgroundTransparent: nav bar overlay made transparent");
|
|
649
653
|
}
|
|
650
|
-
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
651
|
-
// Android 12–14: status bar uses native API, nav bar uses overlay
|
|
652
|
-
window.setStatusBarColor(Color.TRANSPARENT);
|
|
653
|
-
Log.d(TAG, "makeStatusBarBackgroundTransparent: status bar color set transparent (native)");
|
|
654
|
-
View navBarOverlay = decorView.findViewWithTag(NAV_BAR_OVERLAY_TAG);
|
|
655
|
-
if (navBarOverlay != null) {
|
|
656
|
-
navBarOverlay.setBackgroundColor(Color.TRANSPARENT);
|
|
657
|
-
Log.d(TAG, "makeStatusBarBackgroundTransparent: nav bar overlay made transparent");
|
|
658
|
-
}
|
|
659
654
|
} else {
|
|
660
|
-
//
|
|
655
|
+
// API 29–34: both bars use native window API
|
|
661
656
|
window.setStatusBarColor(Color.TRANSPARENT);
|
|
662
657
|
window.setNavigationBarColor(Color.TRANSPARENT);
|
|
663
658
|
Log.d(TAG, "makeStatusBarBackgroundTransparent: set native bar colors to transparent");
|
|
@@ -71,7 +71,7 @@ public class CapacitorStatusBarPlugin extends Plugin {
|
|
|
71
71
|
public void hide(PluginCall call) {
|
|
72
72
|
try {
|
|
73
73
|
getActivity().runOnUiThread(() -> {
|
|
74
|
-
implementation.hideStatusBar(getActivity()
|
|
74
|
+
implementation.hideStatusBar(getActivity());
|
|
75
75
|
call.resolve();
|
|
76
76
|
});
|
|
77
77
|
} catch (Exception e) {
|
|
@@ -227,8 +227,8 @@ import Capacitor
|
|
|
227
227
|
return
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
-
window.backgroundColor =
|
|
231
|
-
print("CapacitorStatusBar: setBackground -
|
|
230
|
+
window.backgroundColor = .clear
|
|
231
|
+
print("CapacitorStatusBar: setBackground - Body is always transparent; status/nav bars use overlays/native APIs")
|
|
232
232
|
}
|
|
233
233
|
}
|
|
234
234
|
|
|
@@ -237,20 +237,15 @@ import Capacitor
|
|
|
237
237
|
var insets: [String: CGFloat] = ["top": 0, "bottom": 0, "left": 0, "right": 0]
|
|
238
238
|
|
|
239
239
|
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
|
|
240
|
-
let window = windowScene.windows.first {
|
|
241
|
-
// Use statusBarManager for accurate status bar height
|
|
242
|
-
let statusBarHeight = windowScene.statusBarManager?.statusBarFrame.height ?? 0
|
|
240
|
+
let window = windowScene.windows.first(where: { $0.isKeyWindow }) ?? windowScene.windows.first {
|
|
243
241
|
let safeAreaInsets = window.safeAreaInsets
|
|
244
242
|
|
|
245
|
-
|
|
246
|
-
insets["
|
|
247
|
-
|
|
248
|
-
insets["
|
|
249
|
-
// left/right: safe area for landscape / display cutouts
|
|
250
|
-
insets["left"] = safeAreaInsets.left
|
|
251
|
-
insets["right"] = safeAreaInsets.right
|
|
243
|
+
insets["top"] = self.sanitizedInsetValue(safeAreaInsets.top)
|
|
244
|
+
insets["bottom"] = 0
|
|
245
|
+
insets["left"] = 0
|
|
246
|
+
insets["right"] = 0
|
|
252
247
|
|
|
253
|
-
print("CapacitorStatusBar: getSafeAreaInsets - top=\(
|
|
248
|
+
print("CapacitorStatusBar: getSafeAreaInsets - top=\(safeAreaInsets.top), bottom=\(safeAreaInsets.bottom), left=\(safeAreaInsets.left), right=\(safeAreaInsets.right)")
|
|
254
249
|
} else {
|
|
255
250
|
print("CapacitorStatusBar: getSafeAreaInsets - Unable to get window, returning zero insets")
|
|
256
251
|
}
|
|
@@ -399,6 +394,12 @@ import Capacitor
|
|
|
399
394
|
return (0.299 * red + 0.587 * green + 0.114 * blue)
|
|
400
395
|
}
|
|
401
396
|
|
|
397
|
+
/// Guard against non-finite/negative inset values before bridging to JS.
|
|
398
|
+
private func sanitizedInsetValue(_ value: CGFloat) -> CGFloat {
|
|
399
|
+
guard value.isFinite else { return 0 }
|
|
400
|
+
return max(0, value)
|
|
401
|
+
}
|
|
402
|
+
|
|
402
403
|
private func isSystemInDarkMode() -> Bool {
|
|
403
404
|
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
|
|
404
405
|
let window = windowScene.windows.first else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "capacitor-plugin-status-bar",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.11",
|
|
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",
|