Thursday, 24 June 2021

Cannot open new bluetooth socket again

After closing bluetooth socket I'm trying to open the new one with the same way, but android tells me, the socket is closed.

This is my server thread for bluetooth conenction:

private inner class AcceptBLThread : Thread() {
        private val mmServerSocket: BluetoothServerSocket? by lazy {
            bluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord(
                connectionBLName,
                UUID.fromString(connectionUUID)
            )
        }

        override fun run() {
            // Keep listening until exception occurs or a socket is returned.
            isAwaitingForBLConnectionVal = true
            Log.i(tag, "Awaiting for BL connection")
            while (isAwaitingForBLConnectionVal) {
                val socket: BluetoothSocket? = try {
                    mmServerSocket?.accept()
                } catch (e: IOException) {
                    Log.e(tag, "Socket's accept() method failed", e)
                    isAwaitingForBLConnectionVal = false
                    null
                }
                socket?.also {
                    manageConnectedSocket(it)
                    mmServerSocket?.close()
                    isAwaitingForBLConnectionVal = false

                    if(settings.isSlaveIndoorMeasurementsEnabled) {
                        awaitForBLConnection()
                    }
                }
            }
        }

        // Closes the connect socket and causes the thread to finish.
        fun cancel() {
            try {
                mmServerSocket?.close()
                isBLMasterConnectedVal = false

                if(settings.isSlaveIndoorMeasurementsEnabled) {
                    awaitForBLConnection()
                }

                Log.i(tag, "Master device disconnected")
                Log.i(tag, "Closed server socket")
            } catch (e: IOException) {
                Log.e(tag, "Could not close the connect socket", e)
            }
        }

        @Suppress("MoveVariableDeclarationIntoWhen")
        private fun manageConnectedSocket(socket: BluetoothSocket) {
            isBLMasterConnectedVal = true

            val inStream = socket.inputStream
            val outStream = socket.outputStream
            val buffer = ByteArray(1024)
            var numBytes: Int

            if(socket.isConnected) {
                Log.i(tag, "Master device connected")
            } else {
                Log.i(tag, "Master device connect failure")
            }

            // Keep listening to the InputStream until an exception occurs.
            while (true) {
                // Read from the InputStream.
                numBytes = try {
                    inStream.read(buffer)
                } catch (e: IOException) {
                    Log.d(tag, "Input stream was disconnected", e)
                    break
                }
                if(numBytes == 1) {
                    val commandType = BluetoothCommands.from(buffer.toInt())
                    when(commandType) {
                        BluetoothCommands.START_INDOOR -> {

                        }
                        BluetoothCommands.STOP_INDOOR -> {

                        }
                        BluetoothCommands.SEND_DATA_TO_MASTER -> {

                        }
                        BluetoothCommands.ON_MASTER_DISCONNECTED -> {
                            Log.i(tag, "Master disconnected BL event")
                            Handler(Looper.getMainLooper()).postDelayed({
                                if(settings.isSlaveIndoorMeasurementsEnabled
                                    && !isAwaitingForBLConnectionVal) {
                                    awaitForBLConnection()
                                }
                            }, 1000)
                        }
                    }
                }
            }
        }
    }

This is my thread from client connection:

private inner class ConnectBLThread(
        val device: BluetoothDevice,
        val connectionCallback: BLCallback?
    ) : Thread() {
        private val socket: BluetoothSocket? by lazy(LazyThreadSafetyMode.NONE) {
            device.createRfcommSocketToServiceRecord(UUID.fromString(connectionUUID))
        }

        override fun run() {
            bluetoothAdapter.cancelDiscovery()

            socket?.let { socket ->
                try {
                    Log.i(tag, "Connecting to slave device")
                    // Connect to the remote device through the socket. This call blocks
                    // until it succeeds or throws an exception.
                    socket.connect()
                    // The connection attempt succeeded. Perform work associated with
                    // the connection in a separate thread.
                    manageConnectedSocket(socket)
                } catch (exc: Exception) {
                    Log.i(tag, "Connecting to slave device failed")
                    connectionCallback?.onConnectionError(device.address)
                }
            }
        }

        // Closes the client socket and causes the thread to finish.
        fun cancel() {
            try {
                socket?.outputStream?.write(
                    BluetoothCommands.ON_MASTER_DISCONNECTED.value.toByteArray()
                )
                Handler(Looper.getMainLooper()).postDelayed({
                    socket?.close()
                    connectionCallback?.onDisconnected(device.address)
                },500)
            } catch (e: IOException) {
                Log.e(tag, "Could not close the client socket", e)
            }
        }

        private fun manageConnectedSocket(socket: BluetoothSocket) {
            Log.i(tag, "Connected to slave device successfully")
            slaveSockets[device.address] = socket
            connectionCallback?.onConnectedSuccessfully()
        }
    }

I want to have checkbox when I'm connecting to device, or when not. But after unchecking this checkbox I cannot connect again. I'm calling "cancel()" method in ConnectBLThread, it's calling

socket?.also {
                    manageConnectedSocket(it)
                    mmServerSocket?.close()
                    isAwaitingForBLConnectionVal = false

                    if(settings.isSlaveIndoorMeasurementsEnabled) {
                        awaitForBLConnection()
                    }
                }

in AcceptBLThread with mmServerSocket?.close() and then I'm trying to connect again. Starting ConnectBLThread and it's give me socket, and it's even say that it's connected but closed. How to create new socket with the same UUID after previous close? Or I shouldn't close the socket at all, cause create new will be impossible?



from Cannot open new bluetooth socket again

No comments:

Post a Comment