2

I am creating a program used to connect to a embedded bluetooth device with a tablet/phone. My code consists largely of pieces of different code I have been given and I have found. The code dealing with the connection of bluetooth devices comes mostly from the source code for the program BlueTerm. I tried to eliminate the need for one of the given classes and have began getting some errors I don't know how to fix. This is the code for my starting Activity:

public class AndroidBluetooth extends Activity {

/** Called when the activity is first created. */
    private static BluetoothAdapter myBtAdapter;
    private static BluetoothDevice myBtDevice;
    private ArrayAdapter<String> btArrayAdapter;
    private ArrayList<BluetoothDevice> btDevicesFound = new ArrayList<BluetoothDevice>();
    private Button btnScanDevice;
    private TextView stateBluetooth;
    private ListView listDevicesFound;
    private InputStream iStream;
    private OutputStream oStream;
    private BluetoothSocket btSocket;
    private String newDeviceAddress;
    private BroadcastReceiver mReceiver;

    private static BluetoothSerialService mSerialService = null;

    // Intent request codes
    private static final int REQUEST_CONNECT_DEVICE = 1;

    private static TextView mTitle;

    // Message types sent from the BluetoothReadService Handler
    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;  

    // Name of the connected device
    private String mConnectedDeviceName = null;

    /**
    * Set to true to add debugging code and logging.
    */
    public static final boolean D = true;

    /**
     * Set to true to log each character received from the remote process to the
     * android log, which makes it easier to debug some kinds of problems with
     * emulating escape sequences and control codes.
     */
    public static final boolean LOG_CHARACTERS_FLAG = D && false;

    /**
     * Set to true to log unknown escape sequences.
     */
    public static final boolean LOG_UNKNOWN_ESCAPE_SEQUENCES = D && false;

    private static final String TAG = "ANDROID BLUETOOTH";
    private static final int REQUEST_ENABLE_BT = 2;


    // Member fields
    //private final Handler mHandler;
    private ConnectThread mConnectThread;
    private ConnectedThread mConnectedThread;
    private int mState;

    //private EmulatorView mEmulatorView;

    // 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 int currentState;

    public boolean customTitleSupported;

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        currentState = 0;
        customTitleSupported = requestWindowFeature( Window.FEATURE_CUSTOM_TITLE );
        // Set up window View
        setContentView(R.layout.main);

        stateBluetooth = new TextView(this);
        myBtAdapter = null;
        startBluetooth();
        CheckBlueToothState();

        customTitleBar( getText( R.string.app_name).toString(), stateBluetooth.getText().toString() );
    }

    public void customTitleBar( String left, String right ) {
        if( right.length() > 30 ) right = right.substring( 0, 20 );

        if( customTitleSupported ) {
            getWindow().setFeatureInt( Window.FEATURE_CUSTOM_TITLE, R.layout.customlayoutbar );
            TextView titleTvLeft = (TextView) findViewById( R.id.titleTvLeft );
            TextView titleTvRight = (TextView) findViewById( R.id.titleTvRight );

            titleTvLeft.setText( left );
            titleTvRight.setText( right );

        }
    }

    public boolean onCreateOptionsMenu( Menu menu ) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate( R.menu.option_menu, menu );
        return true;
    }

    public boolean onOptionsItemSelected( MenuItem item ) {
        switch( item.getItemId() ) {
        case R.id.connect:
            startActivityForResult( new Intent( this, DeviceList.class ), REQUEST_CONNECT_DEVICE  );
            return true;
        case R.id.preferences:
            return true;
        default:
            return super.onContextItemSelected( item );
        }
    }

    private void CheckBlueToothState() {
        if( myBtAdapter == null ) {
            stateBluetooth.setText("Bluetooth NOT supported" );
        } else {
            if( myBtAdapter.isEnabled() ) {
                if( myBtAdapter.isDiscovering() ) {
                    stateBluetooth.setText( "Bluetooth is currently " +
                        "in device discovery process." );
                } else {
                    stateBluetooth.setText( "Bluetooth is Enabled." );
                }
            } else {
                stateBluetooth.setText( "Bluetooth is NOT enabled" );
                Intent enableBtIntent = new Intent( BluetoothAdapter.ACTION_REQUEST_ENABLE );
                startActivityForResult( enableBtIntent, REQUEST_ENABLE_BT );
            }
        }
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(D) Log.d( TAG, "onActivityResult " + resultCode);
        switch (requestCode) {

        case REQUEST_CONNECT_DEVICE:

            // When DeviceListActivity returns with a device to connect
            if (resultCode == Activity.RESULT_OK) {
                // Get the device MAC address
                String address = data.getExtras()
                                 .getString(DeviceList.EXTRA_DEVICE_ADDRESS);
                // Get the BLuetoothDevice object
                BluetoothDevice device = myBtAdapter.getRemoteDevice(address);
                // Attempt to connect to the device
                connect(device);                
            }
            break;

        case REQUEST_ENABLE_BT:
            // When the request to enable Bluetooth returns
            CheckBlueToothState();
        }
    }

    public synchronized void connect(BluetoothDevice device) {
        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);
        mConnectThread.start();
        mSerialService.setState(STATE_CONNECTING);
    }

    //In SDK15 (4.0.3) this method is now public as
    //Bluetooth.fetchUuisWithSdp() and BluetoothDevice.getUuids()
    public ParcelUuid[] servicesFromDevice(BluetoothDevice device) {
        try {
            Class cl = Class.forName("android.bluetooth.BluetoothDevice");
            Class[] par = {};
            Method method = cl.getMethod("getUuids", par);
            Object[] args = {};
            ParcelUuid[] retval = (ParcelUuid[]) method.invoke(device, args);
            return retval;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private final BroadcastReceiver ActionFoundReceiver = new BroadcastReceiver() {
        public void onReceive( Context context, Intent intent ) {
            String action = intent.getAction();
            if( BluetoothDevice.ACTION_FOUND.equals( action ) ) {
                BluetoothDevice btDevice = intent.getParcelableExtra( BluetoothDevice.EXTRA_DEVICE );
                btDevicesFound.add( btDevice );
                btArrayAdapter.add( btDevice.getName() + "\n" + btDevice.getAddress() );
                btArrayAdapter.notifyDataSetChanged();
            }           
        }
    };
    public static void startBluetooth(){
        try {
            myBtAdapter = BluetoothAdapter.getDefaultAdapter();
            myBtAdapter.enable();
        } catch ( NullPointerException ex ) {
            Log.e( "Bluetooth", "Device not available" );
        }
    }

    public static void stopBluetooth() {
        myBtAdapter.disable();
    }
}

About thirty lines up in the connect() method from the bottom is where the error occurs. The line mConnectThread = new ConnectThread( device ); is underlined and the error message says this:

No enclosing instance of type BluetoothSerialService is accessible. Must qualify the allocation with an enclosing instance of type BluetoothSerialService (e.g. x.new A() where x is an instance of BluetoothSerialService).

This is the code I currently have for the BluetoothSerialService:

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


private static final UUID SerialPortServiceClass_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

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

//private EmulatorView mEmulatorView;

// 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

/**
 * Constructor. Prepares a new BluetoothChat session.
 * @param context  The UI Activity Context
 * @param handler  A Handler to send messages back to the UI Activity
 */
public BluetoothSerialService(Context context, Handler handler ) { //EmulatorView emulatorView) {
    mAdapter = BluetoothAdapter.getDefaultAdapter();
    mState = STATE_NONE;
    mHandler = handler;
    //mEmulatorView = emulatorView;
}

/**
 * Set the current state of the chat connection
 * @param state  An integer defining the current connection state
 */
public 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(AndroidBluetooth.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}

/**
 * Return the current connection state. */
public synchronized int getState() {
    return mState;
}

/**
 * Start the chat service. Specifically start AcceptThread to begin a
 * session in listening (server) mode. Called by the Activity onResume() */
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_NONE);
}

/**
 * Start the ConnectThread to initiate a connection to a remote device.
 * @param device  The BluetoothDevice to connect
 */
public synchronized void connect(BluetoothDevice device) {
    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);
    mConnectThread.start();
    setState(STATE_CONNECTING);
}

/**
 * Start the ConnectedThread to begin managing a Bluetooth connection
 * @param socket  The BluetoothSocket on which the connection was made
 * @param device  The BluetoothDevice that has been connected
 */
public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
    if (D) Log.d(TAG, "connected");

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

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

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

    setState(STATE_CONNECTED);
}

/**
 * Stop all threads
 */
public synchronized void stop() {
    if (D) Log.d(TAG, "stop");


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

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

    setState(STATE_NONE);
}

/**
 * Write to the ConnectedThread in an unsynchronized manner
 * @param out The bytes to write
 * @see ConnectedThread#write(byte[])
 */
public void write(byte[] out) {
    // Create temporary object
    ConnectedThread r;
    // Synchronize a copy of the ConnectedThread
    synchronized (this) {
        if (mState != STATE_CONNECTED) return;
        r = mConnectedThread;
    }
    // Perform the write unsynchronized
    r.write(out);
}

/**
 * Indicate that the connection attempt failed and notify the UI Activity.
 */
private void connectionFailed() {
    setState(STATE_NONE);

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

/**
 * Indicate that the connection was lost and notify the UI Activity.
 */
private void connectionLost() {
    setState(STATE_NONE);

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

/**
 * This thread runs while attempting to make an outgoing connection
 * with a device. It runs straight through; the connection either
 * succeeds or fails.
 */
public class ConnectThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final BluetoothDevice mmDevice;

    public ConnectThread(BluetoothDevice device) {
        mmDevice = device;
        BluetoothSocket tmp = null;

        // Get a BluetoothSocket for a connection with the
        // given BluetoothDevice
        try {
            tmp = device.createRfcommSocketToServiceRecord(SerialPortServiceClass_UUID);
        } catch (IOException e) {
            Log.e(TAG, "create() failed", e);
        }
        mmSocket = tmp;
    }

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

        // 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) {
            connectionFailed();
            // Close the socket
            try {
                mmSocket.close();
            } catch (IOException e2) {
                Log.e(TAG, "unable to close() socket during connection failure", e2);
            }
            // Start the service over to restart listening mode
            //BluetoothSerialService.this.start();
            return;
        }

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

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

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

/**
 * This thread runs during a connection with a remote device.
 * It handles all incoming and outgoing transmissions.
 */
public class ConnectedThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;


    public ConnectedThread(BluetoothSocket socket) {
        Log.d(TAG, "create ConnectedThread");
        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);

                //mEmulatorView.write(buffer, bytes);
                // Send the obtained bytes to the UI Activity
                //mHandler.obtainMessage(BlueTerm.MESSAGE_READ, bytes, -1, buffer).sendToTarget();

                String a = buffer.toString();
                a = "";
            } catch (IOException e) {
                Log.e(TAG, "disconnected", e);
                connectionLost();
                break;
            }
        }
    }

    /**
     * Write to the connected OutStream.
     * @param buffer  The bytes to write
     */
    public void write(byte[] buffer) {
        try {
            mmOutStream.write(buffer);

            // Share the sent message back to the UI Activity
            //mHandler.obtainMessage(BlueTerm.MESSAGE_WRITE, buffer.length, -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);
        }
    }
}
}
Wesley Wiser
  • 9,491
  • 4
  • 50
  • 69
JuiCe
  • 4,132
  • 16
  • 68
  • 119
  • If anyone has any advice about how to clean my code I would also appreciate it. I am still uncomfortable with the structure of Android applications, especially ones including bluetooth. I know that this is organized extremely poorly. – JuiCe Jun 14 '12 at 13:42

1 Answers1

6

Is the BluetoothSerialService an inner class? If so, make it static.

See this post

No enclosing instance of type Server is accessible

Community
  • 1
  • 1
stuckless
  • 6,515
  • 2
  • 19
  • 27
  • The BluetoothSerialService object I create is static. – JuiCe Jun 14 '12 at 14:09
  • not the object... but the class... `public static class BluetoothSerialService` – stuckless Jun 14 '12 at 14:16
  • And now that I look back, this may relate to what you're saying. ConnectThread is an inner class of BluetoothSerialService. Should I make ConnectThread static? – JuiCe Jun 14 '12 at 14:17
  • Eclipse won't let me make the entire class static, it gets an error and the only option is "Remove valid modifiers." When I press that, static is removed. – JuiCe Jun 14 '12 at 14:21
  • What is the other error... basically if you have a static class then you cannot access local members of the parent class any longer... so typically you need to restructure the code to accept an instance of the parent object in the other class. This gets a lot less confusing to newer developers, if you put each class in a separate file, (which is like making it static), since you can clearly see what you can and cannot access. Ie, you may need to accept an instance of the other class in the constructor if you are accessing fields, etc. – stuckless Jun 14 '12 at 14:40