0

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)
halfer
  • 19,471
  • 17
  • 87
  • 173
장인수
  • 3
  • 2
  • You are mixing bluetooth classic code with bluetooth low energy code. I guess you should only use one type, which should match your device type. – Emil Aug 23 '21 at 06:49

0 Answers0