Merge branch 'main' into native-theme

This commit is contained in:
CC 2026-06-17 20:56:47 +02:00
commit bfe2619442
7 changed files with 41 additions and 22 deletions

View File

@ -13,8 +13,8 @@ android {
applicationId = "com.bitchat.droid"
minSdk = libs.versions.minSdk.get().toInt()
targetSdk = libs.versions.targetSdk.get().toInt()
versionCode = 33
versionName = "1.7.2"
versionCode = 35
versionName = "1.7.4"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {

View File

@ -46,7 +46,7 @@ class BitchatApplication : Application() {
// Initialize WiFi Aware controller with persisted default
try {
val enabled = com.bitchat.android.ui.debug.DebugPreferenceManager.getWifiAwareEnabled(true)
val enabled = com.bitchat.android.ui.debug.DebugPreferenceManager.getWifiAwareEnabled(false)
com.bitchat.android.wifiaware.WifiAwareController.initialize(this, enabled)
} catch (_: Exception) { }

View File

@ -59,6 +59,7 @@ class MainActivity : OrientationAwareActivity() {
private lateinit var meshService: BluetoothMeshService
private lateinit var unifiedMeshService: MeshService
private val mainViewModel: MainViewModel by viewModels()
private var pendingMeshForegroundServiceStart = false
private val chatViewModel: ChatViewModel by viewModels {
object : ViewModelProvider.Factory {
override fun <T : androidx.lifecycle.ViewModel> create(modelClass: Class<T>): T {
@ -114,8 +115,8 @@ class MainActivity : OrientationAwareActivity() {
// Initialize permission management
permissionManager = PermissionManager(this)
// Ensure foreground service is running and get mesh instance from holder
try { com.bitchat.android.service.MeshForegroundService.start(applicationContext) } catch (_: Exception) { }
// Start the foreground service when allowed, then get mesh instances from the holder.
startMeshForegroundServiceBestEffort()
meshService = com.bitchat.android.service.MeshServiceHolder.getOrCreate(applicationContext)
unifiedMeshService = com.bitchat.android.service.MeshServiceHolder.getUnifiedOrCreate(applicationContext)
// Expose BLE mesh to WiFi Aware controller for cross-transport relays - DEPRECATED
@ -614,6 +615,22 @@ class MainActivity : OrientationAwareActivity() {
mainViewModel.updateErrorMessage(message)
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
@ -715,6 +732,7 @@ class MainActivity : OrientationAwareActivity() {
// Set up unified mesh delegate and start enabled transports
unifiedMeshService.delegate = chatViewModel
unifiedMeshService.startServices()
startMeshForegroundServiceBestEffort()
Log.d("MainActivity", "Mesh service started successfully")
@ -752,6 +770,13 @@ class MainActivity : OrientationAwareActivity() {
handleVerificationIntent(intent)
}
}
override fun onStart() {
super.onStart()
if (pendingMeshForegroundServiceStart) {
startMeshForegroundServiceBestEffort()
}
}
override fun onResume() {
super.onResume()

View File

@ -26,9 +26,9 @@ class PermissionManager(private val context: Context) {
private fun shouldRequireWifiAwarePermission(): Boolean {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return false
val enabled = try {
com.bitchat.android.ui.debug.DebugPreferenceManager.getWifiAwareEnabled(true)
com.bitchat.android.ui.debug.DebugPreferenceManager.getWifiAwareEnabled(false)
} catch (_: Exception) {
true
false
}
if (!enabled) return false

View File

@ -38,24 +38,20 @@ class MeshForegroundService : Service() {
fun start(context: Context) {
val intent = Intent(context, MeshForegroundService::class.java).apply { action = ACTION_START }
// On API >= 26, avoid background-service start restrictions by using startForegroundService
// only when we can actually post a notification (Android 13+ requires runtime notif permission)
val bgEnabled = MeshServicePreferences.isBackgroundEnabled(true)
val hasNotifPerm = hasNotificationPermissionStatic(context)
// Only launch as an FGS when onStartCommand can promote immediately.
val shouldStartForeground = shouldStartAsForeground(context)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (bgEnabled && hasNotifPerm) {
if (shouldStartForeground) {
context.startForegroundService(intent)
} 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(
"MeshForegroundService",
"Not starting service on API>=26 (bgEnabled=$bgEnabled, hasNotifPerm=$hasNotifPerm)"
"Not starting service on API>=26 (shouldStartForeground=$shouldStartForeground)"
)
}
} else {
if (bgEnabled) {
if (MeshServicePreferences.isBackgroundEnabled(true)) {
context.startService(intent)
} else {
android.util.Log.i("MeshForegroundService", "Background disabled; not starting service (pre-O)")
@ -69,12 +65,10 @@ class MeshForegroundService : Service() {
*/
fun onNotificationPermissionGranted(context: Context) {
// If background is enabled and permission now granted, start/promo service
val hasNotifPerm = hasNotificationPermissionStatic(context)
if (!MeshServicePreferences.isBackgroundEnabled(true) || !hasNotifPerm) return
if (!shouldStartAsForeground(context)) return
val intent = Intent(context, MeshForegroundService::class.java).apply { action = ACTION_UPDATE_NOTIFICATION }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Safe now that we can show a notification
context.startForegroundService(intent)
} else {
context.startService(intent)

View File

@ -113,7 +113,7 @@ object DebugPreferenceManager {
if (ready()) prefs.edit().putBoolean(KEY_BLE_ENABLED, value).apply()
}
fun getWifiAwareEnabled(default: Boolean = true): Boolean =
fun getWifiAwareEnabled(default: Boolean = false): Boolean =
if (ready()) prefs.getBoolean(KEY_WIFI_AWARE_ENABLED, default) else default
fun setWifiAwareEnabled(value: Boolean) {

View File

@ -44,7 +44,7 @@ class DebugSettingsManager private constructor() {
private val _bleEnabled = MutableStateFlow(true)
val bleEnabled: StateFlow<Boolean> = _bleEnabled.asStateFlow()
private val _wifiAwareEnabled = MutableStateFlow(true)
private val _wifiAwareEnabled = MutableStateFlow(false)
val wifiAwareEnabled: StateFlow<Boolean> = _wifiAwareEnabled.asStateFlow()
// Master transport toggles
@ -76,7 +76,7 @@ class DebugSettingsManager private constructor() {
_maxClientConnections.value = DebugPreferenceManager.getMaxConnectionsClient(8)
// Transport toggles
_bleEnabled.value = DebugPreferenceManager.getBleEnabled(true)
_wifiAwareEnabled.value = DebugPreferenceManager.getWifiAwareEnabled(true)
_wifiAwareEnabled.value = DebugPreferenceManager.getWifiAwareEnabled(false)
_wifiAwareVerbose.value = DebugPreferenceManager.getWifiAwareVerbose(false)
} catch (_: Exception) {
// Preferences not ready yet; keep defaults. They will be applied on first change.