Android Kotlin - How can I programmatically disconnect a bluetooth device? - android

Right now I have a code that connects the phone to a bluetooth printer, the problem is that I want to close that connection while not needing it, in other words I just want the device to connect to the printer when it needs to send a file and I want it to then disconnect.
To connect to the printer I'm using the following code:
fun connectBluetooth(address: String): Boolean {
var connectSuccess = true
try {
if (bluetoothSocket == null) {
val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
val device: BluetoothDevice = bluetoothAdapter!!.getRemoteDevice(address)
bluetoothSocket = device.createInsecureRfcommSocketToServiceRecord(myUUID)
bluetoothSocket!!.connect()
}
} catch (e: IOException) {
connectSuccess = false
e.printStackTrace()
}
return connectSuccess
}
I'm wondering how I can then close the connection, right now I have been simply doing
bluetoothSocket = null
but I highly doubt that is the right way to do it

Ok it wasn't as hard as I thought it would be, all that had to be done was to close the output stream that I was using in order to send the file to the printer.
I found out about this thanks to the link that was refered to me in the comments by vyas dipak: Disconnect a bluetooth socket in Android
All I did was create this small function and it all worked out well
fun disconnectBluetooth(){
val outputStream : OutputStream? = null
try {
outputStream?.close()
} catch (e: IOException ){}
try {
bluetoothSocket?.close()
} catch (e: IOException){}
bluetoothSocket = null
}

Related

Cannot connect to socket.io in android , saying invalid namespace

When i try to connect my android app with socket.io, it saying invalid namespace. There is no issue with socket url , but having problem in connection, please help if you faced this issue ever. Thanks!
val options = io.socket.client.IO.Options().apply {
forceNew = false
reconnection = true
}
private val socket: Socket = io.socket.client.IO.socket(socket_url,options)
val socket = applicationAccessorImpl.socket
socket.connect()
socket.once(Socket.EVENT_CONNECT) {
try {
Log.d(TAG, "connect")
} catch (e: Exception) {
Log.d(TAG, e.message!!)
}
}.on(Socket.EVENT_CONNECT_ERROR) {
val e = it[0]
Log.e(TAG, "error $e")
}.on(Socket.EVENT_DISCONNECT) {
val e = it[0]
Log.e(TAG, "Transport error $e")
}
Sorry , it was my mistake , i was passing the wrong url 😋

Android - Initiate Bluetooth Socket - connection timeout

I need to connect to a bluetooth device which acts as a server. I know its UUID (at least the device's documentation contains it). However, I get an exception when I try to connect to it. The discovery part takes place successfully.
In the following, I cite the relevant code parts.
Here is the discovery. After I successfully found my device, I try to connect to it.
private val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter()
private val bluetoothReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action: String = intent.action
when (action) {
BluetoothDevice.ACTION_FOUND -> {
val foundDevice: BluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
Log.i("NAME", foundDevice.name)
if (foundDevice.name.startsWith("RN487")) {
bluetoothAdapter?.cancelDiscovery()
device = foundDevice
val connectThread = ConnectThread(device)
connectThread.start()
}
}
}
}
}
private lateinit var device: BluetoothDevice
The ConnectThread class is here:
private inner class ConnectThread(device: BluetoothDevice) : Thread() {
private val mSocket: BluetoothSocket? by lazy(LazyThreadSafetyMode.NONE) {
device.createRfcommSocketToServiceRecord(UUID)
}
override fun run() {
bluetoothAdapter?.cancelDiscovery()
mSocket?.use { socket ->
socket.connect()
toast("Connected!")
}
}
fun cancel() {
try {
mSocket?.close()
} catch (e: IOException) {
Log.e(TAG, "Could not close the client socket", e)
}
}
}
The UUID was given as
private val UUID = nameUUIDFromBytes("49535343-...".toByteArray())
Thanks for your time and expertise!
As one of my eagle-eyed colleagues pointed out, the bluetooth description begins with the "oldschool" version on the official android developers site. Later, the bluetooth low energy is described, which I need for my project.

Android service can't connect to server after recreation only in battery saving mode

I'm writing a chat app with the server and Android client written in Kotlin. I create a background service that constantly reads from the socket connected to the server and sends notifications when a message arrives. Everything works fine until user taps 'x' button and closes the app. Connection with server fails during executing cleanUp code posted below. Server had gotten EOF before service managed to send EXIT request and close streams. Then, service is recreated but when it tries to connect to the server it gets ConnectException (connection refused). It happens only when battery saving mode is on. When it's off or phone is connected to my laptop with USB and charging there's no problem.
The ss command lists that there is someone listening on the specified port, so it's not that problem. I've tried to connect in a loop, i. e. try to connect 5 times every 10 seconds, but it got refused every time. I've tried listening on two different ports, but both failed even if one of them wasn't used before. Docs say that default backlog is 50, so I guess it's not that either. I tried to set a SO_REUSEADDR flag on the server socket, but still nothing. And the strange thing is, that when service is started from the app when I launch it for the second time it can connect again. So I've created a broadcast receiver that starts the service the same way as the app in case it crashes, but it's not helping either.
I really was googling it for over a week but it's my first attempt at using both Kotlin and sockets and I'm running out of ideas. If someone has a clue to what might be going on, I'd really appreciate some help.
Here is the service onStartCommand:
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
activeConversation = intent?.getStringExtra(CONV_NAME) ?: ""
login = intent?.getStringExtra(LOGIN) ?: login
if (thread?.isAlive != true) {
thread = thread(start = true) {
synchronized(lock) {
try {
socket = Socket(SERVER_IP, SERVICE_PORT)
output = ObjectOutputStream(socket?.getOutputStream())
input = ObjectInputStream(socket?.getInputStream())
output?.writeObject(Request(START_SERVICE, mutableMapOf(LOGIN to login)))
} catch (e: IOException) {
e.printStackTrace()
return#thread
}
}
handleMessages() //contains input?.readObject() in infinite loop
}
}
return START_STICKY
}
In onDestory() and onTaskRemoved() I call this function:
private fun cleanUp() {
synchronized(lock) {
thread(start = true) {
try {
output?.writeObject(Request(EXIT, mutableMapOf(LOGIN to login)))
output?.close()
input?.close()
socket?.close()
nullStreams()
thread?.join()
println("SERVICE: thread joined")
} catch(e: IOException) {
e.printStackTrace()
return#thread
} finally {
println("Service sends broadcast to ask for recreation")
val restartIntent = Intent(this, ServiceRestarter::class.java)
restartIntent.putExtra(LOGIN, login)
sendBroadcast(restartIntent)
}
}.join()
}
}
ServiceRestarter:
class ServiceRestarter : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) {
val login = intent?.getStringExtra(LOGIN)
println("SERVICE RESTARTER: receiving restart request from $login")
val serviceIntent = Intent(context, MessengerService::class.java)
serviceIntent.putExtra(LOGIN, login)
context.startService(serviceIntent)
}}
Part of my server responsible for listening:
val clientsSocket = ServerSocket(CLIENTS_PORT)
val serviceSocket = ServerSocket(SERVICE_PORT)
serviceSocket.setReuseAddress(true)
println("Server socket ready!")
println("Service socket port: ${serviceSocket.localPort}")
thread(start = true) {
while(true) ClientThread(clientsSocket.accept(), loggedInUsers, pendingRequests).start()
}
thread(start = true) {
while(true) ServiceThread(serviceSocket.accept(), loggedInUsers).start()
}
And ServiceThread:
class ServiceThread(val socket: Socket,
val loggedInUsers: HashMap<String, UserConnection>) : Thread() {
private var login = ""
private val input = ObjectInputStream(socket.getInputStream())
private val output = ObjectOutputStream(socket.getOutputStream())
override fun run() {
var request = input.readObject() as Request
login = request.content[LOGIN] as String
var userConn: UserConnection?
synchronized(loggedInUsers) {
userConn = loggedInUsers[login]
if(request.action == START_SERVICE) {
println("SERVICE THREAD: New socket conn from $login")
userConn?.run {
println("SERVICE THREAD: putting $login output to logged in users")
serviceStream = output
if(pendingMessage != null) {
output.writeObject(Request(SEND,
mutableMapOf(RESULT to SUCCESS, DATA to pendingMessage)))
pendingMessage = null
}
}
}
}
try { request = input.readObject() as Request }
catch(e: IOException) {
println(e.printStackTrace())
cleanUp()
return#run
}
if(request.action == EXIT) {
println("SERVICE THREAD: Service of user $login is terminating")
cleanUp()
}
}
private fun cleanUp() {
synchronized(loggedInUsers) {
output.close()
input.close()
socket.close()
loggedInUsers[login]?.serviceStream = null
}
}}

Not able to connect with bluetooth device with socket in android studio

Hello everyone I am new to android development i am connecting with bluetooth device as a client in different class thread. If Nullpointerexcception occur then i use default UUID. After this when i use socket.connect() it show debug warning and don't send any pair request to device. Nothing happen. I am new to android development if any one can help. Thank you in advance.
Warning and Logs
here is my code in Thread;
class ConnectWithDevice(context : ConnectWithBluetooth, device : BluetoothDevice) : Thread(){
private val mContext : ConnectWithBluetooth = context
private val mmSocket : BluetoothSocket
private val mmDevice : BluetoothDevice
// Default UUID
private val mmDefaultUUID = UUID.fromString("78c374fd-f84d-4a9e-aa5b-9b0b6292952e")
init {
var temp : BluetoothSocket? = null
mmDevice = device
try {
temp = device.createRfcommSocketToServiceRecord(mmDevice.uuids[0].uuid)
}catch (en : NullPointerException){
en.printStackTrace()
temp = device.createRfcommSocketToServiceRecord(mmDefaultUUID)
}catch (e : IOException){
e.printStackTrace()
Log.e("TAG","Socket's create() method failed",e)
}
mmSocket = temp!!
Log.i("TAG","Got the Socket")
}
override fun run() {
// Cancel discovery because it otherwise slows down the connection.
if(mContext.bluetoothAdapter != null){
mContext.bluetoothAdapter!!.cancelDiscovery()
}
try{
// Connect to the remote device through the socket. This call blocks
// until it succeeds or throws an exception.
Log.i("TAG","Connecting...")
mmSocket.connect()
Log.i("TAG","Bluetooth Successfully Connected")
}catch (connectException : IOException){
// Unable to connect; close the socket and return.
try{
mmSocket.close()
}catch (closeException : IOException){
Log.e("TAG","Could not close the client socket",closeException)
}
return
}
// The connection attempt succeeded. Perform work associated with
// the connection in a separate thread.
Log.i("TAG","Device is Connected")
//manageMyConnectedSocket(mmSocket)
}
// Closes the client socket and causes the thread to finish.
// Call this method from the main activity to shut down the connection.
fun cancel(){
try {
mmSocket.close()
} catch (e: IOException) {
Log.e(ContentValues.TAG, "Could not close the client socket", e)
}
}
}
Finally i find the solution here it is ->
I use this code ->
val m = device.javaClass.getMethod("createRfcommSocket", *arrayOf<Class<*>>(Int::class.java))
temp = m.invoke(device, 1) as BluetoothSocket
Instead of this ->
temp = device.createRfcommSocketToServiceRecord(mmDevice.uuids[0].uuid)

Bluetooth client Socket get same exception everytime

I am writing an Android app mostly in Kotlin that is supposed to scan for Bluetooth devices and also pair with them. I also want it to have a Bluetooth server socket running in the background to await connection attempts. However, I keep running into the same exception when attempting to invoke the BluetoothSocket.connect() method. The exception is:
10-10 20:07:57.917 18643-27894/com.example.zemcd.toofxchange E/Pairing Thread: error connecting
java.io.IOException: read failed, socket might closed or timeout, read ret: -1
at android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:754)
at android.bluetooth.BluetoothSocket.readInt(BluetoothSocket.java:766)
at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:388)
at com.example.zemcd.toofxchange.PairingThread.run(BluetoothUtils.kt:83)
I read that this could be fixed with code similar to
btSocket = device.javaClass.getMethod("createRFcommSocket", Int::class).invoke(device, 1) as BluetoothSocket
But this does not work. It causes the app to crash with a ReflectException caused by NoSuchMethod. Also I have read that this is not a published method for a reason and I would like to try to use the published createRFcommSocketToServiceRecord() method. I am unsure of where to go from here, or what exactly is causing the IOException. Also, I never even get to the pairing screen. I am trying to find what is the cause of this exception, and how to fix it. My code:
class BluetoothUtils {
companion object {
val _UUID = UUID.fromString("a0e7e4c7-0e4e-43b7-9d18-659192512164")
val TAG = "BluetoothUtils"
fun initPairingServer(adapter: BluetoothAdapter){
var mmServerSocket: BluetoothServerSocket? = null
try {
var tmp = adapter.listenUsingRfcommWithServiceRecord(TAG, _UUID)
mmServerSocket = tmp
ListenThread(mmServerSocket).start()
}catch (ioe: IOException){
Log.e(TAG, "Error initializing Bluetooth", ioe)
}
}
fun pair(adapter: BluetoothAdapter, device: BluetoothDevice){
var btSocket: BluetoothSocket? = null
try {
adapter.cancelDiscovery()
btSocket = device.createRfcommSocketToServiceRecord(_UUID)
PairingThread(btSocket).start()
}catch (ioe: IOException){
Log.e(TAG, "error connecting", ioe)
}
}
}
}
class ListenThread(val btServSock: BluetoothServerSocket) : Thread(){
companion object {
val TAG = "ListenThread"
}
var btSocket: BluetoothSocket? = null
override fun run() {
super.run()
while (true){
try {
Log.d(TAG, "listening . . . ")
btSocket = btServSock.accept()
}catch (ioe: IOException){
Log.e(TAG, "Error", ioe)
break
}
//manage connection here
//with either BluetoothUtils function
//or BluetoothSocket extension
}
}
}
class PairingThread(val btSocket: BluetoothSocket) : Thread(){
companion object {
val TAG = "Pairing Thread"
}
override fun run() {
super.run()
try {
Log.d(TAG, "attempting to connect")
btSocket.connect()
}catch (ioe: IOException){
Log.e(TAG, "error connecting", ioe)
btSocket.close()
}
}
}
Please somebody help me find my problem. Could it be that I'm attempting to connect to a device that isn't using the same UUID? I am just trying to connect to my laptop.

Categories

Resources