views:

152

answers:

3

I'm doing bluetooth development for connecting with a PC. I've basicly used the BTChatExample and changed the UUID to the standard PC SPP-profile.

  1. Trying to close a bluetooth application during a blocking read, by closing the BluetoothSocket will leave the Bluetooth stack in a unusable state. This can only be fixed by disabling and enabling bluetooth and restarting the application. Checking logcat, you can see that some of the internal methods are failing, leaving a open port. Any information on this?

  2. First of all there seams to be differences on how bluetooth is implemented on N1 and HTC Legend/Desire both running 2.1, do you know anything about this?

  3. Connecting isn't 100% reliable, sometimes I get a warning saying ~PortSystemContext init: FAILED. This leaves bluetooth unusable, and restarting is needed.

  4. Am I right in assuming that SPP is the only profile supported for use with the APIs? That's what the docs on the BluetoothAdapter says.

I would love to discuss issues on bluetooth with a developer and iron out these bugs so that Android can have good proper BT support it deserves.

A: 

Closing a socket in one thread during a blocking read should definitely cause the read to return (by throwing IOException) and should not leave the stack in a 'bad state'. This is the behavior on Droid and Nexus.

I spoke directly to the original poster, and he had observed this problem on HTC Legend and HTC Desire. It appears like they are not implementing the API's correctly. I am raising the issue with them.

You are correct that SPP/RFCOMM is the only profile that is intended for use with the API's. SPP/RFCOMM gets you a streaming socket which is good enough for a lot of use cases.

For now I recommend BT development on Nexus One / Motorola Droid, which are considered 'reference' implementations of the Bluetooth API's.

Nick Pelly
+1  A: 

May I suggest that you do not perform blocking read() calls unless you have first checked that there is data ready to be read by using inputstream.available() which returns an integer indicating how many bytes are waiting in the input buffer.

    long timeouttime = gettimeinseconds() + 2;
    String response = "";

    while (gettimeinseconds() < timeouttime) {
      if (inputstream.available() > 0)
          response = response + inputstream.read();
      } else {
          Thread.sleep(100); // sleep to slow down the while() loop. 
      }
    }
return response;

That's just pseudo code, and its oversimplified. The bottom line is that we're not performing any blocking calls (read()) unless we're sure they will return immediately without delay.

Also, I highly recommend using BufferedInputStream instead of a standard InputStream.

Brad Hein
A: 

Anyone could solve this problem ?

I try the following code :

// Keep listening to the InputStream while connected
while (!isInterrupted)
{
    try
    {
        //Clear buffer
        buffer = new byte[1024];

        // Read from the InputStream
        if (mmInStream != null && mmInStream.available() > 0)
        {
            if (isInterrupted)
                break;

            bytes = mmInStream.read(buffer);

            // Send the obtained bytes to the UI Activity
            mHandler.obtainMessage(Act_Main.MESSAGE_READ, bytes, -1, buffer).sendToTarget();
        }
        else
        {
            try
            {
                synchronized (this)
                {
                    this.wait(100);
                }

                if (isInterrupted)
                    break;
            }
            catch(InterruptedException ex)
            {
                Log.e(TAG, "WAIT_EXCEPTION:"+ ex.getMessage());
            }
        }
    }
    catch(Exception ex)
    {
        Log.e(TAG, "disconnected", ex);
        connectionLost();
        break;
    }
}

And I change the isInterrupted boolean in the cancel method. Here is my stop method :

/**
 * Stop all threads
 */
public synchronized void stop()
{
    isStop = true ;

    if (D)
        Log.d(TAG, "stop");

    if(mConnectThread != null)
    {
        mConnectThread.cancel();
        mConnectThread = null;
    }

    if(mConnectedThread != null)
    {
        mConnectedThread.cancel();
        mConnectedThread = null;
    }

    setState(STATE_NONE);
}
Hrk