Search code examples
javaandroidbluetoothmetawatch

Sending data via Bluetooth with Android


Ive written code that connects and sends data from an Android device to another via Bluetooth.

It all works when run from that class. When I create an instance of the class the data gets sent to the output stream before the connection creation has finished.

How do I check that the connection is up before sending data?

package com.flightscope.app.metawatch;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import com.flightscope.app.metawatch.Crc;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.util.Log;

public class MetawatchConnected {

//  public static final String TAG = "MetawatchConnected";

    private BluetoothSocket mSocket;
    private BluetoothDevice mMetawatchDevice;
    private final BluetoothAdapter mAdapter;
//  private final InputStream mInput;
//  private final OutputStream mOutput;

    ConnectThread mConnectThread = null;
    ConnectedThread mConnectedThread = null;

    final private String TAG = "MetaWatch Connection Thread";


    public MetawatchConnected(String address)
    {
        Log.d(TAG, "Start");
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        mMetawatchDevice = mAdapter.getRemoteDevice(address);

        if(mConnectThread == null)
        {
            mConnectThread = new ConnectThread(mMetawatchDevice);
            mConnectThread.start();
        }

    }

    public void getBmp()
    {
        Bitmap bmp = Bitmap.createBitmap(96, 96, Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(bmp);
        Paint paint = new Paint();

        paint.setColor(Color.BLACK);
        paint.setTextSize(14);
        Typeface tp = Typeface.DEFAULT;
        paint.setTypeface(tp);
        canvas.drawColor(Color.WHITE);
        canvas.drawText("Carry Distance", 0, 14, 0, 50, paint);

        int[] pixelArray = new int[96 * 96];
        bmp.getPixels(pixelArray, 0, 96, 0, 0, 96, 96);

        int[] buffer = new int[1152];

        for(int i = 0; i < buffer.length; i++)
        {
            int[] bytes = new int[8];

            for(int j = 0; j < bytes.length; j++)
            {
                if(pixelArray[(i * 8) + j ] != Color.BLACK)
                {
                    bytes[j] = 0;
                }
                else
                {
                    bytes[j] = 1;
                }

                buffer[i] = (128 * bytes[7]) + (64 * bytes[6]) + (32* bytes[5]) + (16 * bytes[4]) + 
                            (8 * bytes[3]) + (4 * bytes[2]) + (2 * bytes[1]) + (1 * bytes[0]);

            }

        }

        //fillScreen();

        for(int z = 30; z < 96; z +=2 )
        {
    //      int[] buffer = {0x01, 0x20, 0x40, 0x00, (i), 0xd8, 0xb6, 0x6d, 0xdb, 0xb6, 0x6d, 
    //                      0xdb, 0xb6, 0x6d, 0xdb, 0xb6, 0x0d, (i + 1), 0x00, 0x00, 0x00, 0x00, 
    //                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

            int[] send = new int[30];
            Log.d(TAG, ""+z);
            send[0] = 0x01;
            send[1] = 0x20;
            send[2] = 0x40;
            send[3] = 0x00;
            send[4] = z;
            for(int j = 0; j < 12; j++)
            {
                send[5+j] = buffer[((z * 12) + j)];
            }

            send[17] = (z + 1);
            for(int j = 0; j < 12; j++)
            {
                send[18+j] = buffer[(12 * z) + 12 + j];
            }

            try
            {
                final Crc sendMsg = new Crc(send);
                mConnectedThread.write(sendMsg.message);
            }
            catch(Exception e) { Log.d(TAG, "Write Exception"); }
        }






    }

    public void fillScreen()
    {
        int[] bytes = new int[5];

        bytes[0] = 0x01;
        bytes[1] = (byte) (bytes.length+2); // packet length
        bytes[2] = 0x44; 
        bytes[3] = (byte) 0x02; 
        bytes[4] = (byte) 0x00;
    }



class ConnectThread extends Thread {


    public ConnectThread(BluetoothDevice device)
        {
            BluetoothSocket temp = null;
            mMetawatchDevice = device;
            try
            {
                //temp = btDevice.createRfcommSocketToServiceRecord(myUUID);

                Method m = mMetawatchDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
                 temp = (BluetoothSocket) m.invoke(mMetawatchDevice, 1);

            } //catch(IOException e) {  }
             catch (SecurityException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            mSocket = temp;
        }

        public void run()
        {
            mAdapter.cancelDiscovery();

            try 
            {
                if(mSocket!=null){
                    Log.d(TAG, "Attempting to Connect via Bluetooth");
                mSocket.connect();
                Log.d(TAG,"\nConnected via Bluetooth");

                mConnectedThread = new ConnectedThread(mSocket);
                mConnectedThread.start();
                Log.d(TAG, "Connected Thread Started");
                }
            }
            catch (IOException connectException)
            {
                try
                {
                    Log.d(TAG, "Attempt Close");
                    mSocket.close();
                    Log.d(TAG, "Socket Closed");
                    Log.d(TAG, "Exception : "+connectException.getMessage());
                }
                catch(IOException closeException) { Log.d(TAG, "Open and Close Failed"); }              
            }
        }

        public void cancel()
        {
            try
            {
                Log.d(TAG, "Attempting To Close ConnectingThread Socket");
                mSocket.close();
                Log.d(TAG, "ConnectingThread Socket Closed");
            }
            catch(IOException e) { Log.d(TAG, "Failed To Close ConnectThread Socket"); }
        }
    }

class ConnectedThread extends Thread {

    private final BluetoothSocket mmSocket;
    private final InputStream mmInput;
    private final OutputStream mmOutput;

    public ConnectedThread(BluetoothSocket socket)
    {
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;

        try
        {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        }
        catch(IOException e) { }

        mmInput = tmpIn;
        mmOutput = tmpOut;
    }

    public void run()
    {
        byte[] buffer = new byte[1024];
        int bytes;

        while(true)
        {
            try
            {
                bytes = mmInput.read(buffer);
                Log.d(TAG, "Received : "+bytes);
            }
            catch(IOException e) { break; }
        }
    }

    public void write(byte[] bytes)
    {  
        try
        {
            mmOutput.write(bytes);
            Log.d(TAG, "Bytes Sent");
        }
        catch (IOException e) { Log.d(TAG, "Bytes Not Sent"); }
    }

    public void cancel()
    {
        try
        {
            Log.d(TAG, "Attempting to Close ConnectedThread Socket");
            mmSocket.close();
            Log.d(TAG, "ConnectedThread Socket Closed");
        }
        catch(IOException e) { Log.d(TAG, "ConnectedThread Failed To Close"); }
    }

}




}

MetawatchConnected gets called from a different class, then right after that I send data using getBmp() from the calling class

Calling code

String address = mActiveProfile.metawatchAddressBluetooth;

      if(address != null)
      {  
          if(mMetawatchConnected == null)
          {
              mMetawatchConnected = new MetawatchConnected(address);
          }

      }

              mMetawatchConnected.getBmp();

Solution

  • It seems that you have a synchronization issue. What I had to do in my class was implement a timer. The timer basically controls everything, it checks if BT is connected, if the network is connected, etc... But my activity required long running BT / network connections, I don't think yours does.

    Why don't you add an isConnected() method to your MetawatchConnected class? After connection is complete, set it to true. Then you can:

    if (mMetawatchConnected.isConnected())
    {
    
        mMetawatchConnected.getBmp();
    }
    

    You will still have to deal with synchronization issues such as waiting for the initial connection, but I think you get the point.