HI,
I've seen the exact same problem (HTC Desire). Despite closing the socket by the book (as Brad suggests), the next connect() blocks forever - until ended by close() by another thread.
I circumvented the problem by always calling BluetoothAdapter.disable()/.enable() before connecting. Awful, unfriendly hack, I know.
I suspect that some of the present BT issues are manufacturer specific, as some app implementors seem to live happily with createRfcommSocketToServiceRecord(), which definitely fails on my HTC Desire (Android 2.1 update 1).
I have seen indications (sorry, don't have references) that HTC Desire's BT stack differs from the Nexus One, although they seem to be very similar devices.
BR Per
(addition) Here's a very simple activity to reproduce the problem (without my disable/enable 'cure'):
package com.care2wear.BtTest; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.os.Bundle; import android.util.Log; import android.widget.TextView; public class BtTestActivity extends Activity < private static final String TAG="BtTest"; BluetoothAdapter mBtAdapter = null; BluetoothDevice mBtDev = null; BluetoothSocket mBtSocket = null; InputStream isBt; OutputStream osBt; String mAddress = "00:18:E4:1C:A4:66"; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.main); init(); connect(); // ok disconnect(); // ok connect(); // this invariably fails - blocked until BT is switched off by someone else, or the peer device turns off/goes out of range disconnect(); >private void init() < Log.d(TAG, "initializing"); mBtAdapter = BluetoothAdapter.getDefaultAdapter(); mBtDev = mBtAdapter.getRemoteDevice(mAddress); Log.d(TAG, "initialized"); >private void connect() < try < Log.d(TAG, "connecting"); Method m = mBtDev.getClass().getMethod("createRfcommSocket", new Class[] < int.class >); mBtSocket = (BluetoothSocket) m.invoke(mBtDev, 1); mBtSocket.connect(); Log.d(TAG, "connected"); > catch (SecurityException e) < Log.e(TAG, "SecEx", e); >catch (NoSuchMethodException e) < Log.e(TAG, "NsmEx", e); >catch (IllegalArgumentException e) < Log.e(TAG, "IArgEx", e); >catch (IllegalAccessException e) < Log.e(TAG, "IAccEx", e); >catch (InvocationTargetException e) < Log.e(TAG, "ItEx", e); >catch (IOException e) < Log.e(TAG, "IOEx", e); >> private void disconnect() < Log.d(TAG, "closing"); if (isBt != null) < try < isBt.close(); >catch (IOException e) < Log.e(TAG, "isBt IOE", e); >isBt = null; > if (osBt != null) < try < osBt.close(); >catch (IOException e) < Log.e(TAG, "osBt IOE", e); >osBt = null; > if (mBtSocket != null) < try < mBtSocket.close(); >catch (IOException e) < Log.e(TAG, "socket IOE", e); >mBtSocket = null; > Log.d(TAG, "closed"); > >
If anyone can spot if I'm doing it wrongly, feel free to comment 🙂
(addition 2) I think I got it to work now:
- The official method of connecting RFCOMM (via SDP) now actually seems to work (HTC Desire, 2.1 update 1), BUT I had to remove and re-pair the BT device. Go figure..
- Reconnection may still fail (service discovery failure) if I reconnect 'too quickly' (quit app, then immediately restart). Guess the connection is not completely down yet..
- If I always end the (last) activity not only with finish(), but also with Runtime.getRuntime().exit(0);, it works a lot better. Go figure again.
If anyone can explain this, I'll happily learn. /Per
(addition 3) Finally got the Froyo (2.2) update for my Desire, and as far as I can see, SPP now works 🙂 /Per
Источник
Android: Bluetooth Socket closed
I have been working on a Bluetooth device and am creating an app for it. I should be able to turn on or off this devices LED by sending it the code 0 or 1. I have some error catching in place to help me with the issue, and after staring at it for ages cannot see where the problem lies. I find devices correctly, and have checked the MAC address returned of the device, that is all fine. From what I can see with logs I also appear to open all the sockets correctly. The error occurs on the final stage of the process with sending byte data to the device. Can anyone spot something I can't? Perhaps the connection is not being made successfully? To clarify the exception triggered is in the sendData() method. If you find the error I will love you forever haha. The error message: Fatal Error, In onResume() and an exception occurred during write:socket closed. So what the socket is closing before the data sends or is never successfully opened? Anyway, a lot of code inbound:
public class ScanFragment extends Fragment < ArrayListscannedList; Button scanningButton; TextView scanningText; ListView scannedListView; BluetoothAdapter mBluetoothAdapter; DeviceItem item; DeviceCustomAdapter adapter; BluetoothDevice device; String TAG = "TEST"; private BluetoothAdapter btAdapter = null; private BluetoothSocket btSocket = null; private OutputStream outStream = null; // Intent request codes private static final int REQUEST_CONNECT_DEVICE_SECURE = 1; private static final int REQUEST_ENABLE_BT = 3; // Well known SPP UUID private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); // Insert your bluetooth devices MAC address private static String address = "00:00:00:00:00:00"; public ScanFragment() < // Required empty public constructor >@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) < return inflater.inflate(R.layout.fragment_scan, container, false); >@Override public void onDestroy() < getActivity().unregisterReceiver(mReceiver); super.onDestroy(); >private final BroadcastReceiver mReceiver = new BroadcastReceiver() < public void onReceive(Context context, Intent intent) < Log.i("found", "hello" + ""); String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) < device = intent .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); item = new DeviceItem(); item.setDeviceName(device.getName()); item.setDeviceCode(device.getAddress()); item.setDeviceId(MY_UUID); scannedList.add(item); Log.i("BT", device.getName() + "\n" + device.getAddress()); >else < Log.i("BT", "none" + ""); >adapter = new DeviceCustomAdapter( getActivity().getApplicationContext(), scannedList); scannedListView.setAdapter(adapter); > >; @Override public void onActivityCreated(Bundle savedInstanceState) < // TODO Auto-generated method stub super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState); scannedList = new ArrayList<>(); scanningButton = (Button) getActivity().findViewById(R.id.scanningButton); scanningText = (TextView) getActivity().findViewById(R.id.scanningText); scannedListView = (ListView) getActivity().findViewById(R.id.scannedListView); scannedListView.setVisibility(View.VISIBLE); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (Build.VERSION.SDK_INT >= 15 && ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) < ActivityCompat.requestPermissions(getActivity(), new String[], 1); > if (mBluetoothAdapter == null) < scanningText.setText("Your device does not support Bluetooth, Sorry!"); >else if (!mBluetoothAdapter.isEnabled()) < scanningText.setText("You need to enable bluetooth to use this app.."); Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); >scanningButton.setOnClickListener(new View.OnClickListener() < @Override public void onClick(View view) < scanningText.setText("Scanning. "); mBluetoothAdapter.startDiscovery(); mBluetoothAdapter.isDiscovering(); scanningText.setText("Click on a device to connect"); >>); // Register for broadcasts when a device is discovered. IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); getActivity().registerReceiver(mReceiver, filter); scannedListView.setOnItemClickListener(new AdapterView.OnItemClickListener() < @Override public void onItemClick(AdapterView>parent, View view, int position, long id) < item = scannedList.get(position); String name= scannedList.get(position).getDeviceName(); Toast toast = Toast.makeText(getActivity().getApplicationContext(), "Connecting to " + item.getDeviceCode() + "" + name, Toast.LENGTH_SHORT); toast.show(); scanningText.setText(item.getDeviceCode()); mBluetoothAdapter.cancelDiscovery(); address = item.getDeviceCode(); // Create the result Intent and include the MAC address connectDevice(address, true); ledOff(view); >>); > public void ledOn(View v) < sendData("1"); Toast msg = Toast.makeText(getActivity().getApplicationContext(), "LED is ON", Toast.LENGTH_SHORT); msg.show(); >public void ledOff(View v) < sendData("0"); Toast msg = Toast.makeText(getActivity().getApplicationContext(), "LED is OFF", Toast.LENGTH_SHORT); msg.show(); >public void connectToDevice(String adr) < super.onResume(); //enable buttons once connection established. // btnOn.setEnabled(true); // btnOff.setEnabled(true); // Set up a pointer to the remote node using it's address. btAdapter = mBluetoothAdapter; BluetoothDevice device = btAdapter.getRemoteDevice(adr); // Two things are needed to make a connection: // A MAC address, which we got above. // A Service ID or UUID. In this case we are using the // UUID for SPP. try < btSocket = device.createRfcommSocketToServiceRecord(MY_UUID); >catch (IOException e) < errorExit("Fatal Error", "In onResume() and socket create failed: " + e.getMessage() + "."); >// Discovery is resource intensive. Make sure it isn't going on // when you attempt to connect and pass your message. btAdapter.cancelDiscovery(); // Establish the connection. This will block until it connects. try < btSocket.connect(); >catch (IOException e) < try < btSocket.close(); >catch (IOException e2) < errorExit("Fatal Error", "In onResume() and unable to close socket during connection failure" + e2.getMessage() + "."); >> // Create a data stream so we can talk to server. try < outStream = btSocket.getOutputStream(); >catch (IOException e) < errorExit("Fatal Error", "In onResume() and output stream creation failed:" + e.getMessage() + "."); >> private void errorExit(String title, String message) < Toast msg = Toast.makeText(getActivity().getApplicationContext(), title + " - " + message, Toast.LENGTH_SHORT); msg.show(); // finish(); >private void sendData(String message) < byte[] msgBuffer = message.getBytes(); try < outStream.write(msgBuffer); >catch (IOException e) < String msg = "In onResume() and an exception occurred during write: " + e.getMessage(); errorExit("Fatal Error", msg); >> private void connectDevice(String address, boolean secure) < // Get the device MAC address connectToDevice(address); // Get the BluetoothDevice object BluetoothDevice device = btAdapter.getRemoteDevice(address); >>
Источник