1

There are two different instances of my program not being about to connect to a BluetoothServerSocket.

One of the instances has only 1 UUID generated randomly before it initiates scan mode with SCAN_MODE_CONNECTABLE_DISCOVERABLE and before using the same generated UUID to create a BluetoothServerSocket for listening. The other intance generates a random UUID just before a BluetoothDevice tries to connect with the UUID just generated.

Each of the instances cannot complete the Bluetooth connection. Throughout the entire program, I put many Logs just to try and see why it wouldn't be able to connect.

Below is the code for the first instance. (Generate 1 random UUID at the launch of the app.) If anyone likes to download my Eclipse project just to take a look, here's the link of the project from MediaFire. As for the second instance, uncommenting the C-style comments in the code below will reveal it.

I expected the results would be to have a successful connection between two devices. The successful connection connects a device to a listening socket, by using a generated UUID. The observed results show it is unlikely.

As far as I know, the only way to obtain a UUID is to obtain it from UUID.randomUUID(). If there are other ways, please post a comment below, and I'll check it. But for now, it's not the answer I wanted.

Thanks in advance.

package o.p;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

/**
 * The purpose of this app is to create a server-only Bluetooth connection that
 * only accepts incoming Bluetooth connections. It is used only for testing
 * one device that needs Bluetooth tweaking in order to consistently work
 * correctly on the other device. In short, 2 devices are required.
 * */

public class Main extends Activity implements View.OnClickListener {
    //Button
    private Button acceptButton;
    private Button scanButton;

    //Bluetooth stuffs.
    private BluetoothAdapter btAdapter;
    private BluetoothServerSocket serverSocket;
    private BluetoothSocket socket;
    private BluetoothDevice targetDevice;
    private final UUID uuid = UUID.randomUUID();

    /*private UUID randomUUID;*/

    //Accepting thread.
    private class Accept implements Runnable {
        private BluetoothServerSocket socket;
        private BluetoothSocket result = null;

        public Accept(BluetoothServerSocket s) {
            socket = s;
            result = null;
        }

        @Override
        public void run() {
            try {
                Log.d("DEBUG", "Accepting.");
                result = socket.accept();
                Log.d("DEBUG", "Closing server socket.");
                socket.close();
            }
            catch (IOException e) {
                Log.d("DEBUG - onClick(), case Accept", "Unable to accept incoming connection.");
            }
        }

        public BluetoothSocket getSocket() {
            while (result == null);
            return result;
        }
    }

    //Connecting thread.
    private class Connecting implements Runnable {
        private BluetoothDevice device;

        public Connecting(BluetoothDevice d) {
            device = d;
        }

        @Override
        public void run() {
            try {


                   /*Log.d("DEBUG", "Generating a new random UUID.");
                randomUUID = UUID.randomUUID();*/
                Log.d("DEBUG", "Obtaining a socket.");
                BluetoothSocket s = device.createRfcommSocketToServiceRecord(uuid);
                Log.d("DEBUG", "Cancelling discovery, if it's still discovering.");
                if (btAdapter.isDiscovering())
                    btAdapter.cancelDiscovery();
                Log.d("DEBUG", "Connecting to listening socket with UUID: " + uuid.toString());
                s.connect();

            }
            catch (IOException e) {
                Log.d("DEBUG - Connecting.run()", "Unable to connect to the listening socket.");
            }
        }
    }

    //Thread executor
    private ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();

    //BroadcastReceiver for accepting Bluetooth
    private BroadcastReceiver receiver;

    @Override
    public void onCreate(Bundle b) {
        super.onCreate(b);
        setContentView(R.layout.main);
        init();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button_accept:
                Log.d("DEBUG", "Pressing the Accept button.");
                Accept acceptThread = new Accept(serverSocket);
                Connecting connectThread = new Connecting(targetDevice);
                if (serverSocket != null) {
                    executor.execute(acceptThread);
                    executor.execute(connectThread);
                    socket = acceptThread.getSocket();
                }
                else {
                    Log.d("DEBUG", "Server socket isn't ready.");
                    Toast.makeText(this, "Server socket isn't ready.", Toast.LENGTH_LONG).show();
                }
                break;
            case R.id.button_scan:
                if (btAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
                    Log.d("DEBUG", "Initiating discovery scan mode.");
                    Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
                    discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
                    this.startActivity(discoverableIntent);
                    Toast.makeText(this, "Being discovered...", Toast.LENGTH_LONG).show();
                }
                if (btAdapter.isDiscovering()) {
                    Toast.makeText(this, "Re-scanning...", Toast.LENGTH_SHORT).show();
                    Log.d("DEBUG", "Re-scanning.");
                    btAdapter.cancelDiscovery();
                }
                Log.d("DEBUG", "Scanning.");
                Toast.makeText(this, "Scanning...", Toast.LENGTH_LONG).show();
                btAdapter.startDiscovery();
                break;
        }
    }

    private void init() {
        Log.d("DEBUG", "Initializing.");
        Log.d("DEBUG", "Button initializing.");
        acceptButton = (Button) findViewById(R.id.button_accept);
        acceptButton.setOnClickListener(this);
        scanButton = (Button) findViewById(R.id.button_scan);
        scanButton.setOnClickListener(this);
        Log.d("DEBUG", "Registering BroadcastReceiver.");
        receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                    Log.d("DEBUG", "Device has been found.");
                    BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    Log.d("DEBUG", "Obtained a device from Intent.");
                    if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
                        Log.d("DEBUG", "Removing paired device.");
                        try {
                            Method m = device.getClass().getMethod("removeBond", (Class[]) null);
                            m.invoke(device, (Object[]) null);
                            Log.d("DEBUG", "Removed " + device);
                        }
                        catch (NoSuchMethodException e) {
                            Log.e("ERROR - DeviceReceiver.onReceive()", "", e);
                        }
                        catch (IllegalArgumentException e) {
                            Log.e("ERROR - DeviceReceiver.onReceive()", "", e);
                        }
                        catch (IllegalAccessException e) {
                            Log.e("ERROR - DeviceReceiver.onReceive()", "", e);
                        }
                        catch (InvocationTargetException e) {
                            Log.e("ERROR - DeviceReceiver.onReceive()", "", e);
                        }
                    }
                    else {
                        Log.d("DEBUG", "Obtaining remote device's address.");
                        btAdapter.getRemoteDevice(device.getAddress());
                        try {
                            serverSocket = btAdapter.listenUsingRfcommWithServiceRecord(device.getName(), uuid);
                            Log.d("DEBUG", "Listening to " + device.getName() + "...");
                        }
                        catch (IOException e) {
                            Log.d("DEBUG - onReceive()", "Unable to create a server socket after receiving a broadcast.", e);
                            serverSocket = null;
                            Log.d("DEBUG", "Server socket is set to null.");
                        }
                    }
                    targetDevice = device;
                }
                else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
                    Log.d("DEBUG", "Scanning finished.");
                }
            }
        };
        Log.d("DEBUG", "Creating Bluetooth Adapter.");
        btAdapter = BluetoothAdapter.getDefaultAdapter();
        try {
            Log.d("DEBUG", "Creating a server socket for listening using UUID: " + uuid.toString());
            serverSocket = btAdapter.listenUsingRfcommWithServiceRecord("server", uuid);
        }
        catch (IOException e) {
            Log.d("DEBUG - init()", "Error in creating a server socket from uuid.");
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        //TODO: Not done with the receivers.
        IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        registerReceiver(receiver, filter);
        filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        registerReceiver(receiver, filter);
    }

    @Override
    public void onPause() {
        //TODO: Complete this one. Same for onResume().
        super.onPause();
        unregisterReceiver(receiver);
    }
}
tom_mai78101
  • 2,383
  • 2
  • 32
  • 59
  • I did the same thing. You can use it as reference. Here is the [link](http://stackoverflow.com/questions/6369585/how-to-connect-with-paired-bluetooth-device-programmatic-in-android). –  Feb 07 '13 at 12:33

1 Answers1

1

To be able to connect the UUIDs should match. On the Server side what you are doing is correct i.e generating a ramdom UUID and listening on it, But the client needs to connect using the same UUID that the server is listening on. The way to get it will be from your client use the fetchUuidsWithSdp() on the Server BluetoothDevice object and use the obtained UUID to connect to the server.

Dennis Mathews
  • 6,897
  • 2
  • 26
  • 39
  • Do you know a way to filter out the `ParcelUUID` array after using `fetchUuidsWithSDP()`, so that it matches the client's UUID? Using `fetchUuidWithSDP()`, I was able to obtain `ParcelUUIDs`, but none of them actually let the server accepts the connection. It's like as if the client's UUID isn't in the array, and that the same UUID doesn't match the server's UUID. – tom_mai78101 Feb 13 '13 at 10:19
  • [The answer is discussed here.](https://groups.google.com/forum/?fromgroups#!topic/android-developers/3RzYDDen8WE) In short, UUIDs must not be generated at compile-time. The UUIDs cannot be generated using `UUID.randomUUID()`, unless they are for other specific uses. Even using `BluetoothDevice.getUuids()` or `BluetoothDevice.fetchUuidsWithSDP()` aren't useful, as the UUIDs are generated at compile-time also. (This includes using reflection method and invoking those two function for use with pre-Android 4.0, they aren't useful.) – tom_mai78101 Feb 15 '13 at 16:59
  • Thanks for linking to the discussion and positing the solution that worked for you, Generating UUIDs at compile time basically ensures that your application Client and Server gets to use the same UUID whihc is the basic requriement for it to connect. This is ok as long as you are wring both the server and the client, but what about connecting to some existing server application ? The only way os to get the UUID from SDP, this is how Bluetooth is intended to work, I haveny myself used the fetchUuidsWithSDP() but it seems strange that the UUID it returns is not useful. – Dennis Mathews Feb 15 '13 at 18:39
  • Some sources mentioned that some devices, particularly HTC devices, don't have 100% Bluetooth compatibilities. They suggested that the Bluetooth integration isn't complete for these devices, and that it is likely it will be complete when the API level is at a much higher number, like around 18 to 20. Even so, older API levels will have a hard time utilizing Bluetooth capabilities if the UUIDs fetched with SDP fails, which is what I'm experiencing right now. – tom_mai78101 Feb 16 '13 at 05:49