Delete BluetoothService.kt
parent
754c77fc3d
commit
a2b5112b7b
@ -1,525 +0,0 @@
|
|||||||
package com.rookiedev.hexapod.network
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.bluetooth.*
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.os.Handler
|
|
||||||
import java.io.IOException
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.io.OutputStream
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class does all the work for setting up and managing Bluetooth
|
|
||||||
* connections with other devices. It has a thread that listens for
|
|
||||||
* incoming connections, a thread for connecting with a device, and a
|
|
||||||
* thread for performing data transmissions when connected.
|
|
||||||
*/
|
|
||||||
class BluetoothService(context: Context?) {
|
|
||||||
// Member fields
|
|
||||||
private var bluetoothManager: BluetoothManager? = null
|
|
||||||
private var mContext: Context? = null
|
|
||||||
// private val mAdapter: BluetoothAdapter
|
|
||||||
// private val mHandler: Handler
|
|
||||||
private var mSecureAcceptThread: AcceptThread? = null
|
|
||||||
private var mInsecureAcceptThread: AcceptThread? = null
|
|
||||||
private var mConnectThread: ConnectThread? = null
|
|
||||||
private var mConnectedThread: ConnectedThread? = null
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the current connection state.
|
|
||||||
*/
|
|
||||||
@get:Synchronized
|
|
||||||
var mState: Int
|
|
||||||
private set
|
|
||||||
private var mNewState: Int
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update UI title according to the current state of the chat connection
|
|
||||||
*/
|
|
||||||
@Synchronized
|
|
||||||
private fun updateUserInterfaceTitle() {
|
|
||||||
mState = mState
|
|
||||||
// Log.d(TAG, "updateUserInterfaceTitle() " + mNewState + " -> " + state)
|
|
||||||
mNewState = mState
|
|
||||||
|
|
||||||
// Give the new state to the Handler so the UI Activity can update
|
|
||||||
// mHandler.obtainMessage(Constants.MESSAGE_STATE_CHANGE, mNewState, -1).sendToTarget()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the chat service. Specifically start AcceptThread to begin a
|
|
||||||
* session in listening (server) mode. Called by the Activity onResume()
|
|
||||||
*/
|
|
||||||
@Synchronized
|
|
||||||
fun start() {
|
|
||||||
// Log.d(TAG, "start")
|
|
||||||
|
|
||||||
// Cancel any thread attempting to make a connection
|
|
||||||
if (mConnectThread != null) {
|
|
||||||
mConnectThread!!.cancel()
|
|
||||||
mConnectThread = null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cancel any thread currently running a connection
|
|
||||||
if (mConnectedThread != null) {
|
|
||||||
mConnectedThread!!.cancel()
|
|
||||||
mConnectedThread = null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the thread to listen on a BluetoothServerSocket
|
|
||||||
if (mSecureAcceptThread == null) {
|
|
||||||
mSecureAcceptThread = AcceptThread(true)
|
|
||||||
mSecureAcceptThread!!.start()
|
|
||||||
}
|
|
||||||
if (mInsecureAcceptThread == null) {
|
|
||||||
mInsecureAcceptThread = AcceptThread(false)
|
|
||||||
mInsecureAcceptThread!!.start()
|
|
||||||
}
|
|
||||||
// Update UI title
|
|
||||||
updateUserInterfaceTitle()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the ConnectThread to initiate a connection to a remote device.
|
|
||||||
*
|
|
||||||
* @param device The BluetoothDevice to connect
|
|
||||||
* @param secure Socket Security type - Secure (true) , Insecure (false)
|
|
||||||
*/
|
|
||||||
@Synchronized
|
|
||||||
fun connect(device: BluetoothDevice, secure: Boolean) {
|
|
||||||
// Log.d(TAG, "connect to: $device")
|
|
||||||
|
|
||||||
// Cancel any thread attempting to make a connection
|
|
||||||
if (mState == STATE_CONNECTING) {
|
|
||||||
if (mConnectThread != null) {
|
|
||||||
mConnectThread!!.cancel()
|
|
||||||
mConnectThread = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cancel any thread currently running a connection
|
|
||||||
if (mConnectedThread != null) {
|
|
||||||
mConnectedThread!!.cancel()
|
|
||||||
mConnectedThread = null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the thread to connect with the given device
|
|
||||||
mConnectThread = ConnectThread(device, secure)
|
|
||||||
mConnectThread!!.start()
|
|
||||||
// Update UI title
|
|
||||||
updateUserInterfaceTitle()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the ConnectedThread to begin managing a Bluetooth connection
|
|
||||||
*
|
|
||||||
* @param socket The BluetoothSocket on which the connection was made
|
|
||||||
* @param device The BluetoothDevice that has been connected
|
|
||||||
*/
|
|
||||||
@SuppressLint("MissingPermission")
|
|
||||||
@Synchronized
|
|
||||||
fun connected(socket: BluetoothSocket?, device: BluetoothDevice, socketType: String) {
|
|
||||||
// Log.d(TAG, "connected, Socket Type:$socketType")
|
|
||||||
|
|
||||||
// Cancel the thread that completed the connection
|
|
||||||
if (mConnectThread != null) {
|
|
||||||
mConnectThread!!.cancel()
|
|
||||||
mConnectThread = null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cancel any thread currently running a connection
|
|
||||||
if (mConnectedThread != null) {
|
|
||||||
mConnectedThread!!.cancel()
|
|
||||||
mConnectedThread = null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cancel the accept thread because we only want to connect to one device
|
|
||||||
if (mSecureAcceptThread != null) {
|
|
||||||
mSecureAcceptThread!!.cancel()
|
|
||||||
mSecureAcceptThread = null
|
|
||||||
}
|
|
||||||
if (mInsecureAcceptThread != null) {
|
|
||||||
mInsecureAcceptThread!!.cancel()
|
|
||||||
mInsecureAcceptThread = null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the thread to manage the connection and perform transmissions
|
|
||||||
mConnectedThread = ConnectedThread(socket, socketType)
|
|
||||||
mConnectedThread!!.start()
|
|
||||||
|
|
||||||
// Send the name of the connected device back to the UI Activity
|
|
||||||
// val msg = mHandler.obtainMessage(Constants.MESSAGE_DEVICE_NAME)
|
|
||||||
val bundle = Bundle()
|
|
||||||
bundle.putString(Constants.DEVICE_NAME, device.name)
|
|
||||||
// msg.data = bundle
|
|
||||||
// mHandler.sendMessage(msg)
|
|
||||||
// Update UI title
|
|
||||||
updateUserInterfaceTitle()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop all threads
|
|
||||||
*/
|
|
||||||
@Synchronized
|
|
||||||
fun stop() {
|
|
||||||
// Log.d(TAG, "stop")
|
|
||||||
if (mConnectThread != null) {
|
|
||||||
mConnectThread!!.cancel()
|
|
||||||
mConnectThread = null
|
|
||||||
}
|
|
||||||
if (mConnectedThread != null) {
|
|
||||||
mConnectedThread!!.cancel()
|
|
||||||
mConnectedThread = null
|
|
||||||
}
|
|
||||||
if (mSecureAcceptThread != null) {
|
|
||||||
mSecureAcceptThread!!.cancel()
|
|
||||||
mSecureAcceptThread = null
|
|
||||||
}
|
|
||||||
if (mInsecureAcceptThread != null) {
|
|
||||||
mInsecureAcceptThread!!.cancel()
|
|
||||||
mInsecureAcceptThread = null
|
|
||||||
}
|
|
||||||
mState = STATE_NONE
|
|
||||||
// Update UI title
|
|
||||||
updateUserInterfaceTitle()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write to the ConnectedThread in an unsynchronized manner
|
|
||||||
*
|
|
||||||
* @param out The bytes to write
|
|
||||||
* @see ConnectedThread.write
|
|
||||||
*/
|
|
||||||
fun write(out: ByteArray?) {
|
|
||||||
// Create temporary object
|
|
||||||
var r: ConnectedThread?
|
|
||||||
// Synchronize a copy of the ConnectedThread
|
|
||||||
synchronized(this) {
|
|
||||||
if (mState != STATE_CONNECTED) return
|
|
||||||
r = mConnectedThread
|
|
||||||
}
|
|
||||||
// Perform the write unsynchronized
|
|
||||||
r!!.write(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicate that the connection attempt failed and notify the UI Activity.
|
|
||||||
*/
|
|
||||||
private fun connectionFailed() {
|
|
||||||
// Send a failure message back to the Activity
|
|
||||||
// val msg = mHandler.obtainMessage(Constants.MESSAGE_TOAST)
|
|
||||||
val bundle = Bundle()
|
|
||||||
bundle.putString(Constants.TOAST, "Unable to connect device")
|
|
||||||
// msg.data = bundle
|
|
||||||
// mHandler.sendMessage(msg)
|
|
||||||
mState = STATE_NONE
|
|
||||||
// Update UI title
|
|
||||||
updateUserInterfaceTitle()
|
|
||||||
|
|
||||||
// Start the service over to restart listening mode
|
|
||||||
start()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicate that the connection was lost and notify the UI Activity.
|
|
||||||
*/
|
|
||||||
private fun connectionLost() {
|
|
||||||
// Send a failure message back to the Activity
|
|
||||||
// val msg = mHandler.obtainMessage(Constants.MESSAGE_TOAST)
|
|
||||||
val bundle = Bundle()
|
|
||||||
bundle.putString(Constants.TOAST, "Device connection was lost")
|
|
||||||
// msg.data = bundle
|
|
||||||
// mHandler.sendMessage(msg)
|
|
||||||
mState = STATE_NONE
|
|
||||||
// Update UI title
|
|
||||||
updateUserInterfaceTitle()
|
|
||||||
|
|
||||||
// Start the service over to restart listening mode
|
|
||||||
start()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This thread runs while listening for incoming connections. It behaves
|
|
||||||
* like a server-side client. It runs until a connection is accepted
|
|
||||||
* (or until cancelled).
|
|
||||||
*/
|
|
||||||
@SuppressLint("MissingPermission")
|
|
||||||
private inner class AcceptThread(secure: Boolean) : Thread() {
|
|
||||||
// The local server socket
|
|
||||||
private val mmServerSocket: BluetoothServerSocket?
|
|
||||||
private val mSocketType: String
|
|
||||||
override fun run() {
|
|
||||||
// Log.d(
|
|
||||||
// TAG, "Socket Type: " + mSocketType +
|
|
||||||
// "BEGIN mAcceptThread" + this
|
|
||||||
// )
|
|
||||||
name = "AcceptThread$mSocketType"
|
|
||||||
var socket: BluetoothSocket?
|
|
||||||
|
|
||||||
// Listen to the server socket if we're not connected
|
|
||||||
while (mState != STATE_CONNECTED) {
|
|
||||||
socket = try {
|
|
||||||
// This is a blocking call and will only return on a
|
|
||||||
// successful connection or an exception
|
|
||||||
mmServerSocket!!.accept()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
// Log.e(TAG, "Socket Type: " + mSocketType + "accept() failed", e)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a connection was accepted
|
|
||||||
if (socket != null) {
|
|
||||||
synchronized(this@BluetoothService) {
|
|
||||||
when (mState) {
|
|
||||||
STATE_LISTEN, STATE_CONNECTING -> // Situation normal. Start the connected thread.
|
|
||||||
connected(
|
|
||||||
socket, socket.remoteDevice,
|
|
||||||
mSocketType
|
|
||||||
)
|
|
||||||
STATE_NONE, STATE_CONNECTED -> // Either not ready or already connected. Terminate new socket.
|
|
||||||
try {
|
|
||||||
socket.close()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
// Log.e(
|
|
||||||
// TAG,
|
|
||||||
// "Could not close unwanted socket",
|
|
||||||
// e
|
|
||||||
// )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Log.i(
|
|
||||||
// TAG,
|
|
||||||
// "END mAcceptThread, socket Type: $mSocketType"
|
|
||||||
// )
|
|
||||||
}
|
|
||||||
|
|
||||||
fun cancel() {
|
|
||||||
// Log.d(TAG, "Socket Type" + mSocketType + "cancel " + this)
|
|
||||||
try {
|
|
||||||
mmServerSocket!!.close()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
// Log.e(TAG, "Socket Type" + mSocketType + "close() of server failed", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
var tmp: BluetoothServerSocket? = null
|
|
||||||
mSocketType = if (secure) "Secure" else "Insecure"
|
|
||||||
|
|
||||||
// Create a new listening server socket
|
|
||||||
try {
|
|
||||||
tmp = if (secure) {
|
|
||||||
bluetoothManager!!.adapter.listenUsingRfcommWithServiceRecord(
|
|
||||||
NAME_SECURE,
|
|
||||||
MY_UUID_SECURE
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
bluetoothManager!!.adapter.listenUsingInsecureRfcommWithServiceRecord(
|
|
||||||
NAME_INSECURE, MY_UUID_INSECURE
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} catch (e: IOException) {
|
|
||||||
// Log.e(TAG, "Socket Type: " + mSocketType + "listen() failed", e)
|
|
||||||
}
|
|
||||||
mmServerSocket = tmp
|
|
||||||
mState = STATE_LISTEN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This thread runs while attempting to make an outgoing connection
|
|
||||||
* with a device. It runs straight through; the connection either
|
|
||||||
* succeeds or fails.
|
|
||||||
*/
|
|
||||||
@SuppressLint("MissingPermission")
|
|
||||||
private inner class ConnectThread(private val mmDevice: BluetoothDevice, secure: Boolean) :
|
|
||||||
Thread() {
|
|
||||||
private val mmSocket: BluetoothSocket?
|
|
||||||
private val mSocketType: String
|
|
||||||
override fun run() {
|
|
||||||
// Log.i(
|
|
||||||
// TAG,
|
|
||||||
// "BEGIN mConnectThread SocketType:$mSocketType"
|
|
||||||
// )
|
|
||||||
name = "ConnectThread$mSocketType"
|
|
||||||
|
|
||||||
// Always cancel discovery because it will slow down a connection
|
|
||||||
bluetoothManager!!.adapter.cancelDiscovery()
|
|
||||||
|
|
||||||
// Make a connection to the BluetoothSocket
|
|
||||||
try {
|
|
||||||
// This is a blocking call and will only return on a
|
|
||||||
// successful connection or an exception
|
|
||||||
mmSocket!!.connect()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
// Close the socket
|
|
||||||
try {
|
|
||||||
mmSocket!!.close()
|
|
||||||
} catch (e2: IOException) {
|
|
||||||
// Log.e(
|
|
||||||
// TAG, "unable to close() " + mSocketType +
|
|
||||||
// " socket during connection failure", e2
|
|
||||||
// )
|
|
||||||
}
|
|
||||||
connectionFailed()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset the ConnectThread because we're done
|
|
||||||
synchronized(this@BluetoothService) { mConnectThread = null }
|
|
||||||
|
|
||||||
// Start the connected thread
|
|
||||||
connected(mmSocket, mmDevice, mSocketType)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun cancel() {
|
|
||||||
try {
|
|
||||||
mmSocket!!.close()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
// Log.e(
|
|
||||||
// TAG,
|
|
||||||
// "close() of connect $mSocketType socket failed", e
|
|
||||||
// )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
var tmp: BluetoothSocket? = null
|
|
||||||
mSocketType = if (secure) "Secure" else "Insecure"
|
|
||||||
|
|
||||||
// Get a BluetoothSocket for a connection with the
|
|
||||||
// given BluetoothDevice
|
|
||||||
try {
|
|
||||||
tmp = if (secure) {
|
|
||||||
mmDevice.createRfcommSocketToServiceRecord(
|
|
||||||
MY_UUID_SECURE
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
mmDevice.createInsecureRfcommSocketToServiceRecord(
|
|
||||||
MY_UUID_INSECURE
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} catch (e: IOException) {
|
|
||||||
// Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e)
|
|
||||||
}
|
|
||||||
mmSocket = tmp
|
|
||||||
mState = STATE_CONNECTING
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This thread runs during a connection with a remote device.
|
|
||||||
* It handles all incoming and outgoing transmissions.
|
|
||||||
*/
|
|
||||||
private inner class ConnectedThread(socket: BluetoothSocket?, socketType: String) :
|
|
||||||
Thread() {
|
|
||||||
private val mmSocket: BluetoothSocket? = socket
|
|
||||||
private val mmInStream: InputStream?
|
|
||||||
private val mmOutStream: OutputStream?
|
|
||||||
override fun run() {
|
|
||||||
// Log.i(TAG, "BEGIN mConnectedThread")
|
|
||||||
val buffer = ByteArray(1024)
|
|
||||||
var bytes: Int
|
|
||||||
|
|
||||||
// Keep listening to the InputStream while connected
|
|
||||||
while (mState == STATE_CONNECTED) {
|
|
||||||
try {
|
|
||||||
// Read from the InputStream
|
|
||||||
bytes = mmInStream!!.read(buffer)
|
|
||||||
|
|
||||||
// Send the obtained bytes to the UI Activity
|
|
||||||
// mHandler.obtainMessage(Constants.MESSAGE_READ, bytes, -1, buffer)
|
|
||||||
// .sendToTarget()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
// Log.e(TAG, "disconnected", e)
|
|
||||||
connectionLost()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write to the connected OutStream.
|
|
||||||
*
|
|
||||||
* @param buffer The bytes to write
|
|
||||||
*/
|
|
||||||
fun write(buffer: ByteArray?) {
|
|
||||||
try {
|
|
||||||
mmOutStream!!.write(buffer)
|
|
||||||
|
|
||||||
// Share the sent message back to the UI Activity
|
|
||||||
// mHandler.obtainMessage(Constants.MESSAGE_WRITE, -1, -1, buffer)
|
|
||||||
// .sendToTarget()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
// Log.e(TAG, "Exception during write", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun cancel() {
|
|
||||||
try {
|
|
||||||
mmSocket!!.close()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
// Log.e(TAG, "close() of connect socket failed", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
// Log.d(TAG, "create ConnectedThread: $socketType")
|
|
||||||
var tmpIn: InputStream? = null
|
|
||||||
var tmpOut: OutputStream? = null
|
|
||||||
|
|
||||||
// Get the BluetoothSocket input and output streams
|
|
||||||
try {
|
|
||||||
tmpIn = socket!!.inputStream
|
|
||||||
tmpOut = socket.outputStream
|
|
||||||
} catch (e: IOException) {
|
|
||||||
// Log.e(TAG, "temp sockets not created", e)
|
|
||||||
}
|
|
||||||
mmInStream = tmpIn
|
|
||||||
mmOutStream = tmpOut
|
|
||||||
mState = STATE_CONNECTED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
// Debugging
|
|
||||||
private const val TAG = "BluetoothChatService"
|
|
||||||
|
|
||||||
// Name for the SDP record when creating server socket
|
|
||||||
private const val NAME_SECURE = "BluetoothChatSecure"
|
|
||||||
private const val NAME_INSECURE = "BluetoothChatInsecure"
|
|
||||||
|
|
||||||
// Unique UUID for this application
|
|
||||||
private val MY_UUID_SECURE = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66")
|
|
||||||
private val MY_UUID_INSECURE = UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66")
|
|
||||||
|
|
||||||
// Constants that indicate the current connection state
|
|
||||||
const val STATE_NONE = 0 // we're doing nothing
|
|
||||||
const val STATE_LISTEN = 1 // now listening for incoming connections
|
|
||||||
const val STATE_CONNECTING = 2 // now initiating an outgoing connection
|
|
||||||
const val STATE_CONNECTED = 3 // now connected to a remote device
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor. Prepares a new BluetoothChat session.
|
|
||||||
*
|
|
||||||
* @param context The UI Activity Context
|
|
||||||
* @param handler A Handler to send messages back to the UI Activity
|
|
||||||
*/
|
|
||||||
init {
|
|
||||||
mContext = context
|
|
||||||
// mAdapter = BluetoothAdapter.getDefaultAdapter()
|
|
||||||
bluetoothManager =
|
|
||||||
mContext!!.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
|
|
||||||
bluetoothManager!!.adapter
|
|
||||||
mState = STATE_NONE
|
|
||||||
mNewState = mState
|
|
||||||
// mHandler = handler
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue