mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-24 23:45:19 +00:00
Fix foreground service start eligibility (#714)
* Fix foreground service start eligibility * Defer foreground service start when backgrounded * fix crash --------- Co-authored-by: CC <cc@ggg.local>
This commit is contained in:
@@ -59,6 +59,7 @@ class MainActivity : OrientationAwareActivity() {
|
|||||||
private lateinit var meshService: BluetoothMeshService
|
private lateinit var meshService: BluetoothMeshService
|
||||||
private lateinit var unifiedMeshService: MeshService
|
private lateinit var unifiedMeshService: MeshService
|
||||||
private val mainViewModel: MainViewModel by viewModels()
|
private val mainViewModel: MainViewModel by viewModels()
|
||||||
|
private var pendingMeshForegroundServiceStart = false
|
||||||
private val chatViewModel: ChatViewModel by viewModels {
|
private val chatViewModel: ChatViewModel by viewModels {
|
||||||
object : ViewModelProvider.Factory {
|
object : ViewModelProvider.Factory {
|
||||||
override fun <T : androidx.lifecycle.ViewModel> create(modelClass: Class<T>): T {
|
override fun <T : androidx.lifecycle.ViewModel> create(modelClass: Class<T>): T {
|
||||||
@@ -114,8 +115,8 @@ class MainActivity : OrientationAwareActivity() {
|
|||||||
|
|
||||||
// Initialize permission management
|
// Initialize permission management
|
||||||
permissionManager = PermissionManager(this)
|
permissionManager = PermissionManager(this)
|
||||||
// Ensure foreground service is running and get mesh instance from holder
|
// Start the foreground service when allowed, then get mesh instances from the holder.
|
||||||
try { com.bitchat.android.service.MeshForegroundService.start(applicationContext) } catch (_: Exception) { }
|
startMeshForegroundServiceBestEffort()
|
||||||
meshService = com.bitchat.android.service.MeshServiceHolder.getOrCreate(applicationContext)
|
meshService = com.bitchat.android.service.MeshServiceHolder.getOrCreate(applicationContext)
|
||||||
unifiedMeshService = com.bitchat.android.service.MeshServiceHolder.getUnifiedOrCreate(applicationContext)
|
unifiedMeshService = com.bitchat.android.service.MeshServiceHolder.getUnifiedOrCreate(applicationContext)
|
||||||
// Expose BLE mesh to Wi‑Fi Aware controller for cross-transport relays - DEPRECATED
|
// Expose BLE mesh to Wi‑Fi Aware controller for cross-transport relays - DEPRECATED
|
||||||
@@ -615,6 +616,22 @@ class MainActivity : OrientationAwareActivity() {
|
|||||||
mainViewModel.updateOnboardingState(OnboardingState.ERROR)
|
mainViewModel.updateOnboardingState(OnboardingState.ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun startMeshForegroundServiceBestEffort() {
|
||||||
|
if (!lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
|
||||||
|
pendingMeshForegroundServiceStart = true
|
||||||
|
Log.i("MainActivity", "Deferring foreground mesh service start until activity is started")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
com.bitchat.android.service.MeshForegroundService.start(applicationContext)
|
||||||
|
pendingMeshForegroundServiceStart = false
|
||||||
|
} catch (e: Exception) {
|
||||||
|
pendingMeshForegroundServiceStart = true
|
||||||
|
Log.w("MainActivity", "Unable to start foreground mesh service; will retry when activity is started", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check Battery Optimization status and proceed with onboarding flow
|
* Check Battery Optimization status and proceed with onboarding flow
|
||||||
*/
|
*/
|
||||||
@@ -715,6 +732,7 @@ class MainActivity : OrientationAwareActivity() {
|
|||||||
// Set up unified mesh delegate and start enabled transports
|
// Set up unified mesh delegate and start enabled transports
|
||||||
unifiedMeshService.delegate = chatViewModel
|
unifiedMeshService.delegate = chatViewModel
|
||||||
unifiedMeshService.startServices()
|
unifiedMeshService.startServices()
|
||||||
|
startMeshForegroundServiceBestEffort()
|
||||||
|
|
||||||
Log.d("MainActivity", "Mesh service started successfully")
|
Log.d("MainActivity", "Mesh service started successfully")
|
||||||
|
|
||||||
@@ -753,6 +771,13 @@ class MainActivity : OrientationAwareActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
if (pendingMeshForegroundServiceStart) {
|
||||||
|
startMeshForegroundServiceBestEffort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
// Check Bluetooth and Location status on resume and handle accordingly
|
// Check Bluetooth and Location status on resume and handle accordingly
|
||||||
|
|||||||
@@ -38,24 +38,20 @@ class MeshForegroundService : Service() {
|
|||||||
fun start(context: Context) {
|
fun start(context: Context) {
|
||||||
val intent = Intent(context, MeshForegroundService::class.java).apply { action = ACTION_START }
|
val intent = Intent(context, MeshForegroundService::class.java).apply { action = ACTION_START }
|
||||||
|
|
||||||
// On API >= 26, avoid background-service start restrictions by using startForegroundService
|
// Only launch as an FGS when onStartCommand can promote immediately.
|
||||||
// only when we can actually post a notification (Android 13+ requires runtime notif permission)
|
val shouldStartForeground = shouldStartAsForeground(context)
|
||||||
val bgEnabled = MeshServicePreferences.isBackgroundEnabled(true)
|
|
||||||
val hasNotifPerm = hasNotificationPermissionStatic(context)
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
if (bgEnabled && hasNotifPerm) {
|
if (shouldStartForeground) {
|
||||||
context.startForegroundService(intent)
|
context.startForegroundService(intent)
|
||||||
} else {
|
} else {
|
||||||
// Do not attempt to start a background service from headless context without notif permission
|
|
||||||
// or when background is disabled, to avoid BackgroundServiceStartNotAllowedException.
|
|
||||||
android.util.Log.i(
|
android.util.Log.i(
|
||||||
"MeshForegroundService",
|
"MeshForegroundService",
|
||||||
"Not starting service on API>=26 (bgEnabled=$bgEnabled, hasNotifPerm=$hasNotifPerm)"
|
"Not starting service on API>=26 (shouldStartForeground=$shouldStartForeground)"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (bgEnabled) {
|
if (MeshServicePreferences.isBackgroundEnabled(true)) {
|
||||||
context.startService(intent)
|
context.startService(intent)
|
||||||
} else {
|
} else {
|
||||||
android.util.Log.i("MeshForegroundService", "Background disabled; not starting service (pre-O)")
|
android.util.Log.i("MeshForegroundService", "Background disabled; not starting service (pre-O)")
|
||||||
@@ -69,12 +65,10 @@ class MeshForegroundService : Service() {
|
|||||||
*/
|
*/
|
||||||
fun onNotificationPermissionGranted(context: Context) {
|
fun onNotificationPermissionGranted(context: Context) {
|
||||||
// If background is enabled and permission now granted, start/promo service
|
// If background is enabled and permission now granted, start/promo service
|
||||||
val hasNotifPerm = hasNotificationPermissionStatic(context)
|
if (!shouldStartAsForeground(context)) return
|
||||||
if (!MeshServicePreferences.isBackgroundEnabled(true) || !hasNotifPerm) return
|
|
||||||
|
|
||||||
val intent = Intent(context, MeshForegroundService::class.java).apply { action = ACTION_UPDATE_NOTIFICATION }
|
val intent = Intent(context, MeshForegroundService::class.java).apply { action = ACTION_UPDATE_NOTIFICATION }
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
// Safe now that we can show a notification
|
|
||||||
context.startForegroundService(intent)
|
context.startForegroundService(intent)
|
||||||
} else {
|
} else {
|
||||||
context.startService(intent)
|
context.startService(intent)
|
||||||
|
|||||||
Reference in New Issue
Block a user