rn-system-bar 3.2.0 → 3.2.2

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.
@@ -56,10 +56,7 @@ class SystemBarModule(
56
56
  // NAVIGATION BAR — 100% native, no expo dep
57
57
  // ═══════════════════════════════════════════════
58
58
 
59
- // ── Helpers for transparent / translucent bars ──────────────────────────
60
-
61
59
  private fun applyEdgeToEdgeFlags() {
62
- // Required so our colour / transparency actually shows through
63
60
  activity()!!.window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
64
61
  }
65
62
 
@@ -154,7 +151,6 @@ class SystemBarModule(
154
151
 
155
152
  @ReactMethod
156
153
  fun setNavigationBarStyle(style: String) {
157
- // Maps to button style — "dark"/"auto" → dark icons, "light"/"inverted" → light icons
158
154
  setNavigationBarButtonStyle(if (style == "dark" || style == "auto") "dark" else "light")
159
155
  }
160
156
 
@@ -165,11 +161,9 @@ class SystemBarModule(
165
161
  val c = activity()!!.window.insetsController ?: return@runOnUiThread
166
162
  c.systemBarsBehavior = when (behavior) {
167
163
  "overlay-swipe" -> WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
168
- // inset modes — default persistent behavior
169
164
  else -> WindowInsetsController.BEHAVIOR_DEFAULT
170
165
  }
171
166
  }
172
- // API < 30: IMMERSIVE_STICKY is closest — no-op otherwise
173
167
  }
174
168
  }
175
169
 
@@ -288,14 +282,12 @@ class SystemBarModule(
288
282
  }
289
283
 
290
284
  // ── Realtime brightness listener ─────────────
291
- private var brightnessReceiver: BroadcastReceiver? = null
292
285
  private var brightnessPollingRunnable: Runnable? = null
293
286
  private var lastBrightness = -1
294
287
 
295
288
  @ReactMethod
296
289
  fun startBrightnessListener() {
297
290
  if (brightnessPollingRunnable != null) return
298
- // Settings.System doesn't broadcast changes — poll every 500ms
299
291
  val runnable = object : Runnable {
300
292
  override fun run() {
301
293
  try {
@@ -430,20 +422,15 @@ class SystemBarModule(
430
422
 
431
423
  @ReactMethod
432
424
  fun setOrientation(mode: String) {
433
- // "auto" → always unspecified (follow system auto-rotate toggle unconditionally)
434
425
  if (mode == "auto") {
435
426
  activity()?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
436
427
  return
437
428
  }
438
429
 
439
- // For a specific orientation: check if the device's auto-rotate toggle is ON.
440
- // auto-rotate ON → use sensor-based variant so the device can still rotate
441
- // within the requested axis (portrait ↔ reverse-portrait, etc.)
442
- // auto-rotate OFF → hard-lock to the exact orientation requested
443
430
  val autoRotateOn = Settings.System.getInt(
444
431
  reactContext.contentResolver,
445
432
  Settings.System.ACCELEROMETER_ROTATION,
446
- 0 // default = locked (off)
433
+ 0
447
434
  ) == 1
448
435
 
449
436
  activity()?.requestedOrientation = when (mode) {
@@ -456,7 +443,6 @@ class SystemBarModule(
456
443
  else ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
457
444
 
458
445
  "landscape-left" ->
459
- // Reverse landscape — no sensor variant; honour toggle by using full sensor landscape
460
446
  if (autoRotateOn) ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
461
447
  else ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
462
448
 
@@ -470,7 +456,6 @@ class SystemBarModule(
470
456
 
471
457
  // ═══════════════════════════════════════════════
472
458
  // SYSTEM SCREENCAST (external display / HDMI / Miracast)
473
- // Detects OS-level external displays via DisplayManager.
474
459
  // ═══════════════════════════════════════════════
475
460
 
476
461
  private var displayListener: DisplayManager.DisplayListener? = null
@@ -520,42 +505,41 @@ class SystemBarModule(
520
505
 
521
506
  // ═══════════════════════════════════════════════
522
507
  // APP-ONLY CAST (MediaRouter — Chromecast / TV)
523
- //
524
- // Casts ONLY this app's screen — not the whole system.
525
- // Uses android.media.MediaRouter (API 16+, no Play Services required).
526
- //
527
- // Flow:
528
- // startAppCastScan() → devices arrive via SystemBar_AppCastChange
529
- // connectAppCast(deviceId) → state = "connecting" then "connected"
530
- // disconnectAppCast() → state = "disconnecting" then "idle"
531
508
  // ═══════════════════════════════════════════════
532
509
 
533
510
  private val mediaRouter: android.media.MediaRouter by lazy {
534
511
  reactContext.getSystemService(Context.MEDIA_ROUTER_SERVICE) as android.media.MediaRouter
535
512
  }
536
513
 
537
- // Current state
538
514
  private var appCastState = "idle"
539
515
  private var connectedRoute: android.media.MediaRouter.RouteInfo? = null
540
516
  private var appCastCallback: android.media.MediaRouter.Callback? = null
541
-
542
- // All routes discovered during the current scan (id → route)
543
517
  private val discoveredRoutes = mutableMapOf<String, android.media.MediaRouter.RouteInfo>()
544
518
 
545
- // ── Serialisation helpers ──────────────────
519
+ // ── Helpers ───────────────────────────────────
546
520
 
547
521
  private fun routeId(r: android.media.MediaRouter.RouteInfo): String =
548
522
  r.name?.toString()?.replace(" ", "_")?.plus("_${r.hashCode()}") ?: r.hashCode().toString()
549
523
 
524
+ /**
525
+ * Replaces the removed RouteInfo.isDefault property (removed in API 34+).
526
+ * The default route is the built-in phone speaker / earpiece.
527
+ * We identify it by checking that it only supports audio (not video/live-video)
528
+ * and that it carries no presentation display.
529
+ */
530
+ private fun android.media.MediaRouter.RouteInfo.isDefaultRoute(): Boolean {
531
+ val videoMask = android.media.MediaRouter.ROUTE_TYPE_LIVE_VIDEO or
532
+ android.media.MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY
533
+ return (supportedTypes and videoMask) == 0
534
+ }
535
+
550
536
  private fun routeToMap(r: android.media.MediaRouter.RouteInfo): WritableMap {
551
537
  val m = Arguments.createMap()
552
538
  m.putString("id", routeId(r))
553
539
  m.putString("name", r.name?.toString() ?: "Unknown")
554
540
  val desc = r.description?.toString()
555
541
  if (desc != null) m.putString("description", desc) else m.putNull("description")
556
- // MediaRouter doesn't expose signal strength — set null
557
542
  m.putNull("signalStrength")
558
- // Consider a device to require pairing when its status matches "connecting"
559
543
  m.putBoolean("requiresPairing", false)
560
544
  return m
561
545
  }
@@ -582,23 +566,30 @@ class SystemBarModule(
582
566
  emit("SystemBar_AppCastChange", map)
583
567
  }
584
568
 
585
- // ── Scan ──────────────────────────────────
569
+ // ── Scan ──────────────────────────────────────
586
570
 
587
571
  @ReactMethod
588
572
  fun startAppCastScan() {
589
- if (appCastCallback != null) return // already scanning
573
+ if (appCastCallback != null) return
590
574
  appCastState = "scanning"
591
575
  discoveredRoutes.clear()
592
576
 
593
577
  val cb = object : android.media.MediaRouter.Callback() {
594
- override fun onRouteAdded(router: android.media.MediaRouter, route: android.media.MediaRouter.RouteInfo) {
595
- // Skip the default phone speaker / earpiece
596
- if (route.isDefault) return
578
+
579
+ override fun onRouteAdded(
580
+ router: android.media.MediaRouter,
581
+ route: android.media.MediaRouter.RouteInfo
582
+ ) {
583
+ if (route.isDefaultRoute()) return
597
584
  val id = routeId(route)
598
585
  discoveredRoutes[id] = route
599
586
  emitAppCastChange()
600
587
  }
601
- override fun onRouteRemoved(router: android.media.MediaRouter, route: android.media.MediaRouter.RouteInfo) {
588
+
589
+ override fun onRouteRemoved(
590
+ router: android.media.MediaRouter,
591
+ route: android.media.MediaRouter.RouteInfo
592
+ ) {
602
593
  discoveredRoutes.remove(routeId(route))
603
594
  if (connectedRoute?.let { routeId(it) } == routeId(route)) {
604
595
  connectedRoute = null
@@ -606,24 +597,57 @@ class SystemBarModule(
606
597
  }
607
598
  emitAppCastChange()
608
599
  }
609
- override fun onRouteChanged(router: android.media.MediaRouter, route: android.media.MediaRouter.RouteInfo) {
600
+
601
+ override fun onRouteChanged(
602
+ router: android.media.MediaRouter,
603
+ route: android.media.MediaRouter.RouteInfo
604
+ ) {
610
605
  val id = routeId(route)
611
- if (!route.isDefault) discoveredRoutes[id] = route
606
+ if (!route.isDefaultRoute()) discoveredRoutes[id] = route
612
607
  emitAppCastChange()
613
608
  }
614
- override fun onRouteSelected(router: android.media.MediaRouter, type: Int, route: android.media.MediaRouter.RouteInfo) {
615
- if (route.isDefault) return
609
+
610
+ override fun onRouteSelected(
611
+ router: android.media.MediaRouter,
612
+ type: Int,
613
+ route: android.media.MediaRouter.RouteInfo
614
+ ) {
615
+ if (route.isDefaultRoute()) return
616
616
  connectedRoute = route
617
617
  appCastState = "connected"
618
618
  emitAppCastChange()
619
619
  }
620
- override fun onRouteUnselected(router: android.media.MediaRouter, type: Int, route: android.media.MediaRouter.RouteInfo) {
620
+
621
+ override fun onRouteUnselected(
622
+ router: android.media.MediaRouter,
623
+ type: Int,
624
+ route: android.media.MediaRouter.RouteInfo
625
+ ) {
621
626
  if (appCastState != "idle") {
622
627
  connectedRoute = null
623
628
  appCastState = "idle"
624
629
  emitAppCastChange()
625
630
  }
626
631
  }
632
+
633
+ // ── Required abstract stubs (no-op) ───────
634
+ override fun onRouteGrouped(
635
+ router: android.media.MediaRouter,
636
+ route: android.media.MediaRouter.RouteInfo,
637
+ group: android.media.MediaRouter.RouteGroup,
638
+ index: Int
639
+ ) {}
640
+
641
+ override fun onRouteUngrouped(
642
+ router: android.media.MediaRouter,
643
+ route: android.media.MediaRouter.RouteInfo,
644
+ group: android.media.MediaRouter.RouteGroup
645
+ ) {}
646
+
647
+ override fun onRouteVolumeChanged(
648
+ router: android.media.MediaRouter,
649
+ route: android.media.MediaRouter.RouteInfo
650
+ ) {}
627
651
  }
628
652
 
629
653
  appCastCallback = cb
@@ -631,8 +655,9 @@ class SystemBarModule(
631
655
  mediaRouter.addCallback(
632
656
  android.media.MediaRouter.ROUTE_TYPE_LIVE_VIDEO,
633
657
  cb,
634
- android.media.MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY or
635
- android.media.MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN
658
+ // CALLBACK_FLAG_REQUEST_DISCOVERY is typed as BigInteger in newer SDK bindings
659
+ android.media.MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY.toInt() or
660
+ android.media.MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN.toInt()
636
661
  )
637
662
  }
638
663
  emitAppCastChange()
@@ -648,7 +673,7 @@ class SystemBarModule(
648
673
  }
649
674
  }
650
675
 
651
- // ── Connect / Disconnect ──────────────────
676
+ // ── Connect / Disconnect ──────────────────────
652
677
 
653
678
  @ReactMethod
654
679
  fun connectAppCast(deviceId: String, pairingPin: String?) {
@@ -667,7 +692,6 @@ class SystemBarModule(
667
692
  mainHandler.post {
668
693
  try {
669
694
  mediaRouter.selectRoute(android.media.MediaRouter.ROUTE_TYPE_LIVE_VIDEO, route)
670
- // onRouteSelected callback will set state = "connected" and re-emit
671
695
  } catch (e: Exception) {
672
696
  appCastState = "idle"
673
697
  emitAppCastChange(error = e.message ?: "Connection failed")
@@ -682,7 +706,6 @@ class SystemBarModule(
682
706
  emitAppCastChange()
683
707
  mainHandler.post {
684
708
  try {
685
- // Select the default (phone) route to stop remote casting
686
709
  val defaultRoute = mediaRouter.getDefaultRoute()
687
710
  mediaRouter.selectRoute(android.media.MediaRouter.ROUTE_TYPE_LIVE_VIDEO, defaultRoute)
688
711
  connectedRoute = null
@@ -701,7 +724,7 @@ class SystemBarModule(
701
724
  catch (e: Exception) { promise.reject("APP_CAST_ERROR", e.message, e) }
702
725
  }
703
726
 
704
- // ── Cleanup ──────────────────────────────────
727
+ // ── Cleanup ───────────────────────────────────
705
728
  override fun onCatalystInstanceDestroy() {
706
729
  stopBrightnessListener()
707
730
  stopVolumeListener()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rn-system-bar",
3
- "version": "3.2.0",
3
+ "version": "3.2.2",
4
4
  "description": "Control Android & iOS system bars, brightness, volume, orientation and screen flags from React Native.",
5
5
  "main": "lib/index.js",
6
6
  "react-native": "lib/index.js",