java - 电话间隙 : BluetoothChatExample [Android]

标签 java android cordova bluetooth

我尝试使用 Phonegap 为 Android 开发一个简约的蓝牙聊天。该插件基于 BluetoothChat 的 Android SDK 示例,如示例代码中所示。

native 蓝牙聊天工作正常。 问题是,当我调用“write”函数时,尽管已建立连接,但“ConnectedThread”始终为空。

在 State 设置为 3 (STATE_CONNECTED) 后,我无法识别它在哪里再次设置为 null。

所以当我在android上运行 native 程序时,它工作正常并且写入期间的状态始终为3,但是当我使用我的phonegap插件'r'(ConnectedThread)时变为null:

public void write(byte[] out) {
    // Create temporary object
    ConnectedThread r;
    // Synchronize a copy of the ConnectedThread
    synchronized (this) {
       Log.i(TAG, "State "+mState);
       if (mState != STATE_CONNECTED) return;
            Log.i(TAG, "Connected Thread "+mConnectedThread);
        r = mConnectedThread;

    }
    // Perform the write unsynchronized
    r.write(out);
}

我使用了很多调试消息,但我从未被告知状态再次为空。

完整源代码:

PLUGIN.java

public class BluetoothConnection extends CordovaPlugin {

    //Android specific tag-messages
    private static final String TAG ="BluetoothConnection";
    private static final boolean D = true;


    // Member-Variables

    public BluetoothAdapter mBluetoothAdapter;
    public JSONArray mListOfDiscoveredDevices;
    public String mConnectedDeviceName;
    public ConnectionHandler mConnectionHandler;



    // Phonegap-specific actions, which call the function
    public String ACTION_ENABLEBLUETOOTH = "enableBluetooth";
    public String ACTION_DISABLEBLUETOOTH = "disableBluetooth";
    public String ACTION_DISCOVERDECIVES = "discoverDevices";
    public String ACTION_STOPDISCOVERDEVICES = "stopDiscoverDevices";
    public String ACTION_CREATEBOND = "createBond";
    public String ACTION_WRITEMESSAGE = "writeMessage";

    // not usable, this moment
    public String ACTION_DISCONNECT = "disconnect";

    //Message types sent from the ConnectionHandler
    public static final int MESSAGE_STATE_CHANGE = 1;
public static final int MESSAGE_READ = 2;
public static final int MESSAGE_WRITE = 3;
public static final int MESSAGE_DEVICE_NAME = 4;
public static final int MESSAGE_TOAST = 5;

public static final String DEVICE_NAME = "device_name";
public static final String TOAST = "toast";



    @Override
    public boolean execute(String action, JSONArray args,
                    CallbackContext callbackContext) throws JSONException {

            mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

            if (mBluetoothAdapter.equals(null)) {
                    Log.i(TAG, "no adapter was found");
            }

            mConnectionHandler = new ConnectionHandler(mHandler);


            if (action.equals(ACTION_ENABLEBLUETOOTH)) {
                    enableBluetooth();
            }
            else if (action.equals(ACTION_DISABLEBLUETOOTH)) {
                    disableBluetooth();
            }
            else if (action.equals(ACTION_DISCOVERDECIVES)) {
                    discoverDevices();
            }
            else if (action.equals(ACTION_STOPDISCOVERDEVICES)) {
                    stopDiscovering(callbackContext);
            }
            else if (action.equals(ACTION_CREATEBOND)) {
                    try {
                            BluetoothDevice remoteBtDevice = createBond(args, callbackContext);
                            connect(remoteBtDevice, callbackContext);
                    } catch (Exception e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                    }
            }

            else if(action.equals(ACTION_WRITEMESSAGE)){
                    writeMessage(args.getString(0));
            }

            else if (action.equals(ACTION_DISCONNECT)) {
                    disconnect();
            }

            return false;

    }





    public void enableBluetooth() {
            if (!mBluetoothAdapter.equals(null)) {
                    mBluetoothAdapter.enable();
                    Log.i(TAG, "bluetooth on");
            }

    }

    public void disableBluetooth() {
            if (mBluetoothAdapter.isEnabled()) {
                    mBluetoothAdapter.disable();
                    Log.i(TAG, "bluetooth off");
            }
    }

    public void discoverDevices() {
            mListOfDiscoveredDevices = new JSONArray();
            Log.i("Log", "in the start searching method");
            IntentFilter intentFilter = new IntentFilter(
                            BluetoothDevice.ACTION_FOUND);
            cordova.getActivity().registerReceiver(mFoundDevices, intentFilter);
            mBluetoothAdapter.startDiscovery();
    }

    private void stopDiscovering(CallbackContext callbackContext) {
            if (mBluetoothAdapter.isDiscovering()) {
                    mBluetoothAdapter.cancelDiscovery();
            }

            PluginResult res = new PluginResult(PluginResult.Status.OK,
                            mListOfDiscoveredDevices);
            res.setKeepCallback(true);
            callbackContext.sendPluginResult(res);

            Log.i("Info", "Stopped discovering Devices !");

    }


    public BluetoothDevice createBond(JSONArray args, CallbackContext callbackContext) throws Exception {
            String macAddress = args.getString(0);
            Log.i(TAG, "Connect to MacAddress "+macAddress);
            BluetoothDevice btDevice = mBluetoothAdapter.getRemoteDevice(macAddress);
            Log.i("Device","Device "+btDevice);

            Class class1 = Class.forName("android.bluetooth.BluetoothDevice");
    Method createBondMethod = class1.getMethod("createBond");
    Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);

    if(btDevice.equals(null))
            throw new NullPointerException("Remote BluetoothDevice could not be paired !");

    return btDevice;
}

    public void removeBond(BluetoothDevice btDevice) throws Exception {
             Class btClass = Class.forName("android.bluetooth.BluetoothDevice");
     Method removeBondMethod = btClass.getMethod("removeBond");
     Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice);
    }



    public void connect(BluetoothDevice btDevice, CallbackContext callbackContext) {
            if(!btDevice.equals(null)){
                    mConnectionHandler.connect(btDevice, false);
                    PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
                    result.setKeepCallback(true);
                    callbackContext.sendPluginResult(result);

                    Log.i(TAG, "Status after connecting "+mConnectionHandler.getState());
            }
            else {
                    callbackContext.error("Could not connect to "+btDevice.getAddress());
            }
    }


    public void disconnect(){

    }

    public void writeMessage(String message){
            if(mConnectionHandler.getState() != ConnectionHandler.STATE_CONNECTED){
                    Log.i(TAG, "Could not write to device");
                    Log.i(TAG, "State "+mConnectionHandler.getState());
            }

            if(message.length() > 0) {
                    byte[] send = message.getBytes();
                    mConnectionHandler.write(send);

                    Log.i(TAG, "sending "+message);

            }
            else {
                    Log.i(TAG, "There is nothing to send.");
            }
    }



    private BroadcastReceiver mFoundDevices = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                    Message msg = Message.obtain();
                    String action = intent.getAction();
                    if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                            Toast.makeText(context, "found Device !", Toast.LENGTH_SHORT).show();

                            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);


                            Log.i("FOUND", "Name " + device.getName() + "-" + device.getAddress());
                            JSONObject discoveredDevice = new JSONObject();
                            try {
                                    discoveredDevice.put("name", device.getName());
                                    discoveredDevice.put("adress", device.getAddress());
                                    if (!isJSONInArray(discoveredDevice)) {
                                            mListOfDiscoveredDevices.put(discoveredDevice);
                                    }
                            } catch (JSONException e) {
                                    e.printStackTrace();
                            }

                    }

            }
    };




    private final Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {

        case MESSAGE_STATE_CHANGE:
            if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);

            switch (msg.arg1) {
                    case ConnectionHandler.STATE_CONNECTED:
                            Log.i(TAG, "ConnectionHandler.STATE_CONNECTED !");
                            break;
                    case ConnectionHandler.STATE_CONNECTING:
                            Log.i(TAG, "ConnectionHandler.STATE_CONNECTING !");
                            break;
                    case ConnectionHandler.STATE_LISTEN:
                            Log.i(TAG, "ConnectionHandler.STATE_LISTEN !");
                            break;
                    case ConnectionHandler.STATE_NONE:
                            Log.i(TAG, "ConnectionHandler.STATE_NONE !");
                            break;
                    }
                    break;

                case MESSAGE_WRITE:
                        byte[] writeBuf = (byte[]) msg.obj;
                        // construct a string from the buffer
                        String writeMessage = new String(writeBuf);
                        Log.i(TAG, "Write "+writeMessage);
                        break;
                case MESSAGE_READ:
                        byte[] readBuf = (byte[]) msg.obj;
                        // construct a string from the valid bytes in the buffer
                        String readMessage = new String(readBuf, 0, msg.arg1);
                        Log.i(TAG, "Read "+readMessage);
                        break;
                case MESSAGE_DEVICE_NAME:
                        // save the connected device's name
                        mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
                        Log.i(TAG, mConnectedDeviceName);
                        break;
                case MESSAGE_TOAST:
                        String message = msg.getData().getString(TOAST);
                        Log.i(TAG, "Connection lost : " +message);
                        break;
                }
            }
        };}

连接处理程序

public class ConnectionHandler {
// Debugging
private static final String TAG = "BluetoothChatService";
private static final boolean D = true;

// Name for the SDP record when creating server socket
private static final String NAME_SECURE = "BluetoothChatSecure";
private static final String NAME_INSECURE = "BluetoothChatInsecure";

// Unique UUID for this application
private static final UUID MY_UUID_SECURE =
    UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private static final UUID MY_UUID_INSECURE =
    UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

// Member fields
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private AcceptThread mSecureAcceptThread;
private AcceptThread mInsecureAcceptThread;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;

// Constants that indicate the current connection state
public static final int STATE_NONE = 0; // we're doing nothing
public static final int STATE_LISTEN = 1; // now listening for incoming connections
public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
public static final int STATE_CONNECTED = 3; // now connected to a remote device

public ConnectionHandler(Handler handler) {
    mAdapter = BluetoothAdapter.getDefaultAdapter();
    mState = STATE_NONE;
    mHandler = handler;
}


private synchronized void setState(int state) {
    if (D) Log.d(TAG, "setState() " + mState + " -> " + state);
    mState = state;

    // Give the new state to the Handler so the UI Activity can update
    mHandler.obtainMessage(BluetoothConnection.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}


public synchronized int getState() {
    return mState;
}

public synchronized void start() {
    if (D) Log.d(TAG, "start");

    // Cancel any thread attempting to make a connection
    if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}

    // Cancel any thread currently running a connection
    if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}

    setState(STATE_LISTEN);

    // Start the thread to listen on a BluetoothServerSocket
    if (mSecureAcceptThread == null) {
        mSecureAcceptThread = new AcceptThread(true);
        mSecureAcceptThread.start();
    }
    if (mInsecureAcceptThread == null) {
        mInsecureAcceptThread = new AcceptThread(false);
        mInsecureAcceptThread.start();
    }
}


public synchronized void connect(BluetoothDevice device, boolean secure) {
    if (D) Log.d(TAG, "connect to: " + device);

    // Cancel any thread attempting to make a connection
    if (mState == STATE_CONNECTING) {
        if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
    }

    // Cancel any thread currently running a connection
    if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}

    // Start the thread to connect with the given device
    mConnectThread = new ConnectThread(device, secure);
    mConnectThread.start();
    setState(STATE_CONNECTING);
}


public synchronized void connected(BluetoothSocket socket, BluetoothDevice
        device, final String socketType) {
    if (D) Log.d(TAG, "connected, Socket Type:" + socketType);

    // Cancel the thread that completed the connection
    if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}

    // Cancel any thread currently running a connection
    if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}

    // Cancel the accept thread because we only want to connect to one device
    if (mSecureAcceptThread != null) {
        mSecureAcceptThread.cancel();
        mSecureAcceptThread = null;
    }
    if (mInsecureAcceptThread != null) {
        mInsecureAcceptThread.cancel();
        mInsecureAcceptThread = null;
    }

    // Start the thread to manage the connection and perform transmissions
    mConnectedThread = new ConnectedThread(socket, socketType);
    mConnectedThread.start();

    // Send the name of the connected device back to the UI Activity
    Message msg = mHandler.obtainMessage(BluetoothConnection.MESSAGE_DEVICE_NAME);
    Bundle bundle = new Bundle();
    bundle.putString(BluetoothConnection.DEVICE_NAME, device.getName());
    msg.setData(bundle);
    mHandler.sendMessage(msg);

    setState(STATE_CONNECTED);
}

public synchronized void stop() {
    if (D) Log.d(TAG, "stop");

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

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

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

    if (mInsecureAcceptThread != null) {
        mInsecureAcceptThread.cancel();
        mInsecureAcceptThread = null;
    }
    setState(STATE_NONE);
}

public void write(byte[] out) {
    // Create temporary object
    ConnectedThread r;
    // Synchronize a copy of the ConnectedThread
    synchronized (this) {
       Log.i(TAG, "State "+mState);
       if (mState != STATE_CONNECTED) return;
            Log.i(TAG, "Connected Thread "+mConnectedThread);
        r = mConnectedThread;

    }
    // Perform the write unsynchronized
    r.write(out);
}


private void connectionFailed() {
    // Send a failure message back to the Activity
    Message msg = mHandler.obtainMessage(BluetoothConnection.MESSAGE_TOAST);
    Bundle bundle = new Bundle();
    bundle.putString(BluetoothConnection.TOAST, "Unable to connect device");
    msg.setData(bundle);
    mHandler.sendMessage(msg);

    // Start the service over to restart listening mode
    ConnectionHandler.this.start();
}

private void connectionLost() {
    // Send a failure message back to the Activity
    Message msg = mHandler.obtainMessage(BluetoothConnection.MESSAGE_TOAST);
    Bundle bundle = new Bundle();
    bundle.putString(BluetoothConnection.TOAST, "Device connection was lost");
    msg.setData(bundle);
    mHandler.sendMessage(msg);

    // Start the service over to restart listening mode
    ConnectionHandler.this.start();
}

private class AcceptThread extends Thread {
    // The local server socket
    private final BluetoothServerSocket mmServerSocket;
    private String mSocketType;

    public AcceptThread(boolean secure) {
        BluetoothServerSocket tmp = null;
        mSocketType = secure ? "Secure":"Insecure";

        // Create a new listening server socket
        try {
            if (secure) {
                tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,
                    MY_UUID_SECURE);
            } else {
                tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(
                        NAME_INSECURE, MY_UUID_INSECURE);
            }
        } catch (IOException e) {
            Log.e(TAG, "Socket Type: " + mSocketType + "listen() failed", e);
        }
        mmServerSocket = tmp;
    }

    public void run() {
        if (D) Log.d(TAG, "Socket Type: " + mSocketType +
                "BEGIN mAcceptThread" + this);
        setName("AcceptThread" + mSocketType);

        BluetoothSocket socket = null;

        // Listen to the server socket if we're not connected
        while (mState != STATE_CONNECTED) {
            try {
                // This is a blocking call and will only return on a
                // successful connection or an exception
                socket = mmServerSocket.accept();
            } catch (IOException e) {
                Log.e(TAG, "Socket Type: " + mSocketType + "accept() failed", e);
                break;
            }

            // If a connection was accepted
            if (socket != null) {
                synchronized (ConnectionHandler.this) {
                    switch (mState) {
                    case STATE_LISTEN:
                    case STATE_CONNECTING:
                        // Situation normal. Start the connected thread.
                        connected(socket, socket.getRemoteDevice(),
                                mSocketType);
                        break;
                    case STATE_NONE:
                    case STATE_CONNECTED:
                        // Either not ready or already connected. Terminate new socket.
                        try {
                            socket.close();
                        } catch (IOException e) {
                            Log.e(TAG, "Could not close unwanted socket", e);
                        }
                        break;
                    }
                }
            }
        }
        if (D) Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType);

    }

    public void cancel() {
        if (D) Log.d(TAG, "Socket Type" + mSocketType + "cancel " + this);
        try {
            mmServerSocket.close();
        } catch (IOException e) {
            Log.e(TAG, "Socket Type" + mSocketType + "close() of server failed", e);
        }
    }
}



private class ConnectThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final BluetoothDevice mmDevice;
    private String mSocketType;

    public ConnectThread(BluetoothDevice device, boolean secure) {
        mmDevice = device;
        BluetoothSocket tmp = null;
        mSocketType = secure ? "Secure" : "Insecure";

        // Get a BluetoothSocket for a connection with the
        // given BluetoothDevice
        try {
            if (secure) {
                tmp = device.createRfcommSocketToServiceRecord(
                        MY_UUID_SECURE);
            } else {
                tmp = device.createInsecureRfcommSocketToServiceRecord(
                        MY_UUID_INSECURE);
            }
        } catch (IOException e) {
            Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
        }
        mmSocket = tmp;
    }

    public void run() {
        Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType);
        setName("ConnectThread" + mSocketType);

        // Always cancel discovery because it will slow down a connection
        mAdapter.cancelDiscovery();

        // Make a connection to the BluetoothSocket
        try {
            // This is a blocking call and will only return on a
            // successful connection or an exception
            mmSocket.connect();
        } catch (IOException e) {
            // Close the socket
            try {
                mmSocket.close();
            } catch (IOException e2) {
                Log.e(TAG, "unable to close() " + mSocketType +
                        " socket during connection failure", e2);
            }
            connectionFailed();
            return;
        }

        // Reset the ConnectThread because we're done
        synchronized (ConnectionHandler.this) {
            mConnectThread = null;
        }

        // Start the connected thread
        connected(mmSocket, mmDevice, mSocketType);
    }

    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) {
            Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e);
        }
    }
}

private class ConnectedThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;

    public ConnectedThread(BluetoothSocket socket, String socketType) {
        Log.d(TAG, "create ConnectedThread: " + socketType);
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;

        // Get the BluetoothSocket input and output streams
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) {
            Log.e(TAG, "temp sockets not created", e);
        }

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }

    public void run() {
        Log.i(TAG, "BEGIN mConnectedThread");
        byte[] buffer = new byte[1024];
        int bytes;

        // Keep listening to the InputStream while connected
        while (true) {
            try {
                // Read from the InputStream
                bytes = mmInStream.read(buffer);

                // Send the obtained bytes to the UI Activity
                mHandler.obtainMessage(BluetoothConnection.MESSAGE_READ, bytes, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
                Log.e(TAG, "disconnected", e);
                connectionLost();
                // Start the service over to restart listening mode
                ConnectionHandler.this.start();
                break;
            }
        }
    }

    public void write(byte[] buffer) {
        try {
            mmOutStream.write(buffer);

            // Share the sent message back to the UI Activity
            mHandler.obtainMessage(BluetoothConnection.MESSAGE_WRITE, -1, -1, buffer)
                    .sendToTarget();
        } catch (IOException e) {
            Log.e(TAG, "Exception during write", e);
        }
    }

    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) {
            Log.e(TAG, "close() of connect socket failed", e);
        }
    }
}}

谢谢!!!

最佳答案

我在一个新项目中再次实现 - 现在它可以工作了,不知道为什么 - 但它现在可以工作了。

关于java - 电话间隙 : BluetoothChatExample [Android],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21072148/

相关文章:

android - 为每个构建变体配置 Firebase Analytics + Google Tag Manager (GTM)

android - Cordova Facebook Connect 在初始化时失败

android - 如何滚动由Cordova mfilechooser插件触发的内存文件浏览器

java - Spring Cloud config - 共享文件或其位置

java - Java 中的动态泛型类型

java - JsonObject 构建 Stackoverflow 错误

javascript - Angular Marked 和 Inappbrowser 在系统浏览器中打开所有链接

java - 解析泛型类型描述

java - Netflix Zuul 服务器-/路由端点不可用

android - 滚动到谷歌地图时,Ionic Android 应用程序崩溃