I am trying to sent message from android client to Mac OS X over bluetooth.
I am using bluecove 2.0.1 Java bluetooth library on Mac OS X Snow Leopard.
Code for Server:
public class EchoServer2 {
private static final String UUID_STRING = "00001101-0000-1000-8000-00805F9B34FB"; // 32 hex digits
private static final String SERVICE_NAME = "echoserver";
private LocalDevice mLocalDevice;
public EchoServer2() {
try {
mLocalDevice = LocalDevice.getLocalDevice();
} catch(IOException e) {
System.err.print("Error connection to bluetooth");
}
}
public void start() throws IOException {
StreamConnectionNotifier connectionNotifier =
(StreamConnectionNotifier) Connector.open(
"btspp://localhost:" + UUID_STRING +
";name=" + SERVICE_NAME + ";authenticate=false");
System.out.println("Bluetooth Address: " + mLocalDevice.getBluetoothAddress());
System.out.println("Waiting for a connection...");
StreamConnection streamConnection = connectionNotifier.acceptAndOpen();
System.out.println("Found a new device.");
RemoteDevice device = RemoteDevice.getRemoteDevice(streamConnection);
System.out.println("New Device connected: " + device.getFriendlyName(false).toString());
DataInputStream is = streamConnection.openDataInputStream();
byte[] bytes = new byte[1024];
int r;
while((r = is.read(bytes)) > 0) {
System.out.println(new String(bytes, 0, r));
}
}
}
Code for Android client:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
EditText editText;
TextView textView;
String send_msg;
String rcv_msg;
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); // 32 hex digits
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate");
editText = (EditText) findViewById(R.id.edit_msg);
textView = (TextView) findViewById(R.id.rcv_msg);
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if(adapter == null) {
textView.append("Bluetooth NOT Supported!");
return;
}
// Request user to turn ON Bluetooth
if(!adapter.isEnabled()) {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, RESULT_OK);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
public void onClick(View view) {
Log.d(TAG, "onClick");
new SendMessageToServer().execute(send_msg);
}
private class SendMessageToServer extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... msg) {
Log.d(TAG, "doInBackground");
BluetoothSocket clientSocket = null;
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mBluetoothAdapter.enable();
// Client knows the server MAC address
BluetoothDevice mmDevice = mBluetoothAdapter.getRemoteDevice("00:25:00:C3:1C:FE");
Log.d(TAG, "got hold of remote device");
Log.d(TAG, "remote device: " + mmDevice.getName().toString());
try {
// UUID string same used by server
clientSocket = mmDevice.createInsecureRfcommSocketToServiceRecord(MY_UUID);
Log.d(TAG, "bluetooth socket created");
mBluetoothAdapter.cancelDiscovery(); // Cancel, discovery slows connection
clientSocket.connect();
Log.d(TAG, "connected to server");
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
DataOutputStream out = new DataOutputStream(clientSocket.getOutputStream());
out.writeUTF(msg[0]); // Send message to server
Log.d(TAG, "Message Successfully sent to server");
return in.readUTF(); // Read response from server
} catch (Exception e) {
Log.d(TAG, "Error creating bluetooth socket");
Log.d(TAG, e.getMessage());
return "";
}
}
#Override
protected void onPostExecute(String result) {
Log.d(TAG, "onPostExecute");
rcv_msg = result;
textView.setText(rcv_msg);
}
}
}
I am not able to connect to server even though the UUID are same both for client and server.
Android throws an exception: Service Discovery failed.
However I am able to print the name of remote device (client) on the server. Hence acceptAndOpen() is unable to accept the socket connection.
Please help me in understanding as to why I am unable to clientSocket.connect(); on android ?
Im gonna take a guess and say it has something to do with the UUID numbers you used. They depend solely on the type of device you use. So make sure you look those up and that they are correct for the android device. When i was doing android this stumped me for a long time.
UUID is not something you set.
Here is a link
How can I get the UUID of my Android phone in an application?
Or this
Android - Get Bluetooth UUID for this device
If that is not it.
Did discovery fail on both ends? can you see the device on either end? Which side can you print the name?
You might want to take a look at google's bluetooth sample program. And use that to get you started.
Related
I create app which work with bluetooth and almost everything is ok but one this is not cool. So after I connect device do some staff save everything them disconnect it, my app stops seeing this device is no more on my list, but after 5-10 minutes device back on the list. What can be the issue?
public class MainActivity extends AppCompatActivity {
static final int SEND_TIMES = 1;
static final int SEND_DATE = 2;
List<BluetoothDevice> devices;
Spinner devicesSpinner = null;
BluetoothAdapter bluetoothAdapter = null;
BluetoothSocket clientSocket = null;
OutputStream outputData = null;
InputStream inputData = null;
List<String> devicesNames = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (!bluetoothAdapter.isEnabled()) {
Intent enableRequest = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivity(enableRequest);
}
findDevices();
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(deviceFoundReceiver, filter);
registerReceiver(bondStateChangeReceiver, filter);
devices = new ArrayList();
devicesSpinner = findViewById(R.id.devices_list);
devicesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
try {
if(devices.get(i) == null)
return;
BluetoothDevice remoteDevice = bluetoothAdapter.getRemoteDevice(devices.get(i).getAddress());
Method m = remoteDevice.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
clientSocket = (BluetoothSocket) m.invoke(remoteDevice, 1);
outputData = clientSocket.getOutputStream();
inputData = clientSocket.getInputStream();
} catch (Exception e){
Log.i("REMOTE_DEVICE", "No such a method", e);
}
}
#Override
public void onNothingSelected (AdapterView<?> adapterView){
}
});
if(clientSocket != null)
Toast.makeText(this, "" + clientSocket.isConnected(), Toast.LENGTH_LONG);
}
public void connectDevice(View view) throws IOException {
if (isSocketConnected()) return;
bluetoothAdapter.cancelDiscovery();
if(!clientSocket.isConnected()){
try {
clientSocket.connect();
} catch (Exception e){
Toast.makeText(this, "Can not connect to this device try later!", Toast.LENGTH_LONG).show();
return;
}
TextView textView = (TextView) findViewById(R.id.boundedDevice);
textView.setText(clientSocket.getRemoteDevice().getName());
}
}
public void disconnectDevice(View view) throws IOException {
if(clientSocket.isConnected()){
clientSocket.close();
TextView textView = (TextView) findViewById(R.id.boundedDevice);
textView.setText("Device not connected");
}
}
}
That is my code which I am using for connection, what is wrong?
What I want to have is I would like to have my device straight away on my list after disconnection, to not waiting those 5-10 mins to let my app find it again.
This is client-side code and you need server-side code.So you need two device and one device must be a server another device must be a client.If you want to search available device you work in server side.First of all you must look at android developer bluetooth chat project in the official site.Then find out server-side code.
https://developer.android.com/samples/BluetoothChat/project.html
I am trying to develop an android application that can exchange data on peer to peer connection with other devices without server. So please suggest how can I do this. Thank you in advance.
This is a complete code for chat by SocketProgramming without server.
In my Application, first you are a client and you search for a server. When you do not find any server, you become a server and wait for a client.
public class MainActivity extends ActionBarActivity {
private Handler handler = new Handler();
private TextView text;
private EditText input;
private Button send;
private Socket socket;
private DataOutputStream outputStream;
private BufferedReader inputStream;
private String DeviceName = "Device";
private boolean searchNetwork() {
log("Connecting");
String range = "192.168.56.";
for (int i = 1; i <= 255; i++) {
String ip = range + i;
try {
socket = new Socket();
socket.connect(new InetSocketAddress(ip, 9000), 50);
outputStream = new DataOutputStream(socket.getOutputStream());
inputStream = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
DeviceName += "1";
Log.i("Server", DeviceName);
log("Connected");
return true;
} catch (Exception e) {
}
}
return false;
}
private void runNewChatServer() {
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(9000);
log("Waiting for client...");
socket = serverSocket.accept();
DeviceName += "2";
log("a new client Connected");
} catch (IOException e) {
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.text);
input = (EditText) findViewById(R.id.input);
send = (Button) findViewById(R.id.send);
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
if (!searchNetwork()) {
runNewChatServer();
}
outputStream = new DataOutputStream(
socket.getOutputStream());
inputStream = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
while (true) {
String Message = inputStream.readLine();
if (Message != null) {
log(Message);
}
}
} catch (IOException e) {
log("Error: IO Exception");
e.printStackTrace();
}
}
});
send.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
if (outputStream == null) {
return;
}
try {
String Message = input.getText().toString() + "\n";
outputStream.write(Message.getBytes());
log2(input.getText().toString());
} catch (IOException e) {
e.printStackTrace();
}
input.setText("");
}
});
thread.start();
}
private void log(final String message) {
handler.post(new Runnable() {
String DeviceName2="";
#Override
public void run() {
if (DeviceName.equals("Device1")) {
DeviceName2 = "Device2";
}else if(DeviceName.equals("Device2")) {
DeviceName2 = "Device1";
}else{
DeviceName2 = "UnknowDevice";
}
text.setText(text.getText() + "\n" + DeviceName2 + " :"
+ message);
}
});
}
private void log2(final String message) {
handler.post(new Runnable() {
#Override
public void run() {
text.setText(text.getText() + "\n" + "you" + " :"
+ message);
}
});
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.exit(0);
return true;
}
return super.onKeyDown(keyCode, event);
}
}
Your design has a big problem : ...
If there is no central server some android devices should act as client and others as server but this will not work in some situations:
When the mobile telephony provider assigns private and non-public IP
When the device is connected to a Wi-Fi network but no NAT rule is defined on the router.
In both cases the problem is that the listening port of the device that must act as server is unreachable.
Java provides ServerSocket and Socket to communicate b/w devices. One of the device you can make as server and other device you can make as client and communicate b/w 'em without introducing server hosted on some machine.
The Other and better option is Using Wi-Fi Peer-to-Peer. WifiP2pManager help you to achieve your purpose.Here is an example.
If you're looking for such P2P over a local network, there are two parts to it:
Discovering peers
Communicating with peers
Among Android APIs, you can either use Network Service Discovery APIs for this or Wifi P2P Service Discovery APIs.
There's a wrapper library which which uses these internally and has comparatively better documentation - Salut, which can also be used.
I also created a library for P2P - Near, which uses sockets directly. The problem I was facing with Android APIs was that discovery wasn't happening with certainty every time and the underlying issue was unknown.
If you're looking for P2P across the internet, socket IO is a prevalent solution. Even Near should be able to facilitate the transfers if you provide the IP addresses and they're not behind NAT firewalls.
I am using Bluetooth API of android. I am here creating client-server connection using BluetoothServerSocket & BluetoothSocket but my program stuck at the certain point.
// Create a BroadcastReceiver for ACTION_FOUND
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery find a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// get the BluetoothDevice object from the Intent
BluetoothDevice mBluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.i("MainActivity", "Device Name: " + mBluetoothDevice.getName() + " Address: " + mBluetoothDevice.getAddress());
new AcceptThread().start();
}
}
};
private class AcceptThread extends Thread {
private BluetoothServerSocket mBluetoothServerSocket ;
public AcceptThread() {
try {
mBluetoothServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("BT_SERVER", UUID.fromString("a60f35f0-b93a-11de-8a39-08002009c666"));
} catch (IOException e) {
Log.e("MainActivity", e.getMessage());
}
}
#Override
public void run() {
BluetoothSocket mBluetoothSocket;
// Keep listening until exception occurs or a socket is returned
while(true) {
try {
mBluetoothSocket = mBluetoothServerSocket.accept();
} catch (IOException e) {
break;
}
// If a connection was accepted
if(mBluetoothSocket != null) {
// transfer the data here
Toast.makeText(MainActivity.this, "Socket is created", Toast.LENGTH_LONG).show();;
try {
// close the connection to stop to listen any connection now
mBluetoothSocket.close();
} catch(IOException e) { }
}
}
}
}
Here my program stuck
mBluetoothServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("BT_SERVER", UUID.fromString("a60f35f0-b93a-11de-8a39-08002009c666"));
I could not catch why it getting stuck at this point, Any idea to you for this ?
From your question it is unclear whether your application is a client or server or both. For writing bluetooth client-server applications, android phone at any instance plays a single role of server or a client. If your phone is server, then you need to listen for connections from other bluetooth devices using method listenUsingRfcommWithServiceRecord(). Then use accept() to complete the connection.
In case android phone acts as client, it will initiate a bluetooth connection to other devices. For such scenario, your broadcast receiver is needed. We need to scan for available bluetooth devices with startDiscovery() method. Your broadcast receiver's onReceive() is called when a new bluetooth device is found. To connect to this found device, call createRfcommSocketToServiceRecord() with desired UUID.
Hope this helps.
This may be obvious but did you instantiate your BluetoothAdapter? Accept Thread uses the adapter without intializing it.
myBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
While listening, set the discovery name to a specific value then used listenUsingRfcommWithServiceRecord method in broadcast receiver.
private class AcceptTask extends AsyncTask<UUID,Void,BluetoothSocket> {
#Override
protected BluetoothSocket doInBackground(UUID... params) {
String name = mBtAdapter.getName();
try {
//While listening, set the discovery name to a specific value
mBtAdapter.setName(SEARCH_NAME);
BluetoothServerSocket socket = mBtAdapter.listenUsingRfcommWithServiceRecord("BluetoothRecipe", params[0]);
BluetoothSocket connected = socket.accept();
//Reset the BT adapter name
mBtAdapter.setName(name);
return connected;
} catch (IOException e) {
e.printStackTrace();
mBtAdapter.setName(name);
return null;
}
}
#Override
protected void onPostExecute(BluetoothSocket socket) {
if(socket == null) {
return;
}
mBtSocket = socket;
ConnectedTask task = new ConnectedTask();
task.execute(mBtSocket);
}
}
// End
i want to search and listing bluetooth devices in android, my program now able to list all the active devices but not able to send pairing request to the other devices .I want to implement this onItemClick of list element.And also if bluetooth is not enabled of my device then show a permission to active device,if i go for yes then ok,but if i go for no then permission show again until i press yes..how can i do this?plz help with code..here is my code..
public class Main extends Activity {
TextView out;
private static final int REQUEST_ENABLE_BT = 1;
private BluetoothAdapter btAdapter;
private ArrayList<BluetoothDevice> btDeviceList = new ArrayList<BluetoothDevice>();
private ArrayList<String> mylist= new ArrayList<String>();
private ListView lv;
private Button btn;
public Parcelable[] uuidExtra;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void search(View view)
{
//Register the BroadcastReceiver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothDevice.ACTION_UUID);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(ActionFoundReceiver, filter); // Don't forget to unregister during onDestroy
// Getting the Bluetooth adapter
btAdapter = BluetoothAdapter.getDefaultAdapter();
Toast.makeText(getApplicationContext(),"\nAdapter: " + btAdapter,5000).show();
CheckBTState();
}
private void setDeviceList(ArrayList<String> list) {
lv = (ListView) findViewById(R.id.listView);
ArrayAdapter<String> adapter= new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,list);
lv.setAdapter(adapter);
}
/* This routine is called when an activity completes.*/
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_ENABLE_BT) {
CheckBTState();
}
}
#Override
protected void onDestroy() {
super.onDestroy();
if (btAdapter != null) {
btAdapter.cancelDiscovery();
}
unregisterReceiver(ActionFoundReceiver);
}
private void CheckBTState() {
// Check for Bluetooth support and then check to make sure it is turned on
// If it isn't request to turn it on
// List paired devices
// Emulator doesn't support Bluetooth and will return null
if(btAdapter==null) {
Toast.makeText(getApplicationContext(),"\nBluetooth NOT supported. Aborting.",5000).show();
return;
} else {
if (btAdapter.isEnabled()) {
Toast.makeText(getApplicationContext(),"\nBluetooth is enabled...",5000).show();
// Starting the device discovery
btAdapter.startDiscovery();
} else if (!btAdapter.isEnabled()){
Intent enableBtIntent = new Intent(btAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
/* else{
Intent intent = new Intent(btAdapter.ACTION_STATE_CHANGED);
startActivityForResult(intent, RESULT_CANCELED);
}*/
}
}
private final BroadcastReceiver ActionFoundReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Toast.makeText(getApplicationContext(),"\n Device: " + device.getName() + ", " + device,5000).show();
mylist.add(device.getName());
setDeviceList(mylist);
} else {
if(BluetoothDevice.ACTION_UUID.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Parcelable[] uuidExtra = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID);
for (int i=0; i<uuidExtra.length; i++) {
Toast.makeText(getApplicationContext(),"\n Device: " + device.getName() + ", " + device + ", Service: " + uuidExtra[i].toString(),5000).show();
}
} else {
if(BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
Toast.makeText(getApplicationContext(),"\nDiscovery Started...",5000).show();
} else {
if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
Toast.makeText(getApplicationContext(),"\nDiscovery Finished",5000).show();
Iterator<BluetoothDevice> itr = btDeviceList.iterator();
while (itr.hasNext()) {
// Get Services for paired devices
BluetoothDevice device = itr.next();
Toast.makeText(getApplicationContext(),"\nGetting Services for " + device.getName() + ", " + device,5000).show();
if(!device.fetchUuidsWithSdp()) {
Toast.makeText(getApplicationContext(),"\nSDP Failed for " + device.getName(),5000).show();
}
}
}
}
}
}
}
};
}
It's too late but here is code -> You need to use background thread to connect with bluetooth device as a client. and UUID is Universal Uniquely identification you can use online UUID generator. for secure connections and then get socket with device and connect with it;
ConnectWithDevice(context : ConnectWithBluetooth, device : BluetoothDevice) : Thread(){
private val mContext : ConnectWithBluetooth = context
private val mmSocket : BluetoothSocket
private val mmDevice : BluetoothDevice
// Default UUID
private val mmDefaultUUID = UUID.fromString("78c374fd-f84d-4a9e-aa5b-9b0b6292952e")
init {
var temp : BluetoothSocket? = null
mmDevice = device
try {
// Try here device.createInsecureConnect if it's work then start with this;
temp = device.createRfcommSocketToServiceRecord(mmDevice.uuids[0].uuid)
}catch (en : NullPointerException){
en.printStackTrace()
// Try here device.createInsecureConnect if it's work then start with this;
temp = device.createRfcommSocketToServiceRecord(mmDefaultUUID)
}catch (e : IOException){
e.printStackTrace()
Log.e("TAG","Socket's create() method failed",e)
}
mmSocket = temp!!
Log.i("TAG","Got the Socket")
}
override fun run() {
// Cancel discovery because it otherwise slows down the connection.
if(mContext.bluetoothAdapter != null){
mContext.bluetoothAdapter!!.cancelDiscovery()
}
try{
// Connect to the remote device through the socket. This call blocks
// until it succeeds or throws an exception.
Log.i("TAG","Connecting...")
mmSocket.connect()
Log.i("TAG","Bluetooth Successfully Connected")
}catch (connectException : IOException){
// Unable to connect; close the socket and return.
try{
mmSocket.close()
}catch (closeException : IOException){
Log.e("TAG","Could not close the client socket",closeException)
}
return
}
// The connection attempt succeeded. Perform work associated with
// the connection in a separate thread.
Log.i("TAG","Device is Connected")
//manageMyConnectedSocket(mmSocket)
}
// Closes the client socket and causes the thread to finish.
// Call this method from the main activity to shut down the connection.
fun cancel(){
try {
mmSocket.close()
} catch (e: IOException) {
Log.e(ContentValues.TAG, "Could not close the client socket", e)
}
}
}
This is my first question in SO. I am new (and excited) in Android programming and here is my PROBLEM: I am building a project using my android phone and a microcontroller. The microcontroller has a distance sensor and transmits its value. I have managed to get connected to the microcontroller and send correct signals, but I can't get the distance mesurment, or anything else. The application doesn't crash or anything it just won't get the data from the microcontroller (my computer gets the data from microcontroler (data is a string)). My code from the android app is this:
public class Accelerometer extends Activity {
// Intent request codes
private static final int REQUEST_CONNECT_DEVICE = 1;
private static final int REQUEST_ENABLE_BT = 2;
private static final int RECIEVE_MESSAGE = 3;
// Program variables
private byte microcOut;
private boolean ledStat;
private boolean connectStat = false;
private Button btnled;
private Button connect_button;
private TextView yAccel, xAccel, incoming;
protected static final int MOVE_TIME = 80;
private long lastWrite = 0;
OnClickListener myClickListener;
ProgressDialog myProgressDialog;
private Toast failToast;
private Handler mHandler,h;
private StringBuilder sb = new StringBuilder();
// Sensor object used to handle accelerometer
private SensorManager mySensorManager;
private List<Sensor> sensors;
private Sensor accSensor;
// Bluetooth Stuff
private BluetoothAdapter btAdapter = null;
private BluetoothSocket btSocket = null;
private OutputStream outStream = null;
private InputStream inStream = null;
private ConnectThread mConnectThread = null;
private ConnectedThread mConnectedThread;
private String deviceAddress = null;
// Well known SPP UUID (will *probably* map to RFCOMM channel 1 (default) if not in use);
private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
//Sound Clip to make app prettier
MediaPlayer myclip;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_accelerometer);
myclip = MediaPlayer.create(this, R.raw.cartcar);
myclip.start();
// Finds buttons in .xml layout file
btnled = (Button) findViewById(R.id.led_button1);
connect_button = (Button) findViewById(R.id.connect_button1);
yAccel = (TextView) findViewById(R.id.accText1);
xAccel = (TextView) findViewById(R.id.accText2);
incoming = (TextView) findViewById(R.id.incoming);
// Set Sensor
mySensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
sensors = mySensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
if(sensors.size() > 0) accSensor = sensors.get(0);
myProgressDialog = new ProgressDialog(this);
failToast = Toast.makeText(this, R.string.failedToConnect, Toast.LENGTH_SHORT);
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (myProgressDialog.isShowing()) {
myProgressDialog.dismiss();
}
// Check if bluetooth connection was made to selected device
if (msg.what == 1) {
// Set button to display current status
connectStat = true;
connect_button.setText(R.string.connected);
// Reset the BluCar
microcOut = 0;
ledStat = false;
write(microcOut);
}else {
// Connection failed
failToast.show();
}
}
};
h = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case RECIEVE_MESSAGE: // if receive massage
byte[] readBuf = (byte[]) msg.obj;
String strIncom = new String(readBuf, 0, msg.arg1); // create string from bytes array
sb.append(strIncom); // append string
int endOfLineIndex = sb.indexOf("\r\n"); // determine the end-of-line
if (endOfLineIndex > 0) { // if end-of-line,
String sbprint = sb.substring(0, endOfLineIndex); // extract string
sb.delete(0, sb.length()); // and clear
incoming.setText("Data from Arduino: " + sbprint); // update TextView
}
//Log.d(TAG, "...String:"+ sb.toString() + "Byte:" + msg.arg1 + "...");
break;
}
};
};
// Check whether bluetooth adapter exists
btAdapter = BluetoothAdapter.getDefaultAdapter();
if (btAdapter == null) {
Toast.makeText(this, R.string.no_bt_device, Toast.LENGTH_LONG).show();
finish();
return;
}
// If BT is not on, request that it be enabled.
if (!btAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
/**********************************************************************
* Buttons for controlling BluCar
*/
connect_button.setOnClickListener(new View.OnClickListener() {
// Connect to Bluetooth Module
#Override
public void onClick(View v) {
if (connectStat) {
// Attempt to disconnect from the device
disconnect();
}else{
// Attempt to connect to the device
connect();
}
}
});
// Toggle Headlights
btnled.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (ledStat) {
microcOut = (byte) (microcOut & 124);
btnled.setText(R.string.ledbuttonON);
ledStat = false;
}else{
microcOut = (byte) (microcOut | 128);
btnled.setText(R.string.ledbuttonOFF);
ledStat = true;
}
write(microcOut);
}
});
}
/** Thread used to connect to a specified Bluetooth Device */
public class ConnectThread extends Thread {
private String address;
private boolean connectionStatus;
ConnectThread(String MACaddress) {
address = MACaddress;
connectionStatus = true;
}
public void run() {
// When this returns, it will 'know' about the server,
// via it's MAC address.
try {
BluetoothDevice device = btAdapter.getRemoteDevice(address);
// We need two things before we can successfully connect
// (authentication issues aside): a MAC address, which we
// already have, and an RFCOMM channel.
// Because RFCOMM channels (aka ports) are limited in
// number, Android doesn't allow you to use them directly;
// instead you request a RFCOMM mapping based on a service
// ID. In our case, we will use the well-known SPP Service
// ID. This ID is in UUID (GUID to you Microsofties)
// format. Given the UUID, Android will handle the
// mapping for you. Generally, this will return RFCOMM 1,
// but not always; it depends what other BlueTooth services
// are in use on your Android device.
try {
btSocket = device.createRfcommSocketToServiceRecord(SPP_UUID);
} catch (IOException e) {
connectionStatus = false;
}
}catch (IllegalArgumentException e) {
connectionStatus = false;
}
// Discovery may be going on, e.g., if you're running a
// 'scan for devices' search from your handset's Bluetooth
// settings, so we call cancelDiscovery(). It doesn't hurt
// to call it, but it might hurt not to... discovery is a
// heavyweight process; you don't want it in progress when
// a connection attempt is made.
btAdapter.cancelDiscovery();
// Blocking connect, for a simple client nothing else can
// happen until a successful connection is made, so we
// don't care if it blocks.
try {
btSocket.connect();
} catch (IOException e1) {
try {
btSocket.close();
} catch (IOException e2) {
}
}
// Create a data stream so we can talk to server.
try {
outStream = btSocket.getOutputStream();
} catch (IOException e2) {
connectionStatus = false;
}
// Send final result
if (connectionStatus) {
mHandler.sendEmptyMessage(1);
}else {
mHandler.sendEmptyMessage(0);
}
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CONNECT_DEVICE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
// Show please wait dialog
myProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.pleaseWait), getResources().getString(R.string.makingConnectionString), true);
// Get the device MAC address
deviceAddress = data.getExtras().getString(DeviceList.EXTRA_DEVICE_ADDRESS);
// Connect to device with specified MAC address
mConnectThread = new ConnectThread(deviceAddress);
mConnectThread.start();
}else {
// Failure retrieving MAC address
Toast.makeText(this, R.string.macFailed, Toast.LENGTH_SHORT).show();
}
break;
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK) {
// Bluetooth is now enabled
} else {
// User did not enable Bluetooth or an error occured
Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
finish();
}
}
}
public void write(byte data) {
if (outStream != null) {
try {
outStream.write(data);
} catch (IOException e) {
}
}
}
public void emptyOutStream() {
if (outStream != null) {
try {
outStream.flush();
} catch (IOException e) {
}
}
}
public void connect() {
// Launch the DeviceListActivity to see devices and do scan
Intent serverIntent = new Intent(this, DeviceList.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
}
public void disconnect() {
if (outStream != null) {
try {
outStream.close();
connectStat = false;
connect_button.setText(R.string.disconnected);
} catch (IOException e) {
}
}
}
private final SensorEventListener mSensorListener = new SensorEventListener() {
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
#Override
public void onSensorChanged(SensorEvent event) {
// Checks whether to send steering command or not
long date = System.currentTimeMillis();
if (date - lastWrite > MOVE_TIME) {
yAccel.setText(" " + event.values[1]);
xAccel.setText(" " + event.values[0]);
if (event.values[1] > 2.5) {
// Turn right
microcOut = (byte) (microcOut & 248);
microcOut = (byte) (microcOut | 4);
}else if (event.values[1] < -2.5) {
// Turn left
microcOut = (byte) (microcOut & 244);
microcOut = (byte) (microcOut | 8);
}else {
// Center the steering servo
microcOut = (byte) (microcOut & 240);
}
write(microcOut);
lastWrite = date;
}
}
};
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_accelerometer, menu);
return true;
}
public void onResume() {
super.onResume();
mySensorManager.registerListener(mSensorListener, accSensor, SensorManager.SENSOR_DELAY_GAME);
}
#Override
public void onDestroy() {
emptyOutStream();
disconnect();
if (mSensorListener != null) {
mySensorManager.unregisterListener(mSensorListener);
}
super.onDestroy();
myclip.release();
}
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[256]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer); // Get number of bytes and message in "buffer"
h.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget(); // Send to message queue Handler
} catch (IOException e) {
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(String message) {
byte[] msgBuffer = message.getBytes();
try {
mmOutStream.write(msgBuffer);
} catch (IOException e) {
}
}
}
}
I have read everything over the subject (BluetoothChat, projects of people on the internet ...) and I am very tired. Any help is much appreciated.
--EDIT--
I have managed to get the inputstream into my texteview. My problem now is that my application when it is trying to connect to my device (microcontroller or my pc) gets stuck in the progressdialog (it is connected to the device but the progressdialog will not go away)and waits for something to come in. After a while (like 5-6 secs) even if something comes in it remains stuck and I have to force it to close. I think the problem is in the way the handler handles the thread. In the debugger there is no problem all threads run ok.
The changes in my code are:
In my ConnectThread:
`/** Thread used to connect to a specified Bluetooth Device */
public class ConnectThread extends Thread {
private String address;
private boolean connectionStatus;
ConnectThread(String MACaddress) {
address = MACaddress;
connectionStatus = true;
}
public void run() {
// When this returns, it will 'know' about the server,
// via it's MAC address.
try {
BluetoothDevice device = btAdapter.getRemoteDevice(address);
// We need two things before we can successfully connect
// (authentication issues aside): a MAC address, which we
// already have, and an RFCOMM channel.
// Because RFCOMM channels (aka ports) are limited in
// number, Android doesn't allow you to use them directly;
// instead you request a RFCOMM mapping based on a service
// ID. In our case, we will use the well-known SPP Service
// ID. This ID is in UUID (GUID to you Microsofties)
// format. Given the UUID, Android will handle the
// mapping for you. Generally, this will return RFCOMM 1,
// but not always; it depends what other BlueTooth services
// are in use on your Android device.
try {
btSocket = device.createRfcommSocketToServiceRecord(SPP_UUID);
} catch (IOException e) {
connectionStatus = false;
}
}catch (IllegalArgumentException e) {
connectionStatus = false;
}
// Discovery may be going on, e.g., if you're running a
// 'scan for devices' search from your handset's Bluetooth
// settings, so we call cancelDiscovery(). It doesn't hurt
// to call it, but it might hurt not to... discovery is a
// heavyweight process; you don't want it in progress when
// a connection attempt is made.
btAdapter.cancelDiscovery();
// Blocking connect, for a simple client nothing else can
// happen until a successful connection is made, so we
// don't care if it blocks.
try {
btSocket.connect();
} catch (IOException e1) {
try {
btSocket.close();
} catch (IOException e2) {
}
}
// Create a data stream so we can talk to server.
try {
outStream = btSocket.getOutputStream();
} catch (IOException e2) {
connectionStatus = false;
}
try{
inStream = btSocket.getInputStream();
}catch (IOException e2){
connectionStatus = false;
}
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (connectionStatus) {
try {
byte[] b = new byte[64]; // buffer store for the stream
// Read from the InputStream
bytes = inStream.read(b); // Get number of bytes and message in "buffer"
mHandler.obtainMessage(RECIEVE_MESSAGE, bytes, -1, b).sendToTarget(); // Send to message queue Handler
} catch (IOException e) {
break;
}
}
// Send final result
if (connectionStatus) {
mHandler.obtainMessage(1);
}else {
mHandler.sendEmptyMessage(0);
}
}
}
`
And in my mHandler in my onCreate method:
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (myProgressDialog.isShowing()) {
myProgressDialog.dismiss();
}
// Check if bluetooth connection was made to selected device
if (msg.what == 1) {
// Set button to display current status
connectStat = true;
connect_button.setText(R.string.connected);
// Reset the BluCar
microcOut = 0;
ledStat = false;
write(microcOut);
}else if (msg.what == 2){
byte[] readBuf = (byte[]) msg.obj;
String strIncom = new String(readBuf, 0, msg.arg1); // create string from bytes array
sb.append(strIncom); // append string
int endOfLineIndex = sb.indexOf("."); // determine the end-of-line
if (endOfLineIndex > 0) { // if end-of-line,
String sbprint = sb.substring(0, endOfLineIndex); // extract string
sb.delete(0, sb.length()); // and clear
incoming.setText(sbprint); // update TextView
connectStat = true;
connect_button.setText(R.string.connected);
}else{
incoming.setText("Problem!");
}
}else {
// Connection failed
failToast.show();
}
}
};
Another thing I need is how to empty the buffer when it is full.
PS: Thanks EVERYONE for his/her help I am really grateful.
As an alternative to using the handler, just get the information in the run of the thread..
I have done it this way and it works for me.
public void run() {
byte[] buffer = new byte[128]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
bytes = mmInStream.read(buffer);
byte[] readBuf = (byte[]) buffer;
String strIncom = new String(readBuf, 0, bytes); // create string from bytes array
sb.append(strIncom); // append string
int endOfLineIndex = sb.indexOf("\r\n"); // determine the end-of-line
if (endOfLineIndex > 0) {
// add the current string to eol to a local string
String sbprint = sb.substring(0, endOfLineIndex);
// get the start and end indexes of the heading
int startHeading = sb.indexOf("HE");
int endHeading = sb.indexOf("/HE");
// set the heading
Henry.this.setCurrentHeading(sb.substring((startHeading + 2), endHeading));
// get the start and end indexes of the front range
int startFrontRange = sb.indexOf("FR");
int endFrontRange = sb.indexOf("/FR");
// get the front range
Henry.this.currentFrontRange = sb.substring((startFrontRange + 2), endFrontRange);
... ( grab all the information you need here ) ...
// debugging output what we have
// System.out.println("recv: " + sbprint);
// clean out the sb to ready next run
sb.delete(0, sb.length());
}
I save all the information retrieved from the serial connection in my Application (Henry), then any Activity that wants to use the info gets it from the application. If the view needs to have a updated perspective on the information, I add a timer to the view to kick of a refresh method as often as I like. This has the added advantage of being able to use the information from anywhere in your android application.
I send about 10 data points from the arduino to the device and about 3 data points from the device to the arduino this way. I added my own markup around the datapoints to identify them.
Hope this helps!