Fixed crash on start if Bluetooth is disabled (fixes #3).
This commit is contained in:
parent
748c8c27c5
commit
3baf87be3d
3 changed files with 45 additions and 19 deletions
|
@ -0,0 +1,20 @@
|
||||||
|
package com.nutomic.ensichat.bluetooth
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothAdapter
|
||||||
|
import android.os.Handler
|
||||||
|
import android.test.AndroidTestCase
|
||||||
|
|
||||||
|
class BluetoothInterfaceTest extends AndroidTestCase {
|
||||||
|
|
||||||
|
private lazy val adapter = new BluetoothInterface(getContext, new Handler(), Message => Unit,
|
||||||
|
() => Unit, Message => false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for issue [[https://github.com/Nutomic/ensichat/issues/3 #3]].
|
||||||
|
*/
|
||||||
|
def testStartBluetoothOff(): Unit = {
|
||||||
|
BluetoothAdapter.getDefaultAdapter.disable()
|
||||||
|
adapter.create()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -28,19 +28,23 @@ object BluetoothInterface {
|
||||||
/**
|
/**
|
||||||
* Handles all Bluetooth connectivity.
|
* Handles all Bluetooth connectivity.
|
||||||
*/
|
*/
|
||||||
class BluetoothInterface(service: ChatService, crypto: Crypto, mainHandler: Handler)
|
class BluetoothInterface(context: Context, mainHandler: Handler,
|
||||||
|
onMessageReceived: Message => Unit, callConnectionListeners: () => Unit,
|
||||||
|
onConnectionOpened: (Message) => Boolean)
|
||||||
extends InterfaceHandler {
|
extends InterfaceHandler {
|
||||||
|
|
||||||
private val Tag = "BluetoothInterface"
|
private val Tag = "BluetoothInterface"
|
||||||
|
|
||||||
private lazy val btAdapter = BluetoothAdapter.getDefaultAdapter
|
private lazy val btAdapter = BluetoothAdapter.getDefaultAdapter
|
||||||
|
|
||||||
|
private lazy val crypto = new Crypto(context)
|
||||||
|
|
||||||
private var devices = new HashMap[Device.ID, Device]()
|
private var devices = new HashMap[Device.ID, Device]()
|
||||||
|
|
||||||
private var connections = new HashMap[Device.ID, TransferThread]()
|
private var connections = new HashMap[Device.ID, TransferThread]()
|
||||||
|
|
||||||
private lazy val listenThread =
|
private lazy val listenThread =
|
||||||
new ListenThread(service.getString(R.string.app_name), btAdapter, onConnectionOpened)
|
new ListenThread(context.getString(R.string.app_name), btAdapter, connectionOpened)
|
||||||
|
|
||||||
private var cancelDiscovery = false
|
private var cancelDiscovery = false
|
||||||
|
|
||||||
|
@ -52,13 +56,15 @@ class BluetoothInterface(service: ChatService, crypto: Crypto, mainHandler: Hand
|
||||||
* Initializes and starts discovery and listening.
|
* Initializes and starts discovery and listening.
|
||||||
*/
|
*/
|
||||||
override def create(): Unit = {
|
override def create(): Unit = {
|
||||||
service.registerReceiver(DeviceDiscoveredReceiver,
|
context.registerReceiver(DeviceDiscoveredReceiver,
|
||||||
new IntentFilter(BluetoothDevice.ACTION_FOUND))
|
new IntentFilter(BluetoothDevice.ACTION_FOUND))
|
||||||
service.registerReceiver(BluetoothStateReceiver,
|
context.registerReceiver(BluetoothStateReceiver,
|
||||||
new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED))
|
new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED))
|
||||||
service.registerReceiver(DiscoveryFinishedReceiver,
|
context.registerReceiver(DiscoveryFinishedReceiver,
|
||||||
new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED))
|
new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED))
|
||||||
startBluetoothConnections()
|
// Otherwise, connections are started in [[BluetoothStateReceiver]].
|
||||||
|
if (btAdapter.isEnabled)
|
||||||
|
startBluetoothConnections()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,9 +73,9 @@ class BluetoothInterface(service: ChatService, crypto: Crypto, mainHandler: Hand
|
||||||
override def destroy(): Unit = {
|
override def destroy(): Unit = {
|
||||||
listenThread.cancel()
|
listenThread.cancel()
|
||||||
cancelDiscovery = true
|
cancelDiscovery = true
|
||||||
service.unregisterReceiver(DeviceDiscoveredReceiver)
|
context.unregisterReceiver(DeviceDiscoveredReceiver)
|
||||||
service.unregisterReceiver(BluetoothStateReceiver)
|
context.unregisterReceiver(BluetoothStateReceiver)
|
||||||
service.unregisterReceiver(DiscoveryFinishedReceiver)
|
context.unregisterReceiver(DiscoveryFinishedReceiver)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -93,9 +99,9 @@ class BluetoothInterface(service: ChatService, crypto: Crypto, mainHandler: Hand
|
||||||
btAdapter.startDiscovery()
|
btAdapter.startDiscovery()
|
||||||
}
|
}
|
||||||
|
|
||||||
val pm = PreferenceManager.getDefaultSharedPreferences(service)
|
val pm = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
val scanInterval = pm.getString(SettingsFragment.KeyScanInterval,
|
val scanInterval = pm.getString(SettingsFragment.KeyScanInterval,
|
||||||
service.getResources.getString(R.string.default_scan_interval)).toInt * 1000
|
context.getResources.getString(R.string.default_scan_interval)).toInt * 1000
|
||||||
mainHandler.postDelayed(new Runnable {
|
mainHandler.postDelayed(new Runnable {
|
||||||
override def run(): Unit = discover()
|
override def run(): Unit = discover()
|
||||||
}, scanInterval)
|
}, scanInterval)
|
||||||
|
@ -117,7 +123,7 @@ class BluetoothInterface(service: ChatService, crypto: Crypto, mainHandler: Hand
|
||||||
override def onReceive(context: Context, intent: Intent): Unit = {
|
override def onReceive(context: Context, intent: Intent): Unit = {
|
||||||
discovered.filterNot(d => connections.keySet.contains(d.id))
|
discovered.filterNot(d => connections.keySet.contains(d.id))
|
||||||
.foreach { d =>
|
.foreach { d =>
|
||||||
new ConnectThread(d, onConnectionOpened).start()
|
new ConnectThread(d, connectionOpened).start()
|
||||||
devices += (d.id -> d)
|
devices += (d.id -> d)
|
||||||
}
|
}
|
||||||
discovered = Set[Device]()
|
discovered = Set[Device]()
|
||||||
|
@ -131,8 +137,7 @@ class BluetoothInterface(service: ChatService, crypto: Crypto, mainHandler: Hand
|
||||||
override def onReceive(context: Context, intent: Intent): Unit = {
|
override def onReceive(context: Context, intent: Intent): Unit = {
|
||||||
intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) match {
|
intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) match {
|
||||||
case BluetoothAdapter.STATE_ON =>
|
case BluetoothAdapter.STATE_ON =>
|
||||||
if (crypto.localKeysExist)
|
startBluetoothConnections()
|
||||||
startBluetoothConnections()
|
|
||||||
case BluetoothAdapter.STATE_TURNING_OFF =>
|
case BluetoothAdapter.STATE_TURNING_OFF =>
|
||||||
Log.i(Tag, "Bluetooth disabled, stopping connectivity")
|
Log.i(Tag, "Bluetooth disabled, stopping connectivity")
|
||||||
listenThread.cancel()
|
listenThread.cancel()
|
||||||
|
@ -147,7 +152,7 @@ class BluetoothInterface(service: ChatService, crypto: Crypto, mainHandler: Hand
|
||||||
/**
|
/**
|
||||||
* Initiates data transfer with device.
|
* Initiates data transfer with device.
|
||||||
*/
|
*/
|
||||||
def onConnectionOpened(device: Device, socket: BluetoothSocket): Unit = {
|
def connectionOpened(device: Device, socket: BluetoothSocket): Unit = {
|
||||||
devices += (device.id -> device)
|
devices += (device.id -> device)
|
||||||
connections += (device.id ->
|
connections += (device.id ->
|
||||||
new TransferThread(device, socket, this, crypto, onReceiveMessage))
|
new TransferThread(device, socket, this, crypto, onReceiveMessage))
|
||||||
|
@ -160,7 +165,7 @@ class BluetoothInterface(service: ChatService, crypto: Crypto, mainHandler: Hand
|
||||||
def onConnectionClosed(device: Device, socket: BluetoothSocket): Unit = {
|
def onConnectionClosed(device: Device, socket: BluetoothSocket): Unit = {
|
||||||
devices -= device.id
|
devices -= device.id
|
||||||
connections -= device.id
|
connections -= device.id
|
||||||
service.callConnectionListeners()
|
callConnectionListeners()
|
||||||
addressDeviceMap.inverse().remove(device.id)
|
addressDeviceMap.inverse().remove(device.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,10 +182,10 @@ class BluetoothInterface(service: ChatService, crypto: Crypto, mainHandler: Hand
|
||||||
val address = crypto.calculateAddress(info.key)
|
val address = crypto.calculateAddress(info.key)
|
||||||
// Service.onConnectionOpened sends message, so mapping already needs to be in place.
|
// Service.onConnectionOpened sends message, so mapping already needs to be in place.
|
||||||
addressDeviceMap.put(address, device)
|
addressDeviceMap.put(address, device)
|
||||||
if (!service.onConnectionOpened(msg))
|
if (!onConnectionOpened(msg))
|
||||||
addressDeviceMap.remove(address)
|
addressDeviceMap.remove(address)
|
||||||
case _ =>
|
case _ =>
|
||||||
service.onMessageReceived(msg)
|
onMessageReceived(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -59,7 +59,8 @@ class ChatService extends Service {
|
||||||
|
|
||||||
private lazy val crypto = new Crypto(this)
|
private lazy val crypto = new Crypto(this)
|
||||||
|
|
||||||
private lazy val btInterface = new BluetoothInterface(this, crypto, mainHandler)
|
private lazy val btInterface = new BluetoothInterface(this, mainHandler,
|
||||||
|
onMessageReceived, callConnectionListeners, onConnectionOpened)
|
||||||
|
|
||||||
private lazy val router = new Router(connections, sendVia)
|
private lazy val router = new Router(connections, sendVia)
|
||||||
|
|
||||||
|
|
Reference in a new issue