kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
Merge pull request #434 from mcumings/radioservice-companion
Extract `RadioInterfaceService` companion object functionspull/435/head
commit
63db5f61dc
|
@ -88,7 +88,7 @@ android {
|
|||
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
freeCompilerArgs += [ '-Xopt-in=kotlin.RequiresOptIn' ]
|
||||
freeCompilerArgs += [ '-opt-in=kotlin.RequiresOptIn' ]
|
||||
}
|
||||
lint {
|
||||
abortOnError false
|
||||
|
|
|
@ -42,7 +42,6 @@ import com.geeksville.mesh.model.DeviceVersion
|
|||
import com.geeksville.mesh.model.UIViewModel
|
||||
import com.geeksville.mesh.repository.radio.RadioInterfaceService
|
||||
import com.geeksville.mesh.repository.radio.SerialInterface
|
||||
import com.geeksville.mesh.repository.usb.UsbRepository
|
||||
import com.geeksville.mesh.service.*
|
||||
import com.geeksville.mesh.ui.*
|
||||
import com.geeksville.util.Exceptions
|
||||
|
@ -140,7 +139,7 @@ class MainActivity : BaseActivity(), Logging,
|
|||
val model: UIViewModel by viewModels()
|
||||
|
||||
@Inject
|
||||
internal lateinit var usbRepository: UsbRepository
|
||||
internal lateinit var radioInterfaceService: RadioInterfaceService
|
||||
|
||||
data class TabInfo(val text: String, val icon: Int, val content: Fragment)
|
||||
|
||||
|
@ -982,7 +981,7 @@ class MainActivity : BaseActivity(), Logging,
|
|||
errormsg("Bind of MeshService failed")
|
||||
}
|
||||
|
||||
val bonded = RadioInterfaceService.getBondedDeviceAddress(this, usbRepository) != null
|
||||
val bonded = radioInterfaceService.getBondedDeviceAddress() != null
|
||||
if (!bonded && usbDevice == null) // we will handle USB later
|
||||
showSettingsPage()
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@ package com.geeksville.mesh.repository.radio
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import androidx.lifecycle.Lifecycle
|
||||
|
@ -15,8 +13,6 @@ import com.geeksville.concurrent.handledLaunch
|
|||
import com.geeksville.mesh.CoroutineDispatchers
|
||||
import com.geeksville.mesh.repository.bluetooth.BluetoothRepository
|
||||
import com.geeksville.mesh.repository.usb.UsbRepository
|
||||
import com.geeksville.mesh.service.EXTRA_PAYLOAD
|
||||
import com.geeksville.mesh.service.prefix
|
||||
import com.geeksville.util.anonymize
|
||||
import com.geeksville.util.ignoreException
|
||||
import com.geeksville.util.toRemoteExceptions
|
||||
|
@ -42,7 +38,8 @@ class RadioInterfaceService @Inject constructor(
|
|||
private val dispatchers: CoroutineDispatchers,
|
||||
private val bluetoothRepository: BluetoothRepository,
|
||||
private val processLifecycle: Lifecycle,
|
||||
private val usbRepository: UsbRepository
|
||||
private val usbRepository: UsbRepository,
|
||||
@RadioRepositoryQualifier private val prefs: SharedPreferences
|
||||
): Logging {
|
||||
|
||||
private val _connectionState = MutableStateFlow(RadioServiceConnectionState())
|
||||
|
@ -85,17 +82,6 @@ class RadioInterfaceService @Inject constructor(
|
|||
}
|
||||
|
||||
companion object : Logging {
|
||||
/**
|
||||
* The RECEIVED_FROMRADIO
|
||||
* Payload will be the raw bytes which were contained within a MeshProtos.FromRadio protobuf
|
||||
*/
|
||||
const val RECEIVE_FROMRADIO_ACTION = "$prefix.RECEIVE_FROMRADIO"
|
||||
|
||||
/**
|
||||
* This is broadcast when connection state changed
|
||||
*/
|
||||
const val RADIO_CONNECTED_ACTION = "$prefix.CONNECT_CHANGED"
|
||||
|
||||
const val DEVADDR_KEY = "devAddr2" // the new name for devaddr
|
||||
|
||||
init {
|
||||
|
@ -109,61 +95,49 @@ class RadioInterfaceService @Inject constructor(
|
|||
)
|
||||
info("Using ${factories.size} interface factories")
|
||||
}
|
||||
}
|
||||
|
||||
/// This is public only so that SimRadio can bootstrap our message flow
|
||||
fun broadcastReceivedFromRadio(context: Context, payload: ByteArray) {
|
||||
val intent = Intent(RECEIVE_FROMRADIO_ACTION)
|
||||
intent.putExtra(EXTRA_PAYLOAD, payload)
|
||||
context.sendBroadcast(intent)
|
||||
}
|
||||
|
||||
fun getPrefs(context: Context): SharedPreferences =
|
||||
context.getSharedPreferences("radio-prefs", Context.MODE_PRIVATE)
|
||||
|
||||
/** Return the device we are configured to use, or null for none
|
||||
* device address strings are of the form:
|
||||
*
|
||||
* at
|
||||
*
|
||||
* 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 getDeviceAddress(context: Context, usbRepository: UsbRepository): String? {
|
||||
// If the user has unpaired our device, treat things as if we don't have one
|
||||
val prefs = getPrefs(context)
|
||||
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 && MockInterface.addressValid(context, usbRepository, ""))
|
||||
address = MockInterface.prefix.toString()
|
||||
|
||||
return address
|
||||
}
|
||||
|
||||
/** Like getDeviceAddress, but filtered to return only devices we are currently bonded with
|
||||
*
|
||||
* at
|
||||
*
|
||||
* 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(context: Context, usbRepository: UsbRepository): String? {
|
||||
// If the user has unpaired our device, treat things as if we don't have one
|
||||
val address = getDeviceAddress(context, usbRepository)
|
||||
|
||||
/// Interfaces can filter addresses to indicate that address is no longer acceptable
|
||||
if (address != null) {
|
||||
val c = address[0]
|
||||
val rest = address.substring(1)
|
||||
val isValid = InterfaceFactory.getFactory(c)
|
||||
?.addressValid(context, usbRepository, rest) ?: false
|
||||
if (!isValid)
|
||||
return null
|
||||
}
|
||||
return address
|
||||
/** Return the device we are configured to use, or null for none
|
||||
* device address strings are of the form:
|
||||
*
|
||||
* at
|
||||
*
|
||||
* where a is either x for bluetooth or s for serial
|
||||
* and t is an interface specific address (macaddr or a device path)
|
||||
*/
|
||||
fun getDeviceAddress(): String? {
|
||||
// If the user has unpaired our device, treat things as if we don't have one
|
||||
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 && MockInterface.addressValid(context, usbRepository, ""))
|
||||
address = MockInterface.prefix.toString()
|
||||
|
||||
return address
|
||||
}
|
||||
|
||||
/** Like getDeviceAddress, but filtered to return only devices we are currently bonded with
|
||||
*
|
||||
* at
|
||||
*
|
||||
* 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()
|
||||
|
||||
/// Interfaces can filter addresses to indicate that address is no longer acceptable
|
||||
if (address != null) {
|
||||
val c = address[0]
|
||||
val rest = address.substring(1)
|
||||
val isValid = InterfaceFactory.getFactory(c)
|
||||
?.addressValid(context, usbRepository, rest) ?: false
|
||||
if (!isValid)
|
||||
return null
|
||||
}
|
||||
return address
|
||||
}
|
||||
|
||||
private fun broadcastConnectionChanged(isConnected: Boolean, isPermanent: Boolean) {
|
||||
|
@ -214,7 +188,7 @@ class RadioInterfaceService @Inject constructor(
|
|||
if (radioIf !is NopInterface)
|
||||
warn("Can't start interface - $radioIf is already running")
|
||||
else {
|
||||
val address = getBondedDeviceAddress(context, usbRepository)
|
||||
val address = getBondedDeviceAddress()
|
||||
if (address == null)
|
||||
warn("No bonded mesh radio, can't start interface")
|
||||
else {
|
||||
|
@ -263,7 +237,7 @@ class RadioInterfaceService @Inject constructor(
|
|||
*/
|
||||
@SuppressLint("NewApi")
|
||||
private fun setBondedDeviceAddress(address: String?): Boolean {
|
||||
return if (getBondedDeviceAddress(context, usbRepository) == address && isStarted) {
|
||||
return if (getBondedDeviceAddress() == address && isStarted) {
|
||||
warn("Ignoring setBondedDevice ${address.anonymize}, because we are already using that device")
|
||||
false
|
||||
} else {
|
||||
|
@ -281,7 +255,7 @@ class RadioInterfaceService @Inject constructor(
|
|||
|
||||
debug("Setting bonded device to ${address.anonymize}")
|
||||
|
||||
getPrefs(context).edit {
|
||||
prefs.edit {
|
||||
if (address == null)
|
||||
this.remove(DEVADDR_KEY)
|
||||
else
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
package com.geeksville.mesh.repository.radio
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object RadioRepositoryModule {
|
||||
@Provides
|
||||
@RadioRepositoryQualifier
|
||||
fun provideSharedPreferences(application: Application): SharedPreferences {
|
||||
return application.getSharedPreferences("radio-prefs", Context.MODE_PRIVATE)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.geeksville.mesh.repository.radio
|
||||
|
||||
import javax.inject.Qualifier
|
||||
|
||||
/**
|
||||
* Qualifier to distinguish radio repository- specific object instances.
|
||||
*/
|
||||
@Qualifier
|
||||
annotation class RadioRepositoryQualifier
|
|
@ -22,7 +22,6 @@ import com.geeksville.mesh.repository.location.LocationRepository
|
|||
import com.geeksville.mesh.repository.radio.BluetoothInterface
|
||||
import com.geeksville.mesh.repository.radio.RadioInterfaceService
|
||||
import com.geeksville.mesh.repository.radio.RadioServiceConnectionState
|
||||
import com.geeksville.mesh.repository.usb.UsbRepository
|
||||
import com.geeksville.util.*
|
||||
import com.google.protobuf.ByteString
|
||||
import com.google.protobuf.InvalidProtocolBufferException
|
||||
|
@ -55,9 +54,6 @@ class MeshService : Service(), Logging {
|
|||
@Inject
|
||||
lateinit var radioInterfaceService: RadioInterfaceService
|
||||
|
||||
@Inject
|
||||
lateinit var usbRepository: Lazy<UsbRepository>
|
||||
|
||||
@Inject
|
||||
lateinit var locationRepository: LocationRepository
|
||||
|
||||
|
@ -211,7 +207,7 @@ class MeshService : Service(), Logging {
|
|||
* tell android not to kill us
|
||||
*/
|
||||
private fun startForeground() {
|
||||
val a = RadioInterfaceService.getBondedDeviceAddress(this, usbRepository.get())
|
||||
val a = radioInterfaceService.getBondedDeviceAddress()
|
||||
val wantForeground = a != null && a != "n"
|
||||
|
||||
info("Requesting foreground service=$wantForeground")
|
||||
|
@ -1180,7 +1176,7 @@ class MeshService : Service(), Logging {
|
|||
private fun regenMyNodeInfo() {
|
||||
val myInfo = rawMyNodeInfo
|
||||
if (myInfo != null) {
|
||||
val a = RadioInterfaceService.getBondedDeviceAddress(this, usbRepository.get())
|
||||
val a = radioInterfaceService.getBondedDeviceAddress()
|
||||
val isBluetoothInterface = a != null && a.startsWith("x")
|
||||
|
||||
val nodeNum =
|
||||
|
|
|
@ -4,11 +4,7 @@ import android.annotation.SuppressLint
|
|||
import android.app.Application
|
||||
import android.app.PendingIntent
|
||||
import android.bluetooth.BluetoothDevice
|
||||
import android.bluetooth.le.BluetoothLeScanner
|
||||
import android.bluetooth.le.ScanCallback
|
||||
import android.bluetooth.le.ScanSettings
|
||||
import android.bluetooth.le.ScanFilter
|
||||
import android.bluetooth.le.ScanResult
|
||||
import android.bluetooth.le.*
|
||||
import android.companion.AssociationRequest
|
||||
import android.companion.BluetoothDeviceFilter
|
||||
import android.companion.CompanionDeviceManager
|
||||
|
@ -127,6 +123,7 @@ class BTScanModel @Inject constructor(
|
|||
private val bluetoothRepository: BluetoothRepository,
|
||||
private val usbRepository: UsbRepository,
|
||||
private val nsdRepository: NsdRepository,
|
||||
private val radioInterfaceService: RadioInterfaceService,
|
||||
) : ViewModel(), Logging {
|
||||
|
||||
private val context: Context get() = application.applicationContext
|
||||
|
@ -258,7 +255,7 @@ class BTScanModel @Inject constructor(
|
|||
* returns true if we could start scanning, false otherwise
|
||||
*/
|
||||
fun setupScan(): Boolean {
|
||||
selectedAddress = RadioInterfaceService.getDeviceAddress(context, usbRepository)
|
||||
selectedAddress = radioInterfaceService.getDeviceAddress()
|
||||
|
||||
return if (bluetoothAdapter == null || MockInterface.addressValid(context, usbRepository, "")) {
|
||||
warn("No bluetooth adapter. Running under emulation?")
|
||||
|
|
Ładowanie…
Reference in New Issue