I am working on a singleton BluetoothHelper class. In connectToBTDevice() method, a new thread is invoked and in the thread, bluetooth socket is trying to connect to a bluetooth device. Unfortunately, it starts fine, but exits with a warning System.err as followed:
04-11 20:46:15.711 2848-2848/? D/BluetoothHelper﹕ Connecting...name: Zakariya , address: 84:55:A5:8C:2E:2A
04-11 20:46:17.710 2848-3300/? W/System.err﹕ at com.prome.bluetoothdevicecontroller.helpers.BluetoothHelper.run(BluetoothHelper.java:262)
04-11 20:46:17.710 2848-3300/? D/BluetoothHelper﹕ could not connect to device
04-11 20:46:17.718 2848-3300/? D/BluetoothHelper﹕ socket closed
BluetoothHelper.java
package com.prome.bluetoothdevicecontroller.helpers;
import android.app.Activity;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import com.prome.bluetoothdevicecontroller.activities.MainActivity;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Set;
import java.util.UUID;
/**
* Bluetooth helper class
*
* #author Md. Nabid Imteaj
* #version 1.0
* #see android.bluetooth.BluetoothAdapter
* #see http://developer.android.com/guide/topics/connectivity/bluetooth.html
*/
public class BluetoothHelper implements Runnable {
// tag
public static final String TAG = "BluetoothHelper";
// make it singleton
private static BluetoothHelper bluetoothHelper = null;
// bluetooth adapter
private static BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// local integer > 0, taking random int which may not conflict
// with other requestCode
public static final int REQUEST_ENABLE_BT = 1001;
// save found bluetooth devices in range
ArrayList<BluetoothDevice> foundDevices = new ArrayList<>();
// progress dialog
ProgressDialog progress;
// socket
private BluetoothSocket mBluetoothSocket;
private BluetoothServerSocket mBluetoothServerSocket;
// uuid
private UUID uuid = UUID.randomUUID();
// bluetooth device
private BluetoothDevice bluetoothDevice;
// save context
private Context context;
// constructor
private BluetoothHelper(Context context) {
this.context = context;
}
/**
* Returns new instance if not created, previous instance otherwise
*
* #return bluetoothHelper
*/
public static BluetoothHelper getInstance(Context context) {
if(bluetoothHelper == null) bluetoothHelper = new BluetoothHelper(context);
return bluetoothHelper;
}
/**
* Checks the device is Bluetooth supported or not
*
* #return true if the device is Bluetooth supported, false otherwise
*/
public boolean isBluetoothSupported() {
if(bluetoothAdapter == null) return false;
return true;
}
/**
* Enables Bluetooth
*
* #param context
* #see android.app.Activity
*/
public void enableBluetooth(Activity context) {
if(!bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
// note: onActivityResult() must be implemented in the parent activity
// in our case it is defined in MainActivity
context.startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
// save context for future use
//this.context = context;
}
}
/**
* Returns paired devices connected with this device
*
* #return deviceList
*/
public ArrayList<BluetoothDevice> getPairedDevices() {
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
ArrayList<BluetoothDevice> deviceList = new ArrayList<>();
// check has paired devices or not
if(pairedDevices.size() > 0) {
// initiate array list
//deviceList = new ArrayList<>();
// get names, address and its type
for(BluetoothDevice device : pairedDevices) {
//deviceList.add(device.getName() + "\n" + device.getAddress());
deviceList.add(device);
}
}
return deviceList;
}
/**
* Disables bluetooth
*/
public void disableBluetooth() {
bluetoothAdapter.disable();
}
/**
* Cancel discovering devices
* Must add it in onDestroy() of an activity or fragment
*/
public void cancelDiscovery(Context context) {
// if bluetooth is supported and is discovering devices
// then cancel discovering devices
if(bluetoothAdapter != null && bluetoothAdapter.isDiscovering()) {
bluetoothAdapter.cancelDiscovery();
// unregister receiver
context.unregisterReceiver(mReceiver);
}
}
/**
* Start discovering bluetooth devices in range
*
* #param context
*/
public void startDiscovery(Context context) {
// get a new IntentFilter
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
// register broadcast receiver
context.registerReceiver(mReceiver, filter);
bluetoothAdapter.startDiscovery();
}
private void showProgress(Context context, String message) {
progress = new ProgressDialog(context);
progress.setMessage(message);
progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progress.setIndeterminate(true);
progress.setCancelable(false);
progress.setCanceledOnTouchOutside(false);
progress.show();
}
private void hideProgress() {
if(progress.isShowing()) {
progress.dismiss();
}
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
//discovery starts, we can show progress dialog or perform other tasks
Log.d(BluetoothHelper.TAG, "discovery started");
// clear previous list
foundDevices.clear();
// show loading dialog
showProgress(context, "Scanning devices...");
} else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
//discovery finishes, dismis progress dialog
Log.d(BluetoothHelper.TAG, "discovery finished");
// hide progress dialog
hideProgress();
// show found devices
((MainActivity) context).startDeviceListDialog("Paired Devices", foundDevices);
} else if(BluetoothDevice.ACTION_FOUND.equals(action)) {
//bluetooth device found
BluetoothDevice device = (BluetoothDevice) intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// insert this device into foundDevice array list
foundDevices.add(device);
//showToast("Found device " + device.getName());
Log.d(BluetoothHelper.TAG, "found: " + device.getName() + ", " + device.getAddress());
}
}
};
/**
* Returns found devices by searching in range
*
* #return ArrayList<BluetoothDevice>
*/
public ArrayList<BluetoothDevice> getFoundDevices() {
return foundDevices;
}
public void connectToBTDevice(BluetoothDevice device) {
// get bluetooth device by address
bluetoothDevice = bluetoothAdapter.getRemoteDevice(device.getAddress());
// show dialog connecting
showProgress(context, "Connecting..."+"\n"+device.getName()+"\n"+device.getAddress());
Log.d(BluetoothHelper.TAG, "Connecting..."+"name: "+device.getName()+", address: "+device.getAddress());
// create new thread
Thread bluetoothConnectThread = new Thread(this);
// start thread
bluetoothConnectThread.start();
//pairToDevice(mBluetoothDevice); This method is replaced by progress dialog with thread
}
// thread to connect with bluetooth device
#Override
public void run() {
try {
// open socket
uuid = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
mBluetoothSocket = bluetoothDevice.createRfcommSocketToServiceRecord(uuid);
// cancel discovering
//cancelDiscovery(context);
// already cancelled
// connect through socket
mBluetoothSocket.connect();
Log.d(BluetoothHelper.TAG, "connected to device");
// send empty message
//mHandler.sendEmptyMessage(0);
} catch(IOException e) {
e.printStackTrace();
Log.d(BluetoothHelper.TAG, "could not connect to device");
//hide progress bar
hideProgress();
// close the socket
try {
mBluetoothSocket.close();
Log.d(BluetoothHelper.TAG, "socket closed");
} catch(IOException e1) {
e1.printStackTrace();
Log.d(BluetoothHelper.TAG, "socket could not be closed");
}
}
}
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
hideProgress();
Log.d(BluetoothHelper.TAG, "connected with device");
}
};
/**
* make the device discoverable within 300 seconds
*/
public void makeDiscoverable() {
// create new intent
Intent discoverableIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
context.startActivity(discoverableIntent);
}
}
onnectToBTDevice(BluetoothDevice device) method is at line 234. BluetoothSocket connect() method does not work for both paired and unpaired devices.
Your are exiting the thread after making a connection. In your run method, you need to get the inputStream and outputStream of your socket to read and write data.
// thread to connect with bluetooth device
#Override
public void run() {
try {
// open socket
uuid = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
mBluetoothSocket = bluetoothDevice.createRfcommSocketToServiceRecord(uuid);
// cancel discovering
//cancelDiscovery(context);
// already cancelled
// connect through socket
mBluetoothSocket.connect();
Log.d(BluetoothHelper.TAG, "connected to device");
InputStream mmInStream;
OutputStream mmOutStream;
// Get the BluetoothSocket input and output streams
try
{
mmInStream = socket.getInputStream();
mmOutStream = socket.getOutputStream();
}
catch (IOException e)
{
Log.e(TAG, "error getting streams", e);
return;
}
byte[] buffer = new byte[1024];
int bytes;
//* use the mmOutStream to write to the other end
//* but use the mmInSteam to read from the other end
// Keep listening to the InputStream while connected
while (true)
{
try
{
// Read from the InputStream
bytes = mmInStream.read(buffer);
/* do something with the bytes,
..............................
}
catch (IOException e)
{
Log.e(TAG, "disconnected", e);
connectionLost();
break;
}
}
// send empty message
//mHandler.sendEmptyMessage(0);
} catch(IOException e) {
e.printStackTrace();
Log.d(BluetoothHelper.TAG, "could not connect to device");
//hide progress bar
hideProgress();
// close the socket
try {
mBluetoothSocket.close();
Log.d(BluetoothHelper.TAG, "socket closed");
} catch(IOException e1) {
e1.printStackTrace();
Log.d(BluetoothHelper.TAG, "socket could not be closed");
}
}
}
Related
Currently I've been using this reference http://blog.lemberg.co.uk/how-guide-obdii-reader-app-development but I am still confused on what the next steps are for my Android app to be able to connect to the OBDII. I found code online for a simple bluetooth app. The app is able to form bluetooth connections with other Android phones but not with the OBDII.
public class MainActivity extends Activity {
Button b1,b2,b3,b4;
private BluetoothAdapter BA;
private Set<BluetoothDevice>pairedDevices;
ListView lv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b1 = (Button) findViewById(R.id.button);
b2=(Button)findViewById(R.id.button2);
b3=(Button)findViewById(R.id.button3);
b4=(Button)findViewById(R.id.button4);
BA = BluetoothAdapter.getDefaultAdapter();
lv = (ListView)findViewById(R.id.listView);
}
public void on(View v) {
if (!BA.isEnabled()) {
Intent turnOn = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(turnOn, 0);
Toast.makeText(getApplicationContext(), "Turned on", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(), "Already on", Toast.LENGTH_LONG).show();
}
}
public void off(View v) {
BA.disable();
Toast.makeText(getApplicationContext(), "Turned off", Toast.LENGTH_LONG).show();
}
public void visible(View v) {
Intent getVisible = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
startActivityForResult(getVisible, 0);
}
public void list(View v) {
pairedDevices = BA.getBondedDevices();
ArrayList list = new ArrayList();
for (BluetoothDevice bt : pairedDevices) list.add(bt.getName());
Toast.makeText(getApplicationContext(), "Showing Paired Devices", Toast.LENGTH_SHORT).show();
final ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, list);
lv.setAdapter(adapter);
}
Moving forward, what must be done in order for the app to be able to successfully establish and maintain a bluetooth connection with the OBDII.
Check android-obd-reader OBDII example, which helps you to connect OBDII with your device.
It is using OBD-II Java API to connect and read data from obd.
Using below classes you can manage connection and read data from obd.
BluetoothManager.java : It's helps you to connect device
public class BluetoothManager {
private static final String TAG = BluetoothManager.class.getName();
/*
* http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html
* #createRfcommSocketToServiceRecord(java.util.UUID)
*
* "Hint: If you are connecting to a Bluetooth serial board then try using the
* well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB. However if you
* are connecting to an Android peer then please generate your own unique
* UUID."
*/
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
/**
* Instantiates a BluetoothSocket for the remote device and connects it.
* <p/>
* See http://stackoverflow.com/questions/18657427/ioexception-read-failed-socket-might-closed-bluetooth-on-android-4-3/18786701#18786701
*
* #param dev The remote device to connect to
* #return The BluetoothSocket
* #throws IOException
*/
public static BluetoothSocket connect(BluetoothDevice dev) throws IOException {
BluetoothSocket sock = null;
BluetoothSocket sockFallback = null;
Log.d(TAG, "Starting Bluetooth connection..");
try {
sock = dev.createRfcommSocketToServiceRecord(MY_UUID);
sock.connect();
} catch (Exception e1) {
Log.e(TAG, "There was an error while establishing Bluetooth connection. Falling back..", e1);
Class<?> clazz = sock.getRemoteDevice().getClass();
Class<?>[] paramTypes = new Class<?>[]{Integer.TYPE};
try {
Method m = clazz.getMethod("createRfcommSocket", paramTypes);
Object[] params = new Object[]{Integer.valueOf(1)};
sockFallback = (BluetoothSocket) m.invoke(sock.getRemoteDevice(), params);
sockFallback.connect();
sock = sockFallback;
} catch (Exception e2) {
Log.e(TAG, "Couldn't fallback while establishing Bluetooth connection.", e2);
throw new IOException(e2.getMessage());
}
}
return sock;
}
}
ObdGatewayService.java : It have connection code and reading data from obd.
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;
import com.github.pires.obd.commands.protocol.EchoOffCommand;
import com.github.pires.obd.commands.protocol.LineFeedOffCommand;
import com.github.pires.obd.commands.protocol.ObdResetCommand;
import com.github.pires.obd.commands.protocol.SelectProtocolCommand;
import com.github.pires.obd.commands.protocol.TimeoutCommand;
import com.github.pires.obd.commands.temperature.AmbientAirTemperatureCommand;
import com.github.pires.obd.enums.ObdProtocols;
import com.github.pires.obd.exceptions.UnsupportedCommandException;
import com.github.pires.obd.reader.R;
import com.github.pires.obd.reader.activity.ConfigActivity;
import com.github.pires.obd.reader.activity.MainActivity;
import com.github.pires.obd.reader.io.ObdCommandJob.ObdCommandJobState;
import com.google.inject.Inject;
import java.io.File;
import java.io.IOException;
/**
* This service is primarily responsible for establishing and maintaining a
* permanent connection between the device where the application runs and a more
* OBD Bluetooth interface.
* <p/>
* Secondarily, it will serve as a repository of ObdCommandJobs and at the same
* time the application state-machine.
*/
public class ObdGatewayService extends AbstractGatewayService {
private static final String TAG = ObdGatewayService.class.getName();
#Inject
SharedPreferences prefs;
private BluetoothDevice dev = null;
private BluetoothSocket sock = null;
public void startService() throws IOException {
Log.d(TAG, "Starting service..");
// get the remote Bluetooth device
final String remoteDevice = prefs.getString(ConfigActivity.BLUETOOTH_LIST_KEY, null);
if (remoteDevice == null || "".equals(remoteDevice)) {
Toast.makeText(ctx, getString(R.string.text_bluetooth_nodevice), Toast.LENGTH_LONG).show();
// log error
Log.e(TAG, "No Bluetooth device has been selected.");
// TODO kill this service gracefully
stopService();
throw new IOException();
} else {
final BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
dev = btAdapter.getRemoteDevice(remoteDevice);
/*
* Establish Bluetooth connection
*
* Because discovery is a heavyweight procedure for the Bluetooth adapter,
* this method should always be called before attempting to connect to a
* remote device with connect(). Discovery is not managed by the Activity,
* but is run as a system service, so an application should always call
* cancel discovery even if it did not directly request a discovery, just to
* be sure. If Bluetooth state is not STATE_ON, this API will return false.
*
* see
* http://developer.android.com/reference/android/bluetooth/BluetoothAdapter
* .html#cancelDiscovery()
*/
Log.d(TAG, "Stopping Bluetooth discovery.");
btAdapter.cancelDiscovery();
showNotification(getString(R.string.notification_action), getString(R.string.service_starting), R.drawable.ic_btcar, true, true, false);
try {
startObdConnection();
} catch (Exception e) {
Log.e(
TAG,
"There was an error while establishing connection. -> "
+ e.getMessage()
);
// in case of failure, stop this service.
stopService();
throw new IOException();
}
showNotification(getString(R.string.notification_action), getString(R.string.service_started), R.drawable.ic_btcar, true, true, false);
}
}
/**
* Start and configure the connection to the OBD interface.
* <p/>
* See http://stackoverflow.com/questions/18657427/ioexception-read-failed-socket-might-closed-bluetooth-on-android-4-3/18786701#18786701
*
* #throws IOException
*/
private void startObdConnection() throws IOException {
Log.d(TAG, "Starting OBD connection..");
isRunning = true;
try {
sock = BluetoothManager.connect(dev);
} catch (Exception e2) {
Log.e(TAG, "There was an error while establishing Bluetooth connection. Stopping app..", e2);
stopService();
throw new IOException();
}
// Let's configure the connection.
Log.d(TAG, "Queueing jobs for connection configuration..");
queueJob(new ObdCommandJob(new ObdResetCommand()));
//Below is to give the adapter enough time to reset before sending the commands, otherwise the first startup commands could be ignored.
try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
queueJob(new ObdCommandJob(new EchoOffCommand()));
/*
* Will send second-time based on tests.
*
* TODO this can be done w/o having to queue jobs by just issuing
* command.run(), command.getResult() and validate the result.
*/
queueJob(new ObdCommandJob(new EchoOffCommand()));
queueJob(new ObdCommandJob(new LineFeedOffCommand()));
queueJob(new ObdCommandJob(new TimeoutCommand(62)));
// Get protocol from preferences
final String protocol = prefs.getString(ConfigActivity.PROTOCOLS_LIST_KEY, "AUTO");
queueJob(new ObdCommandJob(new SelectProtocolCommand(ObdProtocols.valueOf(protocol))));
// Job for returning dummy data
queueJob(new ObdCommandJob(new AmbientAirTemperatureCommand()));
queueCounter = 0L;
Log.d(TAG, "Initialization jobs queued.");
}
/**
* This method will add a job to the queue while setting its ID to the
* internal queue counter.
*
* #param job the job to queue.
*/
#Override
public void queueJob(ObdCommandJob job) {
// This is a good place to enforce the imperial units option
job.getCommand().useImperialUnits(prefs.getBoolean(ConfigActivity.IMPERIAL_UNITS_KEY, false));
// Now we can pass it along
super.queueJob(job);
}
/**
* Runs the queue until the service is stopped
*/
protected void executeQueue() throws InterruptedException {
Log.d(TAG, "Executing queue..");
while (!Thread.currentThread().isInterrupted()) {
ObdCommandJob job = null;
try {
job = jobsQueue.take();
// log job
Log.d(TAG, "Taking job[" + job.getId() + "] from queue..");
if (job.getState().equals(ObdCommandJobState.NEW)) {
Log.d(TAG, "Job state is NEW. Run it..");
job.setState(ObdCommandJobState.RUNNING);
if (sock.isConnected()) {
job.getCommand().run(sock.getInputStream(), sock.getOutputStream());
} else {
job.setState(ObdCommandJobState.EXECUTION_ERROR);
Log.e(TAG, "Can't run command on a closed socket.");
}
} else
// log not new job
Log.e(TAG,
"Job state was not new, so it shouldn't be in queue. BUG ALERT!");
} catch (InterruptedException i) {
Thread.currentThread().interrupt();
} catch (UnsupportedCommandException u) {
if (job != null) {
job.setState(ObdCommandJobState.NOT_SUPPORTED);
}
Log.d(TAG, "Command not supported. -> " + u.getMessage());
} catch (IOException io) {
if (job != null) {
if(io.getMessage().contains("Broken pipe"))
job.setState(ObdCommandJobState.BROKEN_PIPE);
else
job.setState(ObdCommandJobState.EXECUTION_ERROR);
}
Log.e(TAG, "IO error. -> " + io.getMessage());
} catch (Exception e) {
if (job != null) {
job.setState(ObdCommandJobState.EXECUTION_ERROR);
}
Log.e(TAG, "Failed to run command. -> " + e.getMessage());
}
if (job != null) {
final ObdCommandJob job2 = job;
((MainActivity) ctx).runOnUiThread(new Runnable() {
#Override
public void run() {
((MainActivity) ctx).stateUpdate(job2);
}
});
}
}
}
/**
* Stop OBD connection and queue processing.
*/
public void stopService() {
Log.d(TAG, "Stopping service..");
notificationManager.cancel(NOTIFICATION_ID);
jobsQueue.clear();
isRunning = false;
if (sock != null)
// close socket
try {
sock.close();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
// kill service
stopSelf();
}
public boolean isRunning() {
return isRunning;
}
public static void saveLogcatToFile(Context context, String devemail) {
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
emailIntent.setType("text/plain");
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{devemail});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "OBD2 Reader Debug Logs");
StringBuilder sb = new StringBuilder();
sb.append("\nManufacturer: ").append(Build.MANUFACTURER);
sb.append("\nModel: ").append(Build.MODEL);
sb.append("\nRelease: ").append(Build.VERSION.RELEASE);
emailIntent.putExtra(Intent.EXTRA_TEXT, sb.toString());
String fileName = "OBDReader_logcat_" + System.currentTimeMillis() + ".txt";
File sdCard = Environment.getExternalStorageDirectory();
File dir = new File(sdCard.getAbsolutePath() + File.separator + "OBD2Logs");
if (dir.mkdirs()) {
File outputFile = new File(dir, fileName);
Uri uri = Uri.fromFile(outputFile);
emailIntent.putExtra(Intent.EXTRA_STREAM, uri);
Log.d("savingFile", "Going to save logcat to " + outputFile);
//emailIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(Intent.createChooser(emailIntent, "Pick an Email provider").addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
try {
#SuppressWarnings("unused")
Process process = Runtime.getRuntime().exec("logcat -f " + outputFile.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
I hope it helps you. Please leave comment or edit your question if more help require.
I'm looking for a way to send data between my Android Device and Google Glass that doesn't rely on Cloud API's. Is this supported? I see the Bluetooth connections in the My Glass app, which makes me think it can be done. Is there an example source code that shows how this is done? Or do I have to decompile the MyGlass app to figure it out?
Is there a preferred method for doing this kind of data transfer? Ideally I'd like to transfer data in both directions.
Ok, for the requesters....
EDIT: The code below still works, but I've put it into a git repo for those who are interested...
https://github.com/NathanielWaggoner/GoogleGlassBlutooth
Here is my Bluetooth Host/Client code. It's not perfect - You're going to need some patience, and there are some bugs on reconnection and such, but it does work. I've been sending data up to Glass From the Hand Held and driving UI updates (publishing live cards, updating live cards etc...) for about three days using this now.
Host:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.UUID;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.widget.TextView;
public class BluetoothHost extends Activity {
public static String msgToSend="";
public static final int STATE_CONNECTION_STARTED = 0;
public static final int STATE_CONNECTION_LOST = 1;
public static final int READY_TO_CONN = 2;
public static final String DEVICE_NAME = "device_name";
public static final String TOAST = "toast";
// our last connection
ConnectedThread mConnectedThread;// = new ConnectedThread(socket);
// track our connections
ArrayList<ConnectedThread> mConnThreads;
// bt adapter for all your bt needs (where we get all our bluetooth powers)
BluetoothAdapter myBt;
// list of sockets we have running (for multiple connections)
ArrayList<BluetoothSocket> mSockets = new ArrayList<BluetoothSocket>();
// list of addresses for devices we've connected to
ArrayList<String> mDeviceAddresses = new ArrayList<String>();
// just a name, nothing more...
String NAME="G6BITCHES";
// We can handle up to 7 connections... or something...
UUID[] uuids = new UUID[2];
// some uuid's we like to use..
String uuid1 = "05f2934c-1e81-4554-bb08-44aa761afbfb";
String uuid2 = "c2911cd0-5c3c-11e3-949a-0800200c9a66";
// just a tag..
String TAG = "G6 Bluetooth Host Activity";
// constant we define and pass to startActForResult (must be >0), that the system passes back to you in your onActivityResult()
// implementation as the requestCode parameter.
int REQUEST_ENABLE_BT = 1;
AcceptThread accThread;
TextView connectedDevices;
Handler handle;
BroadcastReceiver receiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// the activity for this is pretty stripped, just a basic selection ui....
setContentView(R.layout.activity_main);
uuids[0] = UUID.fromString(uuid1);
uuids[1] = UUID.fromString(uuid2);
connectedDevices = (TextView) findViewById(R.id.connected_devices_values);
handle = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case STATE_CONNECTION_STARTED:
connectedDevices.setText(msg.getData().getString("NAMES"));
break;
case STATE_CONNECTION_LOST:
connectedDevices.setText("");
startListening();
break;
case READY_TO_CONN:
startListening();
default:
break;
}
}
};
// ....
myBt = BluetoothAdapter.getDefaultAdapter();
// run the "go get em" thread..
accThread = new AcceptThread();
accThread.start();
}
public void startListening() {
if(accThread!=null) {
accThread.cancel();
}else if (mConnectedThread!= null) {
mConnectedThread.cancel();
} else {
accThread = new AcceptThread();
accThread.start();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private class AcceptThread extends Thread {
private BluetoothServerSocket mmServerSocket;
BluetoothServerSocket tmp;
public AcceptThread() {
BluetoothServerSocket tmp = null;
try {
tmp = myBt.listenUsingInsecureRfcommWithServiceRecord(NAME, uuids[0]);
} catch (IOException e) { }
mmServerSocket = tmp;
}
public void run() {
Log.e(TAG,"Running?");
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned
while (true) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
e.printStackTrace();
break;
}
// If a connection was accepted
if (socket != null) {
try {
mmServerSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Do work to manage the connection (in a separate thread)
manageConnectedSocket(socket);
break;
}
}
}
/** Will cancel the listening socket, and cause the thread to finish */
public void cancel() {
try {
mmServerSocket.close();
Message msg = handle.obtainMessage(READY_TO_CONN);
handle.sendMessage(msg);
} catch (IOException e) { }
}
}
private void manageConnectedSocket(BluetoothSocket socket) {
// start our connection thread
mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
// Send the name of the connected device back to the UI Activity
// so the HH can show you it's working and stuff...
String devs="";
for(BluetoothSocket sock: mSockets) {
devs+=sock.getRemoteDevice().getName()+"\n";
}
// pass it to the UI....
Message msg = handle.obtainMessage(STATE_CONNECTION_STARTED);
Bundle bundle = new Bundle();
bundle.putString("NAMES", devs);
msg.setData(bundle);
handle.sendMessage(msg);
}
private 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 {
//byte[] blah = ("System Time:" +System.currentTimeMillis()).getBytes();
if(!msgToSend.equals("")) {
Log.e(TAG,"writing!");
write(msgToSend.getBytes());
setMsg("");
}
Thread.sleep(1000);
} catch (Exception e) {
Log.e(TAG, "disconnected", e);
connectionLost();
}
}
}
public void connectionLost() {
Message msg = handle.obtainMessage(STATE_CONNECTION_LOST);
handle.sendMessage(msg);
}
/**
* Write to the connected OutStream.
* #param buffer The bytes to write
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
connectionLost();
}
}
public void cancel() {
try {
mmSocket.close();
Message msg = handle.obtainMessage(READY_TO_CONN);
handle.sendMessage(msg);
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
public static synchronized void setMsg(String newMsg) {
msgToSend = newMsg;
}
public static class HostBroadRec extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle b= intent.getExtras();
String vals ="";
for(String key: b.keySet()) {
vals+=key+"&"+b.getString(key)+"Z";
}
BluetoothHost.setMsg(vals);
}
}
}
Client:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Set;
import java.util.UUID;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
public class BluetoothClient extends Activity {
public static final int READY_TO_CONN =0;
public static final int CANCEL_CONN =1;
public static final int MESSAGE_READ =2;
// holds the bluetooth names/ids that we're associated with.
ArrayAdapter<String> btArray;
// bt adapter for all your bt needs
BluetoothAdapter myBt;
String NAME="G6BITCHES";
String TAG = "G6 Bluetooth Slave Activity";
UUID[] uuids = new UUID[2];
// some uuid's we like to use..
String uuid1 = "05f2934c-1e81-4554-bb08-44aa761afbfb";
String uuid2 = "c2911cd0-5c3c-11e3-949a-0800200c9a66";
// DateFormat df = new DateFormat("ddyyyy")
ConnectThread mConnThread;
Spinner devices;
Handler handle;
// constant we define and pass to startActForResult (must be >0), that the system passes back to you in your onActivityResult()
// implementation as the requestCode parameter.
int REQUEST_ENABLE_BT = 1;
// bc for discovery mode for BT...
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// Add the name and address to an array adapter to show in a ListView
if(device!= null) {
if(device.getName().contains("Nexus")) {
} else {
btArray.add(device.getName() + "\n" + device.getAddress());
}
}
update();
}
}
};
Context ctx;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// publishCards(this);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
ctx = this;
handle = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case READY_TO_CONN:
mConnThread=null;
update();
break;
case CANCEL_CONN:
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.e(TAG,"received: "+readMessage);
if (readMessage.length() > 0) {
// do soemthing...
}
// updateCards(ctx, readMessage);
// update()
// mConversationArrayAdapter.add(mConnectedDeviceName+": " + readMessage);
break;
default:
break;
}
}
};
btArray = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, android.R.id.text1);
btArray.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
uuids[0] = UUID.fromString(uuid1);
uuids[1] = UUID.fromString(uuid2);
// spinner for displaying available devices for pairing
devices = (Spinner) findViewById(R.id.devices_spinner);
devices.setAdapter(btArray);
// use the same UUID across an installation
// should allow clients to find us repeatedly
myBt = BluetoothAdapter.getDefaultAdapter();
if (myBt == null) {
Toast.makeText(this, "Device Does not Support Bluetooth", Toast.LENGTH_LONG).show();
}
else if (!myBt.isEnabled()) {
// we need to wait until bt is enabled before set up, so that's done either in the following else, or
// in the onActivityResult for our code ...
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
} else {
detectAndSetUp();
}
setContentView(R.layout.bluetooth_activity_layout);
}
#Override
public void onDestroy() {
unregisterReceiver(mReceiver);
super.onDestroy();
}
#Override
protected void onActivityResult (int requestCode, int resultCode, Intent data){
if(requestCode == REQUEST_ENABLE_BT) {
if (resultCode != RESULT_OK) {
Toast.makeText(this, "Failed to enable Bluetooth", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "Bluetooth Enabled", Toast.LENGTH_LONG).show();
detectAndSetUp();
}
}
}
private void detectAndSetUp() {
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
Set<BluetoothDevice> pairedDevices = myBt.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
if(device.getName().contains("Nexus")) {
} else {
btArray.add(device.getName() + "\n" + device.getAddress());
}
// Add the name and address to an array adapter to show in a ListView
// btArray.add(device.getName() + "\n" + device.getAddress());
// update();
}
}
myBt.startDiscovery();
}
public void update() {
devices = (Spinner) findViewById(R.id.devices_spinner);
devices.setAdapter(btArray);
devices.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int position, long id) {
if(mConnThread!=null) {
Log.e(TAG,"Canceling old connection, and starting new one.");
mConnThread.cancel();
} else {
Log.e(TAG,"got a thing...");
String str = ((TextView)arg1).getText().toString();
Log.e(TAG,"tots: "+str);
String[] vals = str.split("\n");
Log.e(TAG,"mac: "+vals[1]);
BluetoothDevice dev = myBt.getRemoteDevice(vals[1]);
mConnThread = new ConnectThread(dev);
mConnThread.run();
}
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.bluetooth, menu);
return true;
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
Log.e(TAG,"ConnectThread start....");
// Use a temporary object that is later assigned to mmSocket,
// because mmSocket is final
BluetoothSocket tmp = null;
mmDevice = device;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// this seems to work on the note3...
// you can remove the Insecure if you want to...
tmp = device.createInsecureRfcommSocketToServiceRecord(uuids[0]);
// Method m;
// this is an approach I've seen others use, it wasn't nescesary for me,
// but your results may vary...
// m = device.getClass().getMethod("createInsecureRfcommSocket", new Class[] {int.class});
// tmp = (BluetoothSocket) m.invoke(device, 1);
// } catch (NoSuchMethodException e1) {
// // TODO Auto-generated catch block
// e1.printStackTrace();
// } catch (IllegalArgumentException e2) {
// // TODO Auto-generated catch block
// e2.printStackTrace();
// } catch (IllegalAccessException e3) {
// // TODO Auto-generated catch block
// e3.printStackTrace();
// } catch (InvocationTargetException e4) {
// // TODO Auto-generated catch block
// e4.printStackTrace();
// }
// if(tmp.isConnected()) {
// break
// }
} catch (Exception e) {
Log.e(TAG,"Danger Will Robinson");
e.printStackTrace();
}
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
myBt.cancelDiscovery();
Log.e(TAG,"stopping discovery");
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
Log.e(TAG,"connecting!");
mmSocket.connect();
} catch (IOException connectException) {
Log.e(TAG,"failed to connect");
// Unable to connect; close the socket and get out
try {
Log.e(TAG,"close-ah-da-socket");
mmSocket.close();
} catch (IOException closeException) {
Log.e(TAG,"failed to close hte socket");
}
Log.e(TAG,"returning..");
return;
}
Log.e(TAG,"we can now manage our connection!");
// Do work to manage the connection (in a separate thread)
manageConnectedSocket(mmSocket);
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
Message msg = handle.obtainMessage(READY_TO_CONN);
handle.sendMessage(msg);
} catch (IOException e) { }
}
}
public void manageConnectedSocket(BluetoothSocket mmSocket) {
ConnectedThread t = new ConnectedThread(mmSocket);
t.start();
// manage your socket... I'll probably do a lot of the boiler plate here later
}
private 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 {
// byte[] blah = ("System Time:" +System.currentTimeMillis()).getBytes();
// write(blah);
// Thread.sleep(1000);
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
handle.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
// .sendToTarget();
} catch (Exception e) {
Log.e(TAG, "disconnected", e);
connectionLost();
// break;
}
}
}
public void connectionLost() {
Message msg = handle.obtainMessage(CANCEL_CONN);
// Bundle bundle = new Bundle();
// bundle.putString("NAMES", devs);
// msg.setData(bundle);
handle.sendMessage(msg);
}
/**
* 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(BluetoothChat.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);
}
}
}
}
Host Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="transapps.android_bluetooth_host"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="7"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name="transapps.android_bluetooth_host.BluetoothHost"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".BluetoothHost$HostBroadRec" >
<intent-filter>
<action android:name="transapps.g6.new.alert" />
</intent-filter>
</receiver>
</application>
</manifest>
Client Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="transapps.android_blutooth"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name="transapps.android_blutooth.BluetoothClient"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I'll leave the UI as an exercise to the reader.
There is no preferred method, but if you're looking to do it wirelessly, a Bluetooth 3.0 RFCOMM does work.
If you provide more specifics about the problem you're trying to solve in your question, I'll be able to provide a more specific answer.
Several things I noticed when following this solution (awesome work by the way!)
1) I could only create a bluetooth connection when my phone and the Google Glass were not already paired through the MyGlass app - If you are having trouble establishing a connection, try forgetting that pairing.
2) The Glass API does not support controlling your bluetooth connection through intents using commands like
Intent discoveryIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoveryIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, DISCOVER_DURATION);
startActivityForResult(discoveryIntent, REQUEST_BLU);
In order to make the Glass headset discoverable (rather than the phone it is connecting to), I needed to follow solutions similar to those like user4934624 provided at this question and shantanu gave at this question. I invoked a hidden method to access bluetooth functionality directly. Warning: the hidden method seems to have been there for years, but there is no guarantee it will continue to be in future APIs.
// this method allows us to make the device discoverable without alerting the users
// NOTE!!!! This uses a hidden method, so it may be removed from the API in the future
public void makeDiscoverable (){
Class <?> baClass = BluetoothAdapter.class;
Method[] methods = baClass.getDeclaredMethods();
// we want to use method setScanMode(int mode, int duration)
// there are 2 setScanModes
// so select the first setScanMode you see
// test to see which method is the one we want
//for (int i = 0; i<50; i++) {Log.d(Integer.toString(i), methods[i].getName());}
//I had trouble calling the first setScanMode, so I called the second.
// I need to pass in a discoverable time, but it stays discoverable indefinitely
// Thus you must turn off the setScanMode as soon as the connection is established
// I should probably write in some other security stuff to turn it off if connection fails
// maybe a timer running on a different thread?
Method mSetScanMode = methods[38];
try {
mSetScanMode.invoke(myBt, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE,300);
//mSetScanMode.invoke(myBt, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
} catch (Exception e) {
Log.e("discoverable", e.getMessage());
}
}
// this method allows us to make the device not discoverable without alerting the user
// NOTE!!!! This uses a hidden method, so it may be removed from the API in the future
public void makeNotDiscoverable (){
// see notes for makeDiscoverable
Class <?> baClass = BluetoothAdapter.class;
Method [] methods = baClass.getDeclaredMethods();
Method mSetScanMode = methods[38];
try {
mSetScanMode.invoke(myBt, BluetoothAdapter.SCAN_MODE_CONNECTABLE,300);
} catch (Exception e) {
Log.e("discoverable", e.getMessage());
}
}
Note that I first ran a test that output the names of all the methods in the class I mirrored; that allowed me to narrow my search for which method I wanted to use.
The JoeGlass app for android claims to be a replacement for MyGlass. It will talk to your glass directly, using a bluetooth connection. I have not tried yet it but it is open source (github), so if it works, you are good.
My book Beginning Google Glass Development has a full chapter on this topic, with fully working example code on using Bluetooth and socket to transfer data between Glass and Android (or iOS) devices.
The book is available at amazon: http://www.amazon.com/Beginning-Google-Glass-Development-Jeff/dp/1430267887
and the source code is available for download at http://www.apress.com/downloadable/download/sample/sample_id/1562/
There are two different instances of my program not being about to connect to a BluetoothServerSocket.
One of the instances has only 1 UUID generated randomly before it initiates scan mode with SCAN_MODE_CONNECTABLE_DISCOVERABLE and before using the same generated UUID to create a BluetoothServerSocket for listening. The other intance generates a random UUID just before a BluetoothDevice tries to connect with the UUID just generated.
Each of the instances cannot complete the Bluetooth connection. Throughout the entire program, I put many Logs just to try and see why it wouldn't be able to connect.
Below is the code for the first instance. (Generate 1 random UUID at the launch of the app.) If anyone likes to download my Eclipse project just to take a look, here's the link of the project from MediaFire. As for the second instance, uncommenting the C-style comments in the code below will reveal it.
I expected the results would be to have a successful connection between two devices. The successful connection connects a device to a listening socket, by using a generated UUID. The observed results show it is unlikely.
As far as I know, the only way to obtain a UUID is to obtain it from UUID.randomUUID(). If there are other ways, please post a comment below, and I'll check it. But for now, it's not the answer I wanted.
Thanks in advance.
package o.p;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
/**
* The purpose of this app is to create a server-only Bluetooth connection that
* only accepts incoming Bluetooth connections. It is used only for testing
* one device that needs Bluetooth tweaking in order to consistently work
* correctly on the other device. In short, 2 devices are required.
* */
public class Main extends Activity implements View.OnClickListener {
//Button
private Button acceptButton;
private Button scanButton;
//Bluetooth stuffs.
private BluetoothAdapter btAdapter;
private BluetoothServerSocket serverSocket;
private BluetoothSocket socket;
private BluetoothDevice targetDevice;
private final UUID uuid = UUID.randomUUID();
/*private UUID randomUUID;*/
//Accepting thread.
private class Accept implements Runnable {
private BluetoothServerSocket socket;
private BluetoothSocket result = null;
public Accept(BluetoothServerSocket s) {
socket = s;
result = null;
}
#Override
public void run() {
try {
Log.d("DEBUG", "Accepting.");
result = socket.accept();
Log.d("DEBUG", "Closing server socket.");
socket.close();
}
catch (IOException e) {
Log.d("DEBUG - onClick(), case Accept", "Unable to accept incoming connection.");
}
}
public BluetoothSocket getSocket() {
while (result == null);
return result;
}
}
//Connecting thread.
private class Connecting implements Runnable {
private BluetoothDevice device;
public Connecting(BluetoothDevice d) {
device = d;
}
#Override
public void run() {
try {
/*Log.d("DEBUG", "Generating a new random UUID.");
randomUUID = UUID.randomUUID();*/
Log.d("DEBUG", "Obtaining a socket.");
BluetoothSocket s = device.createRfcommSocketToServiceRecord(uuid);
Log.d("DEBUG", "Cancelling discovery, if it's still discovering.");
if (btAdapter.isDiscovering())
btAdapter.cancelDiscovery();
Log.d("DEBUG", "Connecting to listening socket with UUID: " + uuid.toString());
s.connect();
}
catch (IOException e) {
Log.d("DEBUG - Connecting.run()", "Unable to connect to the listening socket.");
}
}
}
//Thread executor
private ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
//BroadcastReceiver for accepting Bluetooth
private BroadcastReceiver receiver;
#Override
public void onCreate(Bundle b) {
super.onCreate(b);
setContentView(R.layout.main);
init();
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_accept:
Log.d("DEBUG", "Pressing the Accept button.");
Accept acceptThread = new Accept(serverSocket);
Connecting connectThread = new Connecting(targetDevice);
if (serverSocket != null) {
executor.execute(acceptThread);
executor.execute(connectThread);
socket = acceptThread.getSocket();
}
else {
Log.d("DEBUG", "Server socket isn't ready.");
Toast.makeText(this, "Server socket isn't ready.", Toast.LENGTH_LONG).show();
}
break;
case R.id.button_scan:
if (btAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Log.d("DEBUG", "Initiating discovery scan mode.");
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
this.startActivity(discoverableIntent);
Toast.makeText(this, "Being discovered...", Toast.LENGTH_LONG).show();
}
if (btAdapter.isDiscovering()) {
Toast.makeText(this, "Re-scanning...", Toast.LENGTH_SHORT).show();
Log.d("DEBUG", "Re-scanning.");
btAdapter.cancelDiscovery();
}
Log.d("DEBUG", "Scanning.");
Toast.makeText(this, "Scanning...", Toast.LENGTH_LONG).show();
btAdapter.startDiscovery();
break;
}
}
private void init() {
Log.d("DEBUG", "Initializing.");
Log.d("DEBUG", "Button initializing.");
acceptButton = (Button) findViewById(R.id.button_accept);
acceptButton.setOnClickListener(this);
scanButton = (Button) findViewById(R.id.button_scan);
scanButton.setOnClickListener(this);
Log.d("DEBUG", "Registering BroadcastReceiver.");
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
Log.d("DEBUG", "Device has been found.");
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.d("DEBUG", "Obtained a device from Intent.");
if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
Log.d("DEBUG", "Removing paired device.");
try {
Method m = device.getClass().getMethod("removeBond", (Class[]) null);
m.invoke(device, (Object[]) null);
Log.d("DEBUG", "Removed " + device);
}
catch (NoSuchMethodException e) {
Log.e("ERROR - DeviceReceiver.onReceive()", "", e);
}
catch (IllegalArgumentException e) {
Log.e("ERROR - DeviceReceiver.onReceive()", "", e);
}
catch (IllegalAccessException e) {
Log.e("ERROR - DeviceReceiver.onReceive()", "", e);
}
catch (InvocationTargetException e) {
Log.e("ERROR - DeviceReceiver.onReceive()", "", e);
}
}
else {
Log.d("DEBUG", "Obtaining remote device's address.");
btAdapter.getRemoteDevice(device.getAddress());
try {
serverSocket = btAdapter.listenUsingRfcommWithServiceRecord(device.getName(), uuid);
Log.d("DEBUG", "Listening to " + device.getName() + "...");
}
catch (IOException e) {
Log.d("DEBUG - onReceive()", "Unable to create a server socket after receiving a broadcast.", e);
serverSocket = null;
Log.d("DEBUG", "Server socket is set to null.");
}
}
targetDevice = device;
}
else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
Log.d("DEBUG", "Scanning finished.");
}
}
};
Log.d("DEBUG", "Creating Bluetooth Adapter.");
btAdapter = BluetoothAdapter.getDefaultAdapter();
try {
Log.d("DEBUG", "Creating a server socket for listening using UUID: " + uuid.toString());
serverSocket = btAdapter.listenUsingRfcommWithServiceRecord("server", uuid);
}
catch (IOException e) {
Log.d("DEBUG - init()", "Error in creating a server socket from uuid.");
}
}
#Override
public void onResume() {
super.onResume();
//TODO: Not done with the receivers.
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(receiver, filter);
filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(receiver, filter);
}
#Override
public void onPause() {
//TODO: Complete this one. Same for onResume().
super.onPause();
unregisterReceiver(receiver);
}
}
To be able to connect the UUIDs should match.
On the Server side what you are doing is correct i.e generating a ramdom UUID and listening on it,
But the client needs to connect using the same UUID that the server is listening on.
The way to get it will be from your client use the fetchUuidsWithSdp() on the Server BluetoothDevice object and use the obtained UUID to connect to the server.
I'm trying to connect to a device with the code below... basically modified from the BTchat source. Everything seems to go fine, but the device is not responding to commands, my phone still says it's paired but not connected, and the device says it's not connected. That makes me pretty sure that it's indeed not connected, but no errors are happening.
Could I have the wrong UUID?
the log says:
04-30 18:51:10.116: DEBUG/BluetoothService(1228): uuid(application): 00001101-0000-1000-8000-00805f9b34fb 1
04-30 18:51:10.116: DEBUG/BluetoothService(1228): Making callback for 00001101-0000-1000-8000-00805f9b34fb with result 1
04-30 18:51:10.131: VERBOSE/BluetoothEventRedirector(31561): Received android.bleutooth.device.action.UUID
and my code is printing to the log that it's connected:
04-30 18:53:21.210: DEBUG/BTComm(1044): connect to: K4500-620963
04-30 18:53:21.225: INFO/BTComm(1044): BEGIN ConnectThread
04-30 18:53:26.272: DEBUG/BTComm(1044): connected to: K4500-620963
04-30 18:53:26.272: DEBUG/BTComm(1044): create ConnectedThread
04-30 18:53:26.280: DEBUG/BTComm(1044): setState() 0 -> 3
04-30 18:53:26.280: INFO/BTComm(1044): BEGIN ConnectedThread
Here is my whole code:
p
ublic class BTCom {
// Debugging
private static final String TAG = "BTComm";
private static final boolean D = true;
private static final UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// Member fields
private final BluetoothAdapter adapter;
private final Handler handler;
private ConnectThread connectThread;
private ConnectedThread connectedThread;
private int state;
private Context context;
private BluetoothDevice BTDevice;
// 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 BTCom(Context context, Handler handler) {
adapter = BluetoothAdapter.getDefaultAdapter();
state = STATE_NONE;
this.handler = handler;
this.context = context;
}
private void checkBluetooth(){
// check if device supports bluetooth
if (adapter == null) {
Toast.makeText(context, "ERROR: This device does not support Bluetooth communication"
, Toast.LENGTH_LONG).show();
return;
}
// now make sure bluetooth is enabled
if (!adapter.isEnabled()) {
// if not, then prompt the user
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
context.startActivity(enableBtIntent);
}
}
public BluetoothDevice getBTDevice(){
Set<BluetoothDevice> pairedDevices = adapter.getBondedDevices();
BluetoothDevice foundDevice = null;
BTDevice = null;
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
// check if the name fits the pattern K4xxx-xxxxxx
if (device.getName().matches("K4\\d\\d\\d-\\d\\d\\d\\d\\d\\d")){
foundDevice = device;
break;
}
}
if (foundDevice == null){ // if we didn't find any
Toast.makeText(context,
"ERROR: No paired BTDevice device was found, please pair a BTDevice device to continue"
, Toast.LENGTH_LONG).show();
return null;
}
}
return foundDevice; // found a BTDevice!
}
/**
* Set the current state of the chat connection
* #param state An integer defining the current connection state
*/
private synchronized void setState(int state) {
if (D) Log.d(TAG, "setState() " + this.state + " -> " + state);
this.state = state;
}
/**
* Start the ConnectThread to initiate a connection to a remote device.
* #param device The BluetoothDevice to connect
*/
public synchronized void connect(BluetoothDevice device) {
Log.d(TAG, "connect to: " + device.getName());
// Cancel any thread attempting to make a connection
if (connectThread != null) {connectThread.cancel(); connectThread = null;}
// Cancel any thread currently running a connection
if (connectedThread != null) {connectedThread.cancel(); connectedThread = null;}
// Start the thread to connect with the given device
connectThread = new ConnectThread(device);
connectThread.start();
}
/**
* 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) {
Log.d(TAG, "connected to: " + device.getName());
// Cancel the thread that completed the connection
if (connectThread != null) {connectThread.cancel(); connectThread = null;}
// Cancel any thread currently running a connection
if (connectedThread != null) {connectedThread.cancel(); connectedThread = null;}
// Start the thread to manage the connection and perform transmissions
connectedThread = new ConnectedThread(socket);
connectedThread.start();
setState(STATE_CONNECTED);
}
/**
* Stop all threads
*/
public synchronized void stop() {
if (D) Log.d(TAG, "stop");
if (connectThread != null) {
connectThread.cancel();
connectThread = null;
}
if (connectedThread != null) {
connectedThread.cancel();
connectedThread = 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 (state != STATE_CONNECTED) return;
r = connectedThread;
}
// Perform the write unsynchronized
r.write(out);
}
private class ConnectThread extends Thread {
private final BluetoothSocket socket;
private final BluetoothDevice device;
public ConnectThread(BluetoothDevice device) {
this.device = device;
BluetoothSocket tmp = null;
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try {
tmp = device.createRfcommSocketToServiceRecord(uuid);
} catch (IOException e) {
Log.e(TAG, "Socket create failed", e);
}
socket = tmp;
}
public void run() {
Log.i(TAG, "BEGIN ConnectThread");
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
socket.connect();
} catch (IOException e) {
// Close the socket
try {
socket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() socket during connection failure", e2);
}
return;
}
// Reset the ConnectThread because we're done
synchronized (BTCom.this) {
connectThread = null;
}
// Start the connected thread
connected(socket, this.device);
}
public void cancel() {
try {
socket.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.
*/
private class ConnectedThread extends Thread {
private final BluetoothSocket socket;
private final InputStream inStream;
private final OutputStream outStream;
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "create ConnectedThread");
this.socket = 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);
}
inStream = tmpIn;
outStream = tmpOut;
}
public void run() {
Log.i(TAG, "BEGIN ConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = inStream.read(buffer);
// Send the obtained bytes to the UI Activity
handler.obtainMessage(KestrelTest.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
// Start the service over to restart listening mode
break;
}
}
}
/**
* Write to the connected OutStream.
* #param buffer The bytes to write
*/
public void write(byte[] buffer) {
try {
outStream.write(buffer);
Log.i(TAG, "Sending " + buffer.length + " bytes");
Log.i(TAG, "Sending: " + new String(buffer));
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void cancel() {
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
}
I'm stumped as to why is't not connecting... Any ideas? Thanks!
What is the device you are connecting to? Perhaps the device requires certain profiles to be supported by the host (Android) system, like A2DP, BIP, BPP etc.
The Bluetooth Chat program creates a basic client-server connection, and does not require Bluetooth Profiles support.
For Bluetooth profile support to be implemented on Android, there is a project called “Sybase-iAnywhere-Blue-SDK-for-Android”, which replaces Android's version, and provides all interfaces into the underlying Bluetooth profiles and protocols. Using this, printing over bluetooth using your Android phone will be possible using the BPP profile provided by this SDK.
See links below for more details: link 1: http://www.sybase.com/detail?id=1064424 Link 2: http://www.sybase.com/products/allproductsa-z/mobiledevicesdks/bluetoothsdks
Application profiles supported by the iAnywhere Blue SDK for Android are said to include:
Handsfree (HFP)
Advanced Audio Distribution (A2DP)
A/V Remote Control (AVRCP)
File Transfer Protocol (FTP)
Object Push Protocol (OPP)
SIM Access (SAP)
Phone Book Access (PBAP)
Message Access Profile (MAP)
Human Interface (HID)
Basic Printing (BPP)
Basic Imaging (BIP)
I need to connect my android to a bluetooth device. I use the BluetoothChat sample from Google.
I had some trouble to do this with a Google Nexus one, because the Nexus was making the connection but disconnects right after. I need to initiate twice time the connection as workaround (see connectionLost()).
Now, it works well on the Nexus One and on the HTC Desire too.
My problem is the disconnection at application exit. It works fine on the Nexus one, the connection is closed, but not on the HTC Desire. I add the inputstream/outputstream close function in addition to the socket close. Have a look at the "stop()" function.
package xxx.yyy.zzz;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.UUID;
import activities.Act_Main;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
/**
* This class does all the work for setting up and managing Bluetooth
* connections with other devices. It has a thread that listens for
* incoming connections, a thread for connecting with a device, and a
* thread for performing data transmissions when connected.
*/
public class BluetoothService {
// Debugging
private static final String TAG = "BluetoothService";
private static final boolean D = true;
// Member fields
//private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;
private String mBTAddress;
private boolean isStop = false;
// 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 Act_Main session.
* #param context The UI Activity Context
* #param handler A Handler to send messages back to the UI Activity
*/
public BluetoothService(Context context, Handler handler)
{
//mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
mHandler = handler;
}
/**
* Set the current state of the connection
* #param state An integer defining the current connection state
*/
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(Act_Main.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}
/**
* Return the current connection state. */
public synchronized int getState()
{
return mState;
}
/**
* Start the ConnectThread to initiate a connection to a remote device.
* #param device The BluetoothDevice to connect
*/
public synchronized void connect(String BTAddress)
{
mBTAddress = BTAddress ;
// Get the BLuetoothDevice object
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(BTAddress);
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);
isStop = false ;
}
/**
* 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(Act_Main.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(Act_Main.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
/**
* Stop all threads
*/
public synchronized void stop()
{
isStop = true ;
if (D)
Log.d(TAG, "stop");
if(mConnectThread != null)
{
mConnectThread.cancel();
Thread moribund = mConnectThread;
mConnectThread = null;
moribund.interrupt();
}
if(mConnectedThread != null)
{
mConnectedThread.cancel();
Thread moribund = mConnectedThread;
mConnectedThread = null;
moribund.interrupt();
}
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)
{
Log.d(TAG, "BT_SEND_MESSAGE");
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()
{
try
{
synchronized (this)
{
this.wait(3000);
}
connect(mBTAddress);
}
catch(InterruptedException ex)
{
Log.e(TAG, "WAIT_EXCEPTION:"+ ex.getMessage());
}
}
/**
* Indicate that the connection was lost and notify the UI Activity.
*/
private void connectionLost()
{
if (!isStop)
connect(mBTAddress);
}
/**
* This thread runs while attempting to make an outgoing connection
* with a device. It runs straight through; the connection either
* succeeds or fails.
*/
private 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(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
}
catch (Exception 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);
}
return;
}
// Reset the ConnectThread because we're done
synchronized (BluetoothService.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.
*/
private class ConnectedThread extends Thread {
private BluetoothSocket mmSocket;
private InputStream mmInStream;
private 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;
int bytes = 0;
// Keep listening to the InputStream while connected
while (true)
{
try
{
//Clear buffer
buffer = new byte[1024];
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(Act_Main.MESSAGE_READ, bytes, -1, buffer).sendToTarget();
}
catch (IOException e)
{
//String bufferStr = new String(buffer, 0, buffer.length);
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);
}
catch (IOException e)
{
Log.e(TAG, "Exception during write", e);
}
}
public void cancel()
{
if (mmOutStream != null)
{
try {mmOutStream.close();} catch (Exception e) { Log.e(TAG, "close() of outputstream failed", e); }
mmOutStream = null;
}
if (mmInStream != null)
{
try {mmInStream.close();} catch (Exception e) { Log.e(TAG, "close() of inputstream failed", e); }
mmInStream = null;
}
if (mmSocket != null)
{
try {mmSocket.close();} catch (Exception e) { Log.e(TAG, "close() of connect socket failed", e); }
mmSocket = null;
}
}
}
}
Thanks in advance for your help.
JJ
Quick comment about synchronization in your code:
Leave the synchronized keyword on your connect() method, but when it comes time to connect, call your connect() from a thread, rather than creating a thread from your connect(). As it stands now, your code is firing off a connect thread from connect() and defeating the purpose of synchronization. (The purpose being to synchronize requests to connect() so that multiple threads don't get jumbled up as they try to connect at the same time). This may well be causing some of your connection issues.
regarding the HTC:
I think you and I encountered the same issue: Why can't HTC Droid running OTA 2.1 communicate with RFCOMM?
A note about disconnecting a bluetooth connection:
Make sure to disconnect gracefully every time using your cancel() method.
I just read this post now : Bluetooth on 2.0+
Has anyone a solution to the bad implementation of the HTC Desire ?
UPDATE : For instance, I've done a very bad workaround. I kill the process when I exit the application :
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
am.restartPackage("com.example.package");
I'm still waiting on a cleaner solution.
UPDATE : It seems HTC fixed it through their Froyo update (android 2.2)