buildgradle : 4.1.0
Bluetooth connection fails. IOException occurs and IOException: read failed, socket might closed - Bluetooth on Android 4.3 I referred.
The code referenced is related to fallback and is similar to the first and second answers. However, the Bluetooth connection still fails. The following code relates to Bluetooth search, pairing and connection. The ConnectToDevice class at the bottom of the code is the core of Bluetooth connection code. An error occurs in the .connect part here. The device, a parameter for the class, passes MAC addresses.
This is the Bluetooth-related code, TemporaryActivity.kt
package com.example.arduino
import android.Manifest
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.app.ProgressDialog
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothSocket
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanResult
import android.content.ContentValues.TAG
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.*
import android.util.Log
import android.view.View
import android.widget.*
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import java.io.IOException
import java.util.*
import kotlin.collections.ArrayList
class TemporaryActivity : AppCompatActivity() {
companion object {
var myUUID: UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")
lateinit var m_progress: ProgressDialog
var m_isConnected : Boolean = false
}
private val REQUEST_ENABLE_BT=1
private val REQUEST_ALL_PERMISSION= 2
private val PERMISSIONS = arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION
)
private var bluetoothAdapter: BluetoothAdapter? = null
private var bluetoothSocket: BluetoothSocket? = null
private var scanning: Boolean = false
lateinit var deviceName: BluetoothDevice
var clickcheck: Boolean = false
private var devicesArr = ArrayList<BluetoothDevice>()
private val SCAN_PERIOD = 1000
private val handler = Handler()
private lateinit var viewManager: RecyclerView.LayoutManager
private lateinit var recyclerViewAdapter : RecyclerAdapter
private val mLeScanCallback = @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
object : ScanCallback() {
override fun onScanFailed(errorCode: Int) {
super.onScanFailed(errorCode)
Log.d("scanCallback", "BLE Scan Failed : " + errorCode)
}
override fun onBatchScanResults(results: MutableList<ScanResult>?) {
super.onBatchScanResults(results)
results?.let{
// results is not null
for (result in it){
if (!devicesArr.contains(result.device) && result.device.name!=null) devicesArr.add(result.device)
}
}
}
override fun onScanResult(callbackType: Int, result: ScanResult?) {
super.onScanResult(callbackType, result)
result?.let {
// result is not null
if (!devicesArr.contains(it.device) && it.device.name!=null) devicesArr.add(it.device)
recyclerViewAdapter.notifyDataSetChanged()
}
}
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun scanDevice(state:Boolean) = if(state){
handler.postDelayed({
scanning = false
bluetoothAdapter?.bluetoothLeScanner?.stopScan(mLeScanCallback)
}, SCAN_PERIOD)
scanning = true
devicesArr.clear()
bluetoothAdapter?.bluetoothLeScanner?.startScan(mLeScanCallback)
}else{
scanning = false
bluetoothAdapter?.bluetoothLeScanner?.stopScan(mLeScanCallback)
}
private fun hasPermissions(context: Context?, permissions: Array<String>): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) {
for (permission in permissions) {
if (ActivityCompat.checkSelfPermission(context, permission)
!= PackageManager.PERMISSION_GRANTED) {
return false
}
}
}
return true
}
// Permission check
@SuppressLint("MissingSuperCall")
@RequiresApi(Build.VERSION_CODES.M)
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String?>,
grantResults: IntArray
) {
when (requestCode) {
REQUEST_ALL_PERMISSION -> {
// If request is cancelled, the result arrays are empty.
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Permissions granted!", Toast.LENGTH_SHORT).show()
} else {
requestPermissions(permissions, REQUEST_ALL_PERMISSION)
Toast.makeText(this, "Permissions must be granted", Toast.LENGTH_SHORT).show()
}
}
}
}
@TargetApi(Build.VERSION_CODES.M)
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_temporary)
val bleOnOffBtn: Button = findViewById(R.id.btn_main_onoff)
val scanBtn: Button = findViewById(R.id.btn_main_connect)
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
viewManager = LinearLayoutManager(this)
recyclerViewAdapter = RecyclerAdapter(devicesArr)
val recyclerView = findViewById<RecyclerView>(R.id.recyclerView).apply {
layoutManager = viewManager
adapter = recyclerViewAdapter
}
var condition: TextView = findViewById(R.id.txt_main_condition)
fun bluetoothOnOff() {
if (bluetoothAdapter == null) {
Toast.makeText(this, "블루투스를 지원하지 않는 기기입니다.", Toast.LENGTH_LONG).show()
} else {
if (bluetoothAdapter?.isEnabled == true) {
bluetoothAdapter?.disable()
condition.text = "연결되지 않음"
} else {
val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
startActivityForResult(enableBtIntent, 1)
condition.text = "연결됨"
val handler = Handler(Looper.myLooper()!!)
handler.postDelayed({
if (bluetoothAdapter?.isEnabled == false) {
condition.text = "연결되지 않음"
Toast.makeText(this, "블루투스 권한을 허용해주세요.", Toast.LENGTH_LONG).show()
}
}, 3000)
}
}
}
bleOnOffBtn.setOnClickListener() {
bluetoothOnOff()
}
scanBtn.setOnClickListener { v: View? -> // Scan Button Onclick
if (!hasPermissions(this, PERMISSIONS)) {
requestPermissions(PERMISSIONS, REQUEST_ALL_PERMISSION)
}
scanDevice(true)
}
class ConnectToDevice(c: Context, val device: BluetoothDevice) : AsyncTask<Void, Void, String>() {
private var connectSuccess : Boolean = true
private val context : Context
init {
this.context = c
}
override fun onPreExecute() {
super.onPreExecute()
m_progress = ProgressDialog.show(context, "연결 중...", "MAC: $device")
}
override fun doInBackground(vararg params: Void?): String? {
try {
if(bluetoothSocket == null || !m_isConnected) {
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
bluetoothSocket = device.createRfcommSocketToServiceRecord(myUUID)
BluetoothAdapter.getDefaultAdapter().cancelDiscovery()
bluetoothSocket!!.connect() //error
Log.d(TAG, "연결되었습니다.")
} else { //bluetoothSocket is null
Log.d(TAG, "블루투스 소켓이 널입니다.")
}
} catch(e: IOException) {
connectSuccess = false
e.printStackTrace()
try {
Log.d(TAG, "연결 실패, fallback 시도 중...")
bluetoothSocket = device.javaClass.getMethod( //trying fallback
"createRfcommSocket", *arrayOf<Class<*>?>(
Int::class.javaPrimitiveType
)
).invoke(device, 3) as BluetoothSocket
bluetoothSocket!!.connect() //error
} catch (e2: Exception) { //connect error
connectSuccess = false
e2.printStackTrace()
Log.i("data", "연결할 수 없습니다. 아노ㅓㅏ 진짜 왜이러지?")
}
}
return null
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
if(!connectSuccess) {
Log.i("data", "연결할 수 없습니다.")
} else {
m_isConnected = true
}
m_progress.dismiss()
}
}
recyclerViewAdapter.setOnItemClickListener(object: RecyclerAdapter.OnItemClickListener {
override fun onClick(v: View, data:BluetoothDevice, pos: Int) {
Toast.makeText(applicationContext, "MAC: $data", Toast.LENGTH_SHORT).show()
//recyclerview click event
//여기는 RecyclerView를 클릭했을 때 발생하는 이벤트 처리
ConnectToDevice(this@TemporaryActivity, data).execute() //여기서만 에러가 발생되는 거 보면 여기가 가장 문제인 듯 하다. 에러 없이 실행하고 싶으면 이 라인 주석처리.
}
})
}
}
private fun Handler.postDelayed(function: () -> Unit?, scanPeriod: Int) {
}
this is Error Code
W/System.err: java.io.IOException: read failed, socket might closed or timeout, read ret: -1
at android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:970)
at android.bluetooth.BluetoothSocket.readInt(BluetoothSocket.java:984)
at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:536)
at com.example.arduino.TemporaryActivity$onCreate$ConnectToDevice.doInBackground(TemporaryActivity.kt:198)
at com.example.arduino.TemporaryActivity$onCreate$ConnectToDevice.doInBackground(TemporaryActivity.kt:179)
at android.os.AsyncTask$3.call(AsyncTask.java:394)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:305)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)