mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 17:45:20 +00:00
check for support
This commit is contained in:
@@ -43,7 +43,7 @@ class BitchatApplication : Application() {
|
|||||||
|
|
||||||
// Initialize Wi‑Fi Aware controller with persisted default
|
// Initialize Wi‑Fi Aware controller with persisted default
|
||||||
try {
|
try {
|
||||||
val enabled = com.bitchat.android.ui.debug.DebugPreferenceManager.getWifiAwareEnabled(false)
|
val enabled = com.bitchat.android.ui.debug.DebugPreferenceManager.getWifiAwareEnabled(true)
|
||||||
com.bitchat.android.wifiaware.WifiAwareController.initialize(this, enabled)
|
com.bitchat.android.wifiaware.WifiAwareController.initialize(this, enabled)
|
||||||
} catch (_: Exception) { }
|
} catch (_: Exception) { }
|
||||||
|
|
||||||
|
|||||||
@@ -26,18 +26,17 @@ class PermissionManager(private val context: Context) {
|
|||||||
private fun shouldRequireWifiAwarePermission(): Boolean {
|
private fun shouldRequireWifiAwarePermission(): Boolean {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return false
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return false
|
||||||
val enabled = try {
|
val enabled = try {
|
||||||
com.bitchat.android.ui.debug.DebugPreferenceManager.getWifiAwareEnabled(false)
|
com.bitchat.android.ui.debug.DebugPreferenceManager.getWifiAwareEnabled(true)
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) {
|
||||||
false
|
true
|
||||||
}
|
}
|
||||||
if (!enabled) return false
|
if (!enabled) return false
|
||||||
|
|
||||||
val hasFeature = try {
|
return try {
|
||||||
context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)
|
com.bitchat.android.wifiaware.WifiAwareSupport.isSupported(context)
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
return hasFeature
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ object DebugPreferenceManager {
|
|||||||
if (ready()) prefs.edit().putBoolean(KEY_BLE_ENABLED, value).apply()
|
if (ready()) prefs.edit().putBoolean(KEY_BLE_ENABLED, value).apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getWifiAwareEnabled(default: Boolean = false): Boolean =
|
fun getWifiAwareEnabled(default: Boolean = true): Boolean =
|
||||||
if (ready()) prefs.getBoolean(KEY_WIFI_AWARE_ENABLED, default) else default
|
if (ready()) prefs.getBoolean(KEY_WIFI_AWARE_ENABLED, default) else default
|
||||||
|
|
||||||
fun setWifiAwareEnabled(value: Boolean) {
|
fun setWifiAwareEnabled(value: Boolean) {
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class DebugSettingsManager private constructor() {
|
|||||||
private val _bleEnabled = MutableStateFlow(true)
|
private val _bleEnabled = MutableStateFlow(true)
|
||||||
val bleEnabled: StateFlow<Boolean> = _bleEnabled.asStateFlow()
|
val bleEnabled: StateFlow<Boolean> = _bleEnabled.asStateFlow()
|
||||||
|
|
||||||
private val _wifiAwareEnabled = MutableStateFlow(false)
|
private val _wifiAwareEnabled = MutableStateFlow(true)
|
||||||
val wifiAwareEnabled: StateFlow<Boolean> = _wifiAwareEnabled.asStateFlow()
|
val wifiAwareEnabled: StateFlow<Boolean> = _wifiAwareEnabled.asStateFlow()
|
||||||
|
|
||||||
// Master transport toggles
|
// Master transport toggles
|
||||||
@@ -76,7 +76,7 @@ class DebugSettingsManager private constructor() {
|
|||||||
_maxClientConnections.value = DebugPreferenceManager.getMaxConnectionsClient(8)
|
_maxClientConnections.value = DebugPreferenceManager.getMaxConnectionsClient(8)
|
||||||
// Transport toggles
|
// Transport toggles
|
||||||
_bleEnabled.value = DebugPreferenceManager.getBleEnabled(true)
|
_bleEnabled.value = DebugPreferenceManager.getBleEnabled(true)
|
||||||
_wifiAwareEnabled.value = DebugPreferenceManager.getWifiAwareEnabled(false)
|
_wifiAwareEnabled.value = DebugPreferenceManager.getWifiAwareEnabled(true)
|
||||||
_wifiAwareVerbose.value = DebugPreferenceManager.getWifiAwareVerbose(false)
|
_wifiAwareVerbose.value = DebugPreferenceManager.getWifiAwareVerbose(false)
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) {
|
||||||
// Preferences not ready yet; keep defaults. They will be applied on first change.
|
// Preferences not ready yet; keep defaults. They will be applied on first change.
|
||||||
|
|||||||
@@ -130,6 +130,9 @@ fun DebugSettingsSheet(
|
|||||||
val wifiAwareVerbose by manager.wifiAwareVerbose.collectAsState()
|
val wifiAwareVerbose by manager.wifiAwareVerbose.collectAsState()
|
||||||
val wifiAwareDiscovered by manager.wifiAwareDiscovered.collectAsState()
|
val wifiAwareDiscovered by manager.wifiAwareDiscovered.collectAsState()
|
||||||
val wifiAwareConnected by manager.wifiAwareConnected.collectAsState()
|
val wifiAwareConnected by manager.wifiAwareConnected.collectAsState()
|
||||||
|
val wifiAwareSupported by com.bitchat.android.wifiaware.WifiAwareController.supported.collectAsState()
|
||||||
|
val wifiAwareAvailable by com.bitchat.android.wifiaware.WifiAwareController.available.collectAsState()
|
||||||
|
val wifiAwareSupportStatus by com.bitchat.android.wifiaware.WifiAwareController.supportStatus.collectAsState()
|
||||||
// Persistent notification is now controlled solely by MeshServicePreferences.isBackgroundEnabled
|
// Persistent notification is now controlled solely by MeshServicePreferences.isBackgroundEnabled
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
val isScrolled by remember {
|
val isScrolled by remember {
|
||||||
@@ -327,7 +330,23 @@ fun DebugSettingsSheet(
|
|||||||
Icon(Icons.Filled.Wifi, contentDescription = null, tint = Color(0xFF9C27B0))
|
Icon(Icons.Filled.Wifi, contentDescription = null, tint = Color(0xFF9C27B0))
|
||||||
Spacer(Modifier.width(8.dp))
|
Spacer(Modifier.width(8.dp))
|
||||||
Text("Wi‑Fi Aware", fontFamily = FontFamily.Monospace, modifier = Modifier.weight(1f))
|
Text("Wi‑Fi Aware", fontFamily = FontFamily.Monospace, modifier = Modifier.weight(1f))
|
||||||
Switch(checked = wifiAwareEnabled, onCheckedChange = { manager.setWifiAwareEnabled(it) })
|
val wifiSwitchEnabled = wifiAwareSupported
|
||||||
|
Text(
|
||||||
|
when {
|
||||||
|
!wifiAwareSupported -> "unsupported"
|
||||||
|
wifiAwareAvailable -> "available"
|
||||||
|
else -> "unavailable"
|
||||||
|
},
|
||||||
|
fontFamily = FontFamily.Monospace,
|
||||||
|
fontSize = 11.sp,
|
||||||
|
color = colorScheme.onSurface.copy(alpha = 0.6f)
|
||||||
|
)
|
||||||
|
Spacer(Modifier.width(8.dp))
|
||||||
|
Switch(
|
||||||
|
checked = wifiAwareEnabled && wifiAwareSupported,
|
||||||
|
enabled = wifiSwitchEnabled,
|
||||||
|
onCheckedChange = { manager.setWifiAwareEnabled(it) }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
Spacer(Modifier.width(24.dp))
|
Spacer(Modifier.width(24.dp))
|
||||||
@@ -601,17 +620,39 @@ fun DebugSettingsSheet(
|
|||||||
item {
|
item {
|
||||||
Surface(shape = RoundedCornerShape(12.dp), color = colorScheme.surfaceVariant.copy(alpha = 0.2f)) {
|
Surface(shape = RoundedCornerShape(12.dp), color = colorScheme.surfaceVariant.copy(alpha = 0.2f)) {
|
||||||
Column(Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
Column(Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||||
|
val running by com.bitchat.android.wifiaware.WifiAwareController.running.collectAsState()
|
||||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||||
Icon(Icons.Filled.WifiTethering, contentDescription = null, tint = Color(0xFF9C27B0))
|
Icon(Icons.Filled.WifiTethering, contentDescription = null, tint = Color(0xFF9C27B0))
|
||||||
Text("Wi‑Fi Aware", fontFamily = FontFamily.Monospace, fontSize = 14.sp, fontWeight = FontWeight.Medium)
|
Text("Wi‑Fi Aware", fontFamily = FontFamily.Monospace, fontSize = 14.sp, fontWeight = FontWeight.Medium)
|
||||||
Spacer(Modifier.weight(1f))
|
Spacer(Modifier.weight(1f))
|
||||||
val running by com.bitchat.android.wifiaware.WifiAwareController.running.collectAsState()
|
val wifiStatusText = when {
|
||||||
Text(if (running) "running" else "stopped", fontFamily = FontFamily.Monospace, fontSize = 12.sp, color = colorScheme.onSurface.copy(alpha = 0.7f))
|
!wifiAwareSupported -> "unsupported"
|
||||||
|
running -> "running"
|
||||||
|
!wifiAwareAvailable -> "unavailable"
|
||||||
|
else -> "stopped"
|
||||||
|
}
|
||||||
|
Text(wifiStatusText, fontFamily = FontFamily.Monospace, fontSize = 12.sp, color = colorScheme.onSurface.copy(alpha = 0.7f))
|
||||||
|
}
|
||||||
|
if (!wifiAwareSupported) {
|
||||||
|
Text(
|
||||||
|
wifiAwareSupportStatus?.reason ?: "Wi-Fi Aware is not supported on this device",
|
||||||
|
fontFamily = FontFamily.Monospace,
|
||||||
|
fontSize = 11.sp,
|
||||||
|
color = colorScheme.onSurface.copy(alpha = 0.6f)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||||
AssistChip(onClick = { manager.setWifiAwareEnabled(true) }, label = { Text("Start") })
|
AssistChip(
|
||||||
|
onClick = { manager.setWifiAwareEnabled(true) },
|
||||||
|
enabled = wifiAwareSupported,
|
||||||
|
label = { Text("Start") }
|
||||||
|
)
|
||||||
AssistChip(onClick = { manager.setWifiAwareEnabled(false) }, label = { Text("Stop") })
|
AssistChip(onClick = { manager.setWifiAwareEnabled(false) }, label = { Text("Stop") })
|
||||||
AssistChip(onClick = { com.bitchat.android.wifiaware.WifiAwareController.getService()?.sendBroadcastAnnounce() }, label = { Text("Announce") })
|
AssistChip(
|
||||||
|
onClick = { com.bitchat.android.wifiaware.WifiAwareController.getService()?.sendBroadcastAnnounce() },
|
||||||
|
enabled = running,
|
||||||
|
label = { Text("Announce") }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Text("Discovered: ${wifiAwareDiscovered.size}", fontFamily = FontFamily.Monospace, fontSize = 12.sp)
|
Text("Discovered: ${wifiAwareDiscovered.size}", fontFamily = FontFamily.Monospace, fontSize = 12.sp)
|
||||||
if (wifiAwareDiscovered.isEmpty()) {
|
if (wifiAwareDiscovered.isEmpty()) {
|
||||||
|
|||||||
@@ -30,12 +30,22 @@ object WifiAwareController {
|
|||||||
private var starting = false
|
private var starting = false
|
||||||
private val restartInFlight = AtomicBoolean(false)
|
private val restartInFlight = AtomicBoolean(false)
|
||||||
private var awareReceiverRegistered = false
|
private var awareReceiverRegistered = false
|
||||||
|
private var lastBlockedReason: String? = null
|
||||||
|
|
||||||
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||||
|
|
||||||
private val _enabled = MutableStateFlow(false)
|
private val _enabled = MutableStateFlow(false)
|
||||||
val enabled: StateFlow<Boolean> = _enabled.asStateFlow()
|
val enabled: StateFlow<Boolean> = _enabled.asStateFlow()
|
||||||
|
|
||||||
|
private val _supported = MutableStateFlow(false)
|
||||||
|
val supported: StateFlow<Boolean> = _supported.asStateFlow()
|
||||||
|
|
||||||
|
private val _available = MutableStateFlow(false)
|
||||||
|
val available: StateFlow<Boolean> = _available.asStateFlow()
|
||||||
|
|
||||||
|
private val _supportStatus = MutableStateFlow<WifiAwareSupport.Status?>(null)
|
||||||
|
val supportStatus: StateFlow<WifiAwareSupport.Status?> = _supportStatus.asStateFlow()
|
||||||
|
|
||||||
private val _running = MutableStateFlow(false)
|
private val _running = MutableStateFlow(false)
|
||||||
val running: StateFlow<Boolean> = _running.asStateFlow()
|
val running: StateFlow<Boolean> = _running.asStateFlow()
|
||||||
|
|
||||||
@@ -51,7 +61,12 @@ object WifiAwareController {
|
|||||||
|
|
||||||
fun initialize(context: Context, enabledByDefault: Boolean) {
|
fun initialize(context: Context, enabledByDefault: Boolean) {
|
||||||
appContext = context.applicationContext
|
appContext = context.applicationContext
|
||||||
registerAwareStateReceiver(appContext!!)
|
val status = refreshSupportStatus(appContext!!)
|
||||||
|
if (status.supported) {
|
||||||
|
registerAwareStateReceiver(appContext!!)
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "Wi-Fi Aware unsupported: ${status.reason}")
|
||||||
|
}
|
||||||
setEnabled(enabledByDefault)
|
setEnabled(enabledByDefault)
|
||||||
// Start background poller for debug surfacing
|
// Start background poller for debug surfacing
|
||||||
scope.launch {
|
scope.launch {
|
||||||
@@ -95,16 +110,20 @@ object WifiAwareController {
|
|||||||
synchronized(lifecycleLock) { starting = false }
|
synchronized(lifecycleLock) { starting = false }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
|
||||||
Log.w(TAG, "Wi‑Fi Aware requires Android 10 (Q)+; disabled.")
|
val status = refreshSupportStatus(ctx)
|
||||||
try { com.bitchat.android.ui.debug.DebugSettingsManager.getInstance().addDebugMessage(com.bitchat.android.ui.debug.DebugMessage.SystemMessage("Wi‑Fi Aware not supported on this device (requires Android 10+)")) } catch (_: Exception) {}
|
if (!status.supported) {
|
||||||
|
val reason = status.reason ?: "not supported"
|
||||||
|
Log.w(TAG, "Wi‑Fi Aware unsupported; not starting ($reason)")
|
||||||
|
addBlockedDebugMessage("unsupported:$reason", "Wi-Fi Aware not supported on this device ($reason)")
|
||||||
synchronized(lifecycleLock) { starting = false }
|
synchronized(lifecycleLock) { starting = false }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val awareManager = ctx.getSystemService(android.net.wifi.aware.WifiAwareManager::class.java)
|
|
||||||
if (awareManager == null || !awareManager.isAvailable) {
|
val awareManager = WifiAwareSupport.getManager(ctx)
|
||||||
|
if (awareManager == null || !status.available) {
|
||||||
Log.w(TAG, "Wi-Fi Aware is not currently available; not starting")
|
Log.w(TAG, "Wi-Fi Aware is not currently available; not starting")
|
||||||
try { com.bitchat.android.ui.debug.DebugSettingsManager.getInstance().addDebugMessage(com.bitchat.android.ui.debug.DebugMessage.SystemMessage("Wi‑Fi Aware is not available on this device right now")) } catch (_: Exception) {}
|
addBlockedDebugMessage("unavailable", "Wi-Fi Aware is not available right now")
|
||||||
synchronized(lifecycleLock) { starting = false }
|
synchronized(lifecycleLock) { starting = false }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -121,7 +140,7 @@ object WifiAwareController {
|
|||||||
|
|
||||||
if (!locationEnabled) {
|
if (!locationEnabled) {
|
||||||
Log.w(TAG, "Location services are disabled; Wi-Fi Aware cannot start.")
|
Log.w(TAG, "Location services are disabled; Wi-Fi Aware cannot start.")
|
||||||
try { com.bitchat.android.ui.debug.DebugSettingsManager.getInstance().addDebugMessage(com.bitchat.android.ui.debug.DebugMessage.SystemMessage("Enable Location Services to start Wi-Fi Aware")) } catch (_: Exception) {}
|
addBlockedDebugMessage("location-disabled", "Enable Location Services to start Wi-Fi Aware")
|
||||||
synchronized(lifecycleLock) { starting = false }
|
synchronized(lifecycleLock) { starting = false }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -131,7 +150,7 @@ object WifiAwareController {
|
|||||||
val granted = androidx.core.content.ContextCompat.checkSelfPermission(ctx, android.Manifest.permission.NEARBY_WIFI_DEVICES) == android.content.pm.PackageManager.PERMISSION_GRANTED
|
val granted = androidx.core.content.ContextCompat.checkSelfPermission(ctx, android.Manifest.permission.NEARBY_WIFI_DEVICES) == android.content.pm.PackageManager.PERMISSION_GRANTED
|
||||||
if (!granted) {
|
if (!granted) {
|
||||||
Log.w(TAG, "Missing NEARBY_WIFI_DEVICES permission; not starting Wi‑Fi Aware")
|
Log.w(TAG, "Missing NEARBY_WIFI_DEVICES permission; not starting Wi‑Fi Aware")
|
||||||
try { com.bitchat.android.ui.debug.DebugSettingsManager.getInstance().addDebugMessage(com.bitchat.android.ui.debug.DebugMessage.SystemMessage("Grant Nearby Wi‑Fi Devices to start Wi‑Fi Aware")) } catch (_: Exception) {}
|
addBlockedDebugMessage("missing-nearby-wifi", "Grant Nearby Wi-Fi Devices to start Wi-Fi Aware")
|
||||||
synchronized(lifecycleLock) { starting = false }
|
synchronized(lifecycleLock) { starting = false }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -152,6 +171,7 @@ object WifiAwareController {
|
|||||||
_running.value = true
|
_running.value = true
|
||||||
}
|
}
|
||||||
try { com.bitchat.android.service.MeshServiceHolder.unifiedMeshService?.refreshDelegates() } catch (_: Exception) { }
|
try { com.bitchat.android.service.MeshServiceHolder.unifiedMeshService?.refreshDelegates() } catch (_: Exception) { }
|
||||||
|
clearBlockedDebugMessage()
|
||||||
try { com.bitchat.android.ui.debug.DebugSettingsManager.getInstance().addDebugMessage(com.bitchat.android.ui.debug.DebugMessage.SystemMessage("Wi‑Fi Aware started")) } catch (_: Exception) {}
|
try { com.bitchat.android.ui.debug.DebugSettingsManager.getInstance().addDebugMessage(com.bitchat.android.ui.debug.DebugMessage.SystemMessage("Wi‑Fi Aware started")) } catch (_: Exception) {}
|
||||||
} else {
|
} else {
|
||||||
if (reusableService == null) {
|
if (reusableService == null) {
|
||||||
@@ -216,6 +236,8 @@ object WifiAwareController {
|
|||||||
if (delayMs > 0L) delay(delayMs)
|
if (delayMs > 0L) delay(delayMs)
|
||||||
var attempt = 0
|
var attempt = 0
|
||||||
while (_enabled.value && !_running.value && attempt < MAX_RESTART_ATTEMPTS) {
|
while (_enabled.value && !_running.value && attempt < MAX_RESTART_ATTEMPTS) {
|
||||||
|
val ctx = appContext
|
||||||
|
if (ctx != null && !refreshSupportStatus(ctx).supported) break
|
||||||
startIfPossible()
|
startIfPossible()
|
||||||
if (_running.value) break
|
if (_running.value) break
|
||||||
attempt++
|
attempt++
|
||||||
@@ -234,17 +256,16 @@ object WifiAwareController {
|
|||||||
*/
|
*/
|
||||||
private fun registerAwareStateReceiver(ctx: Context) {
|
private fun registerAwareStateReceiver(ctx: Context) {
|
||||||
if (awareReceiverRegistered) return
|
if (awareReceiverRegistered) return
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) return
|
if (!refreshSupportStatus(ctx).supported) return
|
||||||
try {
|
try {
|
||||||
val filter = android.content.IntentFilter(
|
val filter = android.content.IntentFilter(
|
||||||
android.net.wifi.aware.WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED
|
android.net.wifi.aware.WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED
|
||||||
)
|
)
|
||||||
ctx.registerReceiver(object : android.content.BroadcastReceiver() {
|
ctx.registerReceiver(object : android.content.BroadcastReceiver() {
|
||||||
override fun onReceive(c: Context?, intent: android.content.Intent?) {
|
override fun onReceive(c: Context?, intent: android.content.Intent?) {
|
||||||
val mgr = ctx.getSystemService(android.net.wifi.aware.WifiAwareManager::class.java)
|
val status = refreshSupportStatus(ctx)
|
||||||
val available = mgr?.isAvailable == true
|
Log.i(TAG, "Wi-Fi Aware availability changed: supported=${status.supported} available=${status.available} enabled=${_enabled.value} running=${_running.value}")
|
||||||
Log.i(TAG, "Wi-Fi Aware availability changed: available=$available enabled=${_enabled.value} running=${_running.value}")
|
if (status.available) {
|
||||||
if (available) {
|
|
||||||
if (_enabled.value) restartIfStillEnabled(500)
|
if (_enabled.value) restartIfStillEnabled(500)
|
||||||
} else if (_running.value) {
|
} else if (_running.value) {
|
||||||
// Aware went away; tear down cleanly so we can re-attach when it returns.
|
// Aware went away; tear down cleanly so we can re-attach when it returns.
|
||||||
@@ -259,5 +280,26 @@ object WifiAwareController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun refreshSupportStatus(ctx: Context): WifiAwareSupport.Status {
|
||||||
|
val status = WifiAwareSupport.evaluate(ctx)
|
||||||
|
_supported.value = status.supported
|
||||||
|
_available.value = status.available
|
||||||
|
_supportStatus.value = status
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addBlockedDebugMessage(key: String, message: String) {
|
||||||
|
if (lastBlockedReason == key) return
|
||||||
|
lastBlockedReason = key
|
||||||
|
try {
|
||||||
|
com.bitchat.android.ui.debug.DebugSettingsManager.getInstance()
|
||||||
|
.addDebugMessage(com.bitchat.android.ui.debug.DebugMessage.SystemMessage(message))
|
||||||
|
} catch (_: Exception) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clearBlockedDebugMessage() {
|
||||||
|
lastBlockedReason = null
|
||||||
|
}
|
||||||
|
|
||||||
fun getService(): WifiAwareMeshService? = service
|
fun getService(): WifiAwareMeshService? = service
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -318,6 +318,15 @@ class WifiAwareMeshService(private val context: Context) : MeshService, Transpor
|
|||||||
Log.i(TAG, "Wi-Fi Aware transport disabled by debug settings; not starting")
|
Log.i(TAG, "Wi-Fi Aware transport disabled by debug settings; not starting")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
val supportStatus = com.bitchat.android.wifiaware.WifiAwareSupport.evaluate(context)
|
||||||
|
if (!supportStatus.supported) {
|
||||||
|
Log.i(TAG, "Wi-Fi Aware unsupported on this device; not starting (${supportStatus.reason})")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!supportStatus.available) {
|
||||||
|
Log.i(TAG, "Wi-Fi Aware unavailable right now; not starting (${supportStatus.reason})")
|
||||||
|
return
|
||||||
|
}
|
||||||
if (recoveryInProgress) {
|
if (recoveryInProgress) {
|
||||||
Log.i(TAG, "Wi-Fi Aware recovery cleanup still in progress; deferring start")
|
Log.i(TAG, "Wi-Fi Aware recovery cleanup still in progress; deferring start")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package com.bitchat.android.wifiaware
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.net.wifi.aware.WifiAwareManager
|
||||||
|
import android.os.Build
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Centralized Wi-Fi Aware capability checks.
|
||||||
|
*
|
||||||
|
* "Supported" is stable device/API capability. "Available" is runtime state and can change
|
||||||
|
* when Wi-Fi, location, airplane mode, or system radio state changes.
|
||||||
|
*/
|
||||||
|
object WifiAwareSupport {
|
||||||
|
data class Status(
|
||||||
|
val supported: Boolean,
|
||||||
|
val available: Boolean,
|
||||||
|
val reason: String? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
fun evaluate(context: Context): Status {
|
||||||
|
val appContext = context.applicationContext
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||||
|
return Status(
|
||||||
|
supported = false,
|
||||||
|
available = false,
|
||||||
|
reason = "requires Android 10+"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val hasFeature = try {
|
||||||
|
appContext.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
if (!hasFeature) {
|
||||||
|
return Status(
|
||||||
|
supported = false,
|
||||||
|
available = false,
|
||||||
|
reason = "device does not advertise Wi-Fi Aware support"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val manager = getManager(appContext)
|
||||||
|
?: return Status(
|
||||||
|
supported = false,
|
||||||
|
available = false,
|
||||||
|
reason = "WifiAwareManager unavailable"
|
||||||
|
)
|
||||||
|
|
||||||
|
val available = try {
|
||||||
|
manager.isAvailable
|
||||||
|
} catch (_: Exception) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status(
|
||||||
|
supported = true,
|
||||||
|
available = available,
|
||||||
|
reason = if (available) null else "Wi-Fi Aware temporarily unavailable"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isSupported(context: Context): Boolean = evaluate(context).supported
|
||||||
|
|
||||||
|
fun getManager(context: Context): WifiAwareManager? {
|
||||||
|
return try {
|
||||||
|
context.applicationContext.getSystemService(WifiAwareManager::class.java)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user