mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
refactor: move RadioInterfaceService out of Activity / Fragment
This commit is contained in:
parent
94507195a8
commit
3922bfbffb
6 changed files with 28 additions and 64 deletions
|
|
@ -5,7 +5,6 @@ import android.bluetooth.BluetoothAdapter
|
|||
import android.content.*
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.hardware.usb.UsbDevice
|
||||
import android.hardware.usb.UsbManager
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
|
|
@ -38,13 +37,10 @@ import com.geeksville.mesh.model.UIViewModel
|
|||
import com.geeksville.mesh.model.primaryChannel
|
||||
import com.geeksville.mesh.model.toChannelSet
|
||||
import com.geeksville.mesh.repository.radio.BluetoothInterface
|
||||
import com.geeksville.mesh.repository.radio.InterfaceId
|
||||
import com.geeksville.mesh.repository.radio.RadioInterfaceService
|
||||
import com.geeksville.mesh.service.*
|
||||
import com.geeksville.mesh.ui.*
|
||||
import com.geeksville.mesh.ui.map.MapFragment
|
||||
import com.geeksville.mesh.util.Exceptions
|
||||
import com.geeksville.mesh.util.getParcelableExtraCompat
|
||||
import com.geeksville.mesh.util.LanguageUtils
|
||||
import com.geeksville.mesh.util.getPackageInfoCompat
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
|
@ -122,9 +118,6 @@ class MainActivity : AppCompatActivity(), Logging {
|
|||
@Inject
|
||||
internal lateinit var serviceRepository: ServiceRepository
|
||||
|
||||
@Inject
|
||||
internal lateinit var radioInterfaceService: RadioInterfaceService
|
||||
|
||||
private val bluetoothPermissionsLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result ->
|
||||
if (result.entries.all { it.value }) {
|
||||
|
|
@ -252,9 +245,6 @@ class MainActivity : AppCompatActivity(), Logging {
|
|||
|
||||
private var requestedChannelUrl: Uri? = null
|
||||
|
||||
/** We keep the usb device here, so later we can give it to our service */
|
||||
private var usbDevice: UsbDevice? = null
|
||||
|
||||
/// Handle any itents that were passed into us
|
||||
private fun handleIntent(intent: Intent) {
|
||||
val appLinkAction = intent.action
|
||||
|
|
@ -272,11 +262,7 @@ class MainActivity : AppCompatActivity(), Logging {
|
|||
}
|
||||
|
||||
UsbManager.ACTION_USB_DEVICE_ATTACHED -> {
|
||||
val device: UsbDevice? = intent.getParcelableExtraCompat(UsbManager.EXTRA_DEVICE)
|
||||
if (device != null) {
|
||||
debug("Handle USB device attached! $device")
|
||||
usbDevice = device
|
||||
}
|
||||
showSettingsPage()
|
||||
}
|
||||
|
||||
Intent.ACTION_MAIN -> {
|
||||
|
|
@ -464,13 +450,6 @@ class MainActivity : AppCompatActivity(), Logging {
|
|||
serviceRepository.setMeshService(service)
|
||||
|
||||
try {
|
||||
usbDevice?.let { usb ->
|
||||
debug("Switching to USB radio ${usb.deviceName}")
|
||||
val address = radioInterfaceService.toInterfaceAddress(InterfaceId.SERIAL, usb.deviceName)
|
||||
service.setDeviceAddress(address)
|
||||
usbDevice = null // Only switch once - thereafter it should be stored in settings
|
||||
}
|
||||
|
||||
val connectionState =
|
||||
MeshService.ConnectionState.valueOf(service.connectionState())
|
||||
|
||||
|
|
@ -593,8 +572,7 @@ class MainActivity : AppCompatActivity(), Logging {
|
|||
}
|
||||
|
||||
val bonded = model.bondedAddress != null
|
||||
if (!bonded && usbDevice == null) // we will handle USB later
|
||||
showSettingsPage()
|
||||
if (!bonded) showSettingsPage()
|
||||
}
|
||||
|
||||
private fun showSettingsPage() {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,10 @@ class BTScanModel @Inject constructor(
|
|||
private val bleDevices = MutableLiveData<List<BluetoothDevice>>(listOf())
|
||||
private val usbDevices = MutableLiveData<Map<String, UsbSerialDriver>>(mapOf())
|
||||
|
||||
val isMockInterfaceAddressValid: Boolean by lazy {
|
||||
radioInterfaceService.isAddressValid(radioInterfaceService.mockInterfaceAddress)
|
||||
}
|
||||
|
||||
init {
|
||||
combine(
|
||||
bluetoothRepository.state,
|
||||
|
|
@ -180,7 +184,7 @@ class BTScanModel @Inject constructor(
|
|||
private fun setupScan(): Boolean {
|
||||
selectedAddress = radioInterfaceService.getDeviceAddress()
|
||||
|
||||
return if (radioInterfaceService.isAddressValid(radioInterfaceService.mockInterfaceAddress)) {
|
||||
return if (isMockInterfaceAddressValid) {
|
||||
warn("Running under emulator/test lab")
|
||||
|
||||
val testnodes = listOf(
|
||||
|
|
|
|||
|
|
@ -8,11 +8,12 @@ enum class InterfaceId(val id: Char) {
|
|||
MOCK('m'),
|
||||
NOP('n'),
|
||||
SERIAL('s'),
|
||||
TCP('t');
|
||||
TCP('t'),
|
||||
;
|
||||
|
||||
companion object {
|
||||
fun forIdChar(id: Char): InterfaceId? {
|
||||
return values().firstOrNull { it.id == id }
|
||||
return entries.firstOrNull { it.id == id }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package com.geeksville.mesh.repository.radio
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
|
|
@ -16,7 +15,10 @@ import com.geeksville.mesh.repository.nsd.NsdRepository
|
|||
import com.geeksville.mesh.util.anonymize
|
||||
import com.geeksville.mesh.util.ignoreException
|
||||
import com.geeksville.mesh.util.toRemoteExceptions
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
|
|
@ -46,7 +48,6 @@ class RadioInterfaceService @Inject constructor(
|
|||
private val processLifecycle: Lifecycle,
|
||||
@RadioRepositoryQualifier private val prefs: SharedPreferences,
|
||||
private val interfaceFactory: InterfaceFactory,
|
||||
private val mockInterfaceSpec: MockInterfaceSpec
|
||||
) : Logging {
|
||||
|
||||
private val _connectionState = MutableStateFlow(RadioServiceConnectionState())
|
||||
|
|
@ -132,8 +133,9 @@ class RadioInterfaceService @Inject constructor(
|
|||
var address = prefs.getString(DEVADDR_KEY, null)
|
||||
|
||||
// If we are running on the emulator we default to the mock interface, so we can have some data to show to the user
|
||||
if (address == null && mockInterfaceSpec.addressValid(""))
|
||||
address = "${InterfaceId.MOCK.id}"
|
||||
if (address == null && isAddressValid(mockInterfaceAddress)) {
|
||||
address = mockInterfaceAddress
|
||||
}
|
||||
|
||||
return address
|
||||
}
|
||||
|
|
@ -145,7 +147,6 @@ class RadioInterfaceService @Inject constructor(
|
|||
* where a is either x for bluetooth or s for serial
|
||||
* and t is an interface specific address (macaddr or a device path)
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
fun getBondedDeviceAddress(): String? {
|
||||
// If the user has unpaired our device, treat things as if we don't have one
|
||||
val address = getDeviceAddress()
|
||||
|
|
@ -248,7 +249,6 @@ class RadioInterfaceService @Inject constructor(
|
|||
*
|
||||
* @return true if the device changed, false if no change
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
private fun setBondedDeviceAddress(address: String?): Boolean {
|
||||
return if (getBondedDeviceAddress() == address && isStarted) {
|
||||
warn("Ignoring setBondedDevice ${address.anonymize}, because we are already using that device")
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class SerialInterface @AssistedInject constructor(
|
|||
errormsg("Can't find device")
|
||||
} else {
|
||||
info("Opening $device")
|
||||
val onConnect: () -> Unit = { super.connect() }
|
||||
val onConnect: () -> Unit = { super.connect() }
|
||||
usbRepository.createSerialConnection(device, object : SerialConnectionListener {
|
||||
override fun onMissingPermission() {
|
||||
errormsg("Need permissions for port")
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import android.content.BroadcastReceiver
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.hardware.usb.UsbDevice
|
||||
import android.hardware.usb.UsbManager
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
|
|
@ -41,7 +40,6 @@ import com.geeksville.mesh.model.BluetoothViewModel
|
|||
import com.geeksville.mesh.model.UIViewModel
|
||||
import com.geeksville.mesh.model.getInitials
|
||||
import com.geeksville.mesh.repository.location.LocationRepository
|
||||
import com.geeksville.mesh.repository.radio.RadioInterfaceService
|
||||
import com.geeksville.mesh.service.MeshService
|
||||
import com.geeksville.mesh.service.SoftwareUpdateService
|
||||
import com.geeksville.mesh.util.PendingIntentCompat
|
||||
|
|
@ -66,9 +64,6 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
|||
private val bluetoothViewModel: BluetoothViewModel by activityViewModels()
|
||||
private val model: UIViewModel by activityViewModels()
|
||||
|
||||
@Inject
|
||||
internal lateinit var radioInterfaceServiceLazy: dagger.Lazy<RadioInterfaceService>
|
||||
|
||||
@Inject
|
||||
internal lateinit var locationRepository: LocationRepository
|
||||
|
||||
|
|
@ -502,8 +497,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
|||
// If we are running on an emulator, always leave this message showing so we can test the worst case layout
|
||||
val curRadio = scanModel.selectedAddress
|
||||
|
||||
val radioInterfaceService = radioInterfaceServiceLazy.get()
|
||||
if (curRadio != null && !radioInterfaceService.isAddressValid(radioInterfaceService.mockInterfaceAddress)) {
|
||||
if (curRadio != null && !scanModel.isMockInterfaceAddressValid) {
|
||||
binding.warningNotPaired.visibility = View.GONE
|
||||
} else if (bluetoothViewModel.enabled.value == true) {
|
||||
binding.warningNotPaired.visibility = View.VISIBLE
|
||||
|
|
@ -574,22 +568,13 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
|||
val usbReceiver = object : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (BTScanModel.ACTION_USB_PERMISSION == intent.action) {
|
||||
if (BTScanModel.ACTION_USB_PERMISSION != intent.action) return
|
||||
|
||||
val device: UsbDevice? =
|
||||
intent.getParcelableExtraCompat(UsbManager.EXTRA_DEVICE)
|
||||
val deviceName: String = device?.deviceName ?: "unknown"
|
||||
|
||||
if (intent.getBooleanExtra(
|
||||
UsbManager.EXTRA_PERMISSION_GRANTED,
|
||||
false
|
||||
)
|
||||
) {
|
||||
info("User approved USB access")
|
||||
changeDeviceAddress(it.fullAddress)
|
||||
} else {
|
||||
errormsg("USB permission denied for device $deviceName")
|
||||
}
|
||||
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
|
||||
info("User approved USB access")
|
||||
changeDeviceAddress(it.fullAddress)
|
||||
} else {
|
||||
errormsg("USB permission denied for device ${it.address}")
|
||||
}
|
||||
// We don't need to stay registered
|
||||
requireActivity().unregisterReceiver(this)
|
||||
|
|
@ -600,7 +585,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
|||
activity,
|
||||
0,
|
||||
Intent(BTScanModel.ACTION_USB_PERMISSION),
|
||||
PendingIntentCompat.FLAG_IMMUTABLE
|
||||
PendingIntentCompat.FLAG_MUTABLE
|
||||
)
|
||||
val filter = IntentFilter(BTScanModel.ACTION_USB_PERMISSION)
|
||||
requireActivity().registerReceiver(usbReceiver, filter)
|
||||
|
|
@ -622,12 +607,8 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
|||
// We need this receiver to get informed when the bond attempt finished
|
||||
val bondChangedReceiver = object : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(
|
||||
context: Context,
|
||||
intent: Intent
|
||||
) = exceptionReporter {
|
||||
val state =
|
||||
intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1)
|
||||
override fun onReceive(context: Context, intent: Intent) = exceptionReporter {
|
||||
val state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1)
|
||||
debug("Received bond state changed $state")
|
||||
|
||||
if (state != BluetoothDevice.BOND_BONDING) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue