Use BroadcastReceiver to close connection.

This is needed when the connection is closed because one device
disabled its Bluetooth interface.
This commit is contained in:
Felix Ableitner 2015-09-11 14:01:45 +02:00
parent f695508fdd
commit c03d0d222e
4 changed files with 30 additions and 17 deletions

View file

@ -162,7 +162,7 @@ class BluetoothInterface(context: Context, mainHandler: Handler,
def connectionOpened(device: Device, socket: BluetoothSocket): Unit = {
devices += (device.id -> device)
connections += (device.id ->
new TransferThread(device, socket, this, crypto, onReceiveMessage))
new TransferThread(context, device, socket, this, crypto, onReceiveMessage))
connections(device.id).start()
}

View file

@ -13,7 +13,7 @@ class ConnectThread(device: Device, onConnected: (Device, BluetoothSocket) => Un
private val Tag = "ConnectThread"
private val socket =
device.bluetoothDevice.createInsecureRfcommSocketToServiceRecord(BluetoothInterface.AppUuid)
device.btDevice.get.createInsecureRfcommSocketToServiceRecord(BluetoothInterface.AppUuid)
override def run(): Unit = {
Log.i(Tag, "Connecting to " + device.toString)
@ -32,7 +32,7 @@ class ConnectThread(device: Device, onConnected: (Device, BluetoothSocket) => Un
}
Log.i(Tag, "Successfully connected to device " + device.name)
onConnected(new Device(device.bluetoothDevice, true), socket)
onConnected(new Device(device.btDevice.get, true), socket)
}
}

View file

@ -29,6 +29,4 @@ private[bluetooth] case class Device(id: Device.ID, name: String, connected: Boo
this(new Device.ID(btDevice.getAddress), btDevice.getName, connected, Option(btDevice))
}
def bluetoothDevice = btDevice.get
}

View file

@ -2,7 +2,8 @@ package com.nutomic.ensichat.bluetooth
import java.io._
import android.bluetooth.BluetoothSocket
import android.bluetooth.{BluetoothDevice, BluetoothSocket}
import android.content.{IntentFilter, Intent, Context, BroadcastReceiver}
import android.util.Log
import com.nutomic.ensichat.protocol._
import com.nutomic.ensichat.protocol.body.ConnectionInfo
@ -16,12 +17,14 @@ import Message.ReadMessageException
* @param socket An open socket to the given device.
* @param onReceive Called when a message was received from the other device.
*/
class TransferThread(device: Device, socket: BluetoothSocket, handler: BluetoothInterface,
class TransferThread(context: Context, device: Device, socket: BluetoothSocket, handler: BluetoothInterface,
crypto: Crypto, onReceive: (Message, Device.ID) => Unit) extends Thread {
private val Tag = "TransferThread"
val inStream: InputStream =
private var isClosed = false
private val inStream: InputStream =
try {
socket.getInputStream
} catch {
@ -30,7 +33,7 @@ class TransferThread(device: Device, socket: BluetoothSocket, handler: Bluetooth
null
}
val outStream: OutputStream =
private val outStream: OutputStream =
try {
socket.getOutputStream
} catch {
@ -39,19 +42,24 @@ class TransferThread(device: Device, socket: BluetoothSocket, handler: Bluetooth
null
}
private val disconnectReceiver = new BroadcastReceiver {
override def onReceive(context: Context, intent: Intent): Unit = {
val address = intent.getParcelableExtra[BluetoothDevice](BluetoothDevice.EXTRA_DEVICE).getAddress
if (device.btDevice.get.getAddress == address) {
Log.i(Tag, "Device with address " + address + " disconnected")
close()
}
}
}
override def run(): Unit = {
Log.i(Tag, "Starting data transfer with " + device.toString)
context.registerReceiver(disconnectReceiver,
new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED))
send(crypto.sign(new Message(new MessageHeader(ConnectionInfo.Type,
Address.Null, Address.Null, 0), new ConnectionInfo(crypto.getLocalPublicKey))))
// TODO: on disconnect (disable bluetooth):
// connection is never closed
// - no exception thrown
// - isConnected returning true
// -> step through, find alternative method/callback etc
// -> check source
// -> otherwise, need timeout?
while (socket.isConnected) {
try {
if (inStream.available() > 0) {
@ -80,13 +88,20 @@ class TransferThread(device: Device, socket: BluetoothSocket, handler: Bluetooth
}
def close(): Unit = {
if (isClosed)
return
isClosed = true
context.unregisterReceiver(disconnectReceiver)
try {
Log.i(Tag, "Closing connection to " + device)
inStream.close()
outStream.close()
socket.close()
} catch {
case e: IOException => Log.e(Tag, "Failed to close socket", e);
} finally {
handler.onConnectionClosed(new Device(device.bluetoothDevice, false), null)
handler.onConnectionClosed(new Device(device.btDevice.get, false), null)
}
}