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
|
|
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
|
-
// ──
|
|
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
|
|
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
|
-
|
|
595
|
-
|
|
596
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
606
|
+
if (!route.isDefaultRoute()) discoveredRoutes[id] = route
|
|
612
607
|
emitAppCastChange()
|
|
613
608
|
}
|
|
614
|
-
|
|
615
|
-
|
|
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
|
-
|
|
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
|
-
|
|
635
|
-
android.media.MediaRouter.
|
|
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