expo-beacon 0.9.0 → 0.9.1

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.
@@ -68,6 +68,7 @@
68
68
  <service
69
69
  android:name="expo.modules.beacon.BeaconForegroundService"
70
70
  android:foregroundServiceType="connectedDevice"
71
+ android:stopWithTask="false"
71
72
  android:exported="false" />
72
73
 
73
74
  <!-- Restart monitoring after boot.
@@ -91,6 +92,8 @@
91
92
  <!-- Self-scheduled CarPlay watchdog (11-min cadence; above
92
93
  setExactAndAllowWhileIdle per-app quota). -->
93
94
  <action android:name="expo.modules.beacon.ACTION_CARPLAY_WATCHDOG" />
95
+ <!-- Near-term keepalive armed when the app task is swiped away. -->
96
+ <action android:name="expo.modules.beacon.ACTION_TASK_REMOVED_KEEPALIVE" />
94
97
  </intent-filter>
95
98
  </receiver>
96
99
  </application>
@@ -1430,11 +1430,23 @@ class BeaconForegroundService : Service(), BeaconConsumer {
1430
1430
  * `stopSelf()` here; the system will redeliver `onStartCommand` on
1431
1431
  * its own if the process is later reclaimed.
1432
1432
  *
1433
- * Logging is the only side-effect so that stuck-state issues are
1434
- * traceable in logcat.
1433
+ * We also arm a near-term keepalive alarm so devices that tear down the
1434
+ * process on task removal recover before the slower periodic watchdogs run.
1435
1435
  */
1436
1436
  override fun onTaskRemoved(rootIntent: Intent?) {
1437
1437
  val keepAlive = isMonitoringActive(this) || isCarPlayEnabled(this)
1438
+ if (keepAlive) {
1439
+ try {
1440
+ if (isCarPlayEnabled(this)) {
1441
+ startCarPlayObserverInternal()
1442
+ CarPlayWatchdogWorker.schedule(this)
1443
+ BootReceiver.scheduleCarPlayWatchdogAlarm(this)
1444
+ }
1445
+ BootReceiver.scheduleTaskRemovedKeepAlive(this)
1446
+ } catch (t: Throwable) {
1447
+ Log.w(TAG, "Failed to arm task-removed keepalive", t)
1448
+ }
1449
+ }
1438
1450
  Log.d(
1439
1451
  TAG,
1440
1452
  "onTaskRemoved received (monitoring=${isMonitoringActive(this)}, " +
@@ -17,9 +17,12 @@ private const val ACTION_RETRY_MONITORING = "expo.modules.beacon.ACTION_RETRY_MO
17
17
  * process has been killed.
18
18
  */
19
19
  internal const val ACTION_CARPLAY_WATCHDOG = "expo.modules.beacon.ACTION_CARPLAY_WATCHDOG"
20
+ private const val ACTION_TASK_REMOVED_KEEPALIVE = "expo.modules.beacon.ACTION_TASK_REMOVED_KEEPALIVE"
20
21
  private const val RETRY_DELAY_MS = 10_000L
21
22
  private const val RETRY_REQUEST_CODE = 0x424F4F54 // "BOOT"
22
23
  private const val CARPLAY_WATCHDOG_REQUEST_CODE = 0x43504C57 // "CPLW"
24
+ private const val TASK_REMOVED_KEEPALIVE_REQUEST_CODE = 0x54524B41 // "TRKA"
25
+ private const val TASK_REMOVED_KEEPALIVE_DELAY_MS = 2_000L
23
26
 
24
27
  /**
25
28
  * Cadence for the AlarmManager-based CarPlay watchdog. Set to **11 minutes**
@@ -75,6 +78,21 @@ class BootReceiver : BroadcastReceiver() {
75
78
  // Reschedule the next tick. setExactAndAllowWhileIdle is one-shot.
76
79
  scheduleCarPlayWatchdogAlarm(context)
77
80
  }
81
+ ACTION_TASK_REMOVED_KEEPALIVE -> {
82
+ val monitoringActive = BeaconForegroundService.isMonitoringActive(context)
83
+ val carPlayEnabled = BeaconForegroundService.isCarPlayEnabled(context)
84
+ if (!monitoringActive && !carPlayEnabled) {
85
+ Log.d(TAG, "BootReceiver: task-removed keepalive skipped (nothing active)")
86
+ return
87
+ }
88
+ if (carPlayEnabled) {
89
+ tryEnableCarPlay(context)
90
+ scheduleCarPlayWatchdogAlarm(context)
91
+ } else {
92
+ tryStartService(context)
93
+ }
94
+ Log.d(TAG, "BootReceiver: task-removed keepalive ensured service is running")
95
+ }
78
96
  }
79
97
  }
80
98
 
@@ -200,5 +218,35 @@ class BootReceiver : BroadcastReceiver() {
200
218
  Log.w(TAG, "BootReceiver: failed to cancel CarPlay watchdog alarm", t)
201
219
  }
202
220
  }
221
+
222
+ /**
223
+ * Schedule a near-term service keepalive after the user swipes the app
224
+ * task away. Some devices tear down the process despite a foreground
225
+ * service; this closes that gap before the slower periodic watchdogs run.
226
+ */
227
+ @JvmStatic
228
+ fun scheduleTaskRemovedKeepAlive(context: Context) {
229
+ val alarmManager = context.getSystemService(AlarmManager::class.java) ?: return
230
+ val intent = Intent(context, BootReceiver::class.java).apply {
231
+ action = ACTION_TASK_REMOVED_KEEPALIVE
232
+ `package` = context.packageName
233
+ }
234
+ val pendingIntent = PendingIntent.getBroadcast(
235
+ context,
236
+ TASK_REMOVED_KEEPALIVE_REQUEST_CODE,
237
+ intent,
238
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
239
+ )
240
+ try {
241
+ alarmManager.setExactAndAllowWhileIdle(
242
+ AlarmManager.ELAPSED_REALTIME_WAKEUP,
243
+ SystemClock.elapsedRealtime() + TASK_REMOVED_KEEPALIVE_DELAY_MS,
244
+ pendingIntent,
245
+ )
246
+ Log.d(TAG, "BootReceiver: task-removed keepalive armed (${TASK_REMOVED_KEEPALIVE_DELAY_MS}ms)")
247
+ } catch (t: Throwable) {
248
+ Log.w(TAG, "BootReceiver: failed to arm task-removed keepalive", t)
249
+ }
250
+ }
203
251
  }
204
252
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-beacon",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "Expo module for scanning, pairing, and monitoring iBeacons on Android and iOS",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",