diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b63f8d9df..343f5515d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -57,6 +57,11 @@ android:name="android.software.companion_device_setup" android:required="false" /> + + + - - + + @@ -135,6 +138,10 @@ android:pathPrefix="/c/" /> + + + + { + UsbManager.ACTION_USB_DEVICE_ATTACHED -> { val device: UsbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)!! - errormsg("Handle USB device attached! $device") + debug("Handle USB device attached! $device") + showSettingsPage() // Later in the boot we should show the settings page } Intent.ACTION_MAIN -> { @@ -750,7 +751,11 @@ class MainActivity : AppCompatActivity(), Logging, val bonded = RadioInterfaceService.getBondedDeviceAddress(this) != null if (!bonded) - pager.currentItem = 5 + showSettingsPage() + } + + fun showSettingsPage() { + pager.currentItem = 5 } override fun onCreateOptionsMenu(menu: Menu): Boolean { diff --git a/app/src/main/java/com/geeksville/mesh/service/SerialInterface.kt b/app/src/main/java/com/geeksville/mesh/service/SerialInterface.kt index 784b98745..0bac2490c 100644 --- a/app/src/main/java/com/geeksville/mesh/service/SerialInterface.kt +++ b/app/src/main/java/com/geeksville/mesh/service/SerialInterface.kt @@ -1,8 +1,13 @@ package com.geeksville.mesh.service +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 com.geeksville.android.Logging +import com.geeksville.util.exceptionReporter import com.geeksville.util.ignoreException import com.hoho.android.usbserial.driver.UsbSerialDriver import com.hoho.android.usbserial.driver.UsbSerialPort @@ -45,12 +50,67 @@ class SerialInterface(private val service: RadioInterfaceService, val address: S } } - private var uart: UsbSerialPort? = null + private var uart: UsbSerialDriver? = null private var ioManager: SerialInputOutputManager? = null - init { - val manager = service.getSystemService(Context.USB_SERVICE) as UsbManager + var usbReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) = exceptionReporter { + if (UsbManager.ACTION_USB_DEVICE_DETACHED == intent.action) { + debug("A USB device was detached") + val device: UsbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)!! + if (uart?.device == device) + onDeviceDisconnect() + } + + if (UsbManager.ACTION_USB_DEVICE_ATTACHED == intent.action) { + debug("attaching USB") + val device: UsbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)!! + val manager = context.getSystemService(Context.USB_SERVICE) as UsbManager + if (manager.hasPermission(device)) { + // reinit the port from scratch and reopen + onDeviceDisconnect() + connect() + } else { + warn("We don't have permissions for this USB device") + } + } + } + } + + init { + val filter = IntentFilter() + filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED) + filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED) + service.registerReceiver(usbReceiver, filter) + + connect() + } + + override fun close() { + debug("Closing serial port for good") + service.unregisterReceiver(usbReceiver) + onDeviceDisconnect() + } + + /** Tell MeshService our device has gone away, but wait for it to come back */ + fun onDeviceDisconnect() { + debug("USB device disconnected, but it might come back") + + ignoreException { ioManager?.let { it.stop() } } + ioManager = null + ignoreException { + uart?.apply { + ports[0].close() // This will cause the reader thread to exit + } + } + uart = null + + service.onDisconnect(isPermanent = true) // if USB device disconnects it is definitely permantently gone, not sleeping) + } + + private fun connect() { + val manager = service.getSystemService(Context.USB_SERVICE) as UsbManager val device = findSerial(service, address) if (device != null) { @@ -65,7 +125,7 @@ class SerialInterface(private val service: RadioInterfaceService, val address: S connection port.open(connection) port.setParameters(921600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE) - uart = port + uart = device debug("Starting serial reader thread") val io = SerialInputOutputManager(port, this) @@ -167,15 +227,6 @@ class SerialInterface(private val service: RadioInterfaceService, val address: S ptr = nextPtr } - override fun close() { - debug("Closing serial port") - ignoreException { ioManager?.let { it.stop() } } - ioManager = null - ignoreException { - uart?.close() // This will cause the reader thread to exit - } - uart = null - } /** * Called when [SerialInputOutputManager.run] aborts due to an error. @@ -184,7 +235,7 @@ class SerialInterface(private val service: RadioInterfaceService, val address: S errormsg("Serial error: $e") // FIXME - try to reconnect to the device when it comes back - service.onDisconnect(isPermanent = false) + onDeviceDisconnect() } /**