Android Bluetooth: невозможно подключиться к сокету для прослушивания после создания случайного UUID

Есть два разных случая, когда моя программа не собирается подключаться к BluetoothServerSocket.

Один из экземпляров имеет только 1 UUID, сгенерированный случайным образом, прежде чем он инициирует режим сканирования с SCAN_MODE_CONNECTABLE_DISCOVERABLE и перед использованием того же сгенерированного UUID для создания BluetoothServerSocket для прослушивания. Другой экземпляр генерирует случайный UUID непосредственно перед тем, как BluetoothDevice попытается соединиться с только что сгенерированным UUID.

Каждый из экземпляров не может завершить соединение Bluetooth. На протяжении всей программы я помещал много журналов, чтобы попытаться понять, почему она не сможет подключиться.

Ниже приведен код для первого экземпляра. (Сгенерируйте 1 случайный UUID при запуске приложения.) Если кому-то нравится загружать мой проект Eclipse, просто чтобы посмотреть, вот ссылка на проект от MediaFire. Что касается второго случая, раскомментируйте комментарии в стиле C в приведенном ниже коде, чтобы открыть его.

Я ожидал, что в результате будет установлено успешное соединение между двумя устройствами. Успешное соединение подключает устройство к прослушивающему сокету с помощью сгенерированного UUID. Наблюдаемые результаты показывают, что это маловероятно.

Насколько мне известно, единственный способ получить UUID — это получить его от UUID.randomUUID(). Если есть другие способы, пожалуйста, оставьте комментарий ниже, и я проверю его. Но пока это не тот ответ, которого я хотел.

Заранее спасибо.

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);
    }
}

person tom_mai78101    schedule 07.02.2013    source источник
comment
Я сделал то же самое. Вы можете использовать его в качестве ссылки. Вот ссылка.   -  person    schedule 07.02.2013


Ответы (1)


Для возможности подключения UUID должны совпадать. На стороне сервера то, что вы делаете, правильно, то есть генерируете UUID ramdom и прослушиваете его, но клиенту необходимо подключиться, используя тот же UUID, который прослушивает сервер. Способ получить его будет заключаться в том, что ваш клиент использует fetchUuidsWithSdp() для объекта Server BluetoothDevice и использует полученный UUID для подключения к серверу.

person Dennis Mathews    schedule 07.02.2013
comment
Знаете ли вы способ отфильтровать массив ParcelUUID после использования fetchUuidsWithSDP(), чтобы он соответствовал UUID клиента? Используя fetchUuidWithSDP(), я смог получить ParcelUUIDs, но ни один из них на самом деле не позволил серверу принять соединение. Это похоже на то, что UUID клиента не находится в массиве, и этот же UUID не соответствует UUID сервера. - person tom_mai78101; 13.02.2013
comment
Ответ обсуждается здесь. Короче говоря, UUID не должен генерироваться во время компиляции. UUID не могут быть сгенерированы с использованием UUID.randomUUID(), если только они не предназначены для других конкретных целей. Даже использование BluetoothDevice.getUuids() или BluetoothDevice.fetchUuidsWithSDP() бесполезно, так как UUID также генерируются во время компиляции. (Это включает в себя использование метода отражения и вызов этих двух функций для использования с версиями до Android 4.0, они бесполезны.) - person tom_mai78101; 15.02.2013
comment
Спасибо за ссылку на обсуждение и предложение решения, которое сработало для вас. Генерация UUID во время компиляции в основном гарантирует, что ваш клиент и сервер приложения будут использовать один и тот же UUID, который является основным требованием для его подключения. Это нормально, пока вы работаете и с сервером, и с клиентом, но как насчет подключения к какому-нибудь существующему серверному приложению? Единственный способ получить UUID из SDP, это то, как должен работать Bluetooth, я сам использовал fetchUuidsWithSDP(), но кажется странным, что возвращаемый UUID бесполезен. - person Dennis Mathews; 15.02.2013
comment
Некоторые источники упомянули, что некоторые устройства, особенно устройства HTC, не имеют 100% совместимости с Bluetooth. Они предположили, что интеграция Bluetooth не завершена для этих устройств и, вероятно, она будет завершена, когда уровень API будет намного выше, например, от 18 до 20. Даже в этом случае более старые уровни API будут иметь серьезные проблемы. время использования возможностей Bluetooth в случае сбоя UUID, полученного с помощью SDP, что я и испытываю прямо сейчас. - person tom_mai78101; 16.02.2013