How to disconnect a bluetooth connection (HTC Desire) - android

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)

Related

Android bluetooth socket connection not working

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");
}
}
}

Application using bluetooth SPP profile not working after update from Android 4.2 to Android 4.3

I wrote a simple application based on bluetoothChat. I communicate between the phone and a bluetooth module using SPP profile. The phone always initiates the communication. The application worked pefectly on Android 4.2, using Nexus 3 and Samsung Galaxy 3.
After the update to Android 4.3, the application does not work anymore. I connect all the time, I can send an outpustream and receive the right data, but after the 1st outputstream command, the application always disconnected after around 6s.
As shown in the logcat below, it looks there is a timer issue on the inputstream.
08-23 14:10:00.726: D/mems(23193): STEVAL-MKI106V1
08-23 14:10:00.804: D/Main Activity(23193): firmware version*setdb106V1
08-23 14:10:00.812: D/Main Activity(23193): sent message*setdb106V1
08-23 14:10:00.812: D/BluetoothMEMSCommunication(23193): dans write3
08-23 14:10:00.812: D/BluetoothMEMSCommunication(23193): envoi stream
08-23 14:10:05.812: W/bt-btif(20368): dm_pm_timer expires
08-23 14:10:05.812: W/bt-btif(20368): dm_pm_timer expires 0
08-23 14:10:05.812: W/bt-btif(20368): proc dm_pm_timer expires
08-23 14:10:11.656: E/bt-btm(20368): btm_sec_disconnected - Clearing Pending flag
08-23 14:10:11.656: W/bt-btif(20368): invalid rfc slot id: 15
08-23 14:10:11.656: I/connection(23193): connectionlost
What is dm_pm_timer?
I tried to connect a different way, with secure and insecure rfcom. I know the bluetooth chat is not optimized to receive the buffer, so I modified it, not no effect. I used the flush command for the outpustream too, but no effect either.
package com.meneujj.memsbtbis;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.UUID;
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;
import android.widget.Toast;
public class BluetoothMEMSCommunication {
// debugging
private static final String TAG = "BluetoothMEMSCommunication";
private static final boolean D = true;
// eMotion BT h as this standard UUID
private static final UUID STANDARD_UUID =
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// Member fields
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private int mState;
private int handlerCalling;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
// Constants they indicate the current connection state
public static final int STATE_NONE = 0;
public static final int STATE_CONNECTED = 3; // now connected to a remote device
// constructor. Prepares a new Bluetooth Connection
// context The UI Activity Context
// handler an Handler to send messages back to the UI Activity
public BluetoothMEMSCommunication(Context context, Handler handler, int i) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
mHandler = handler;
handlerCalling = i;
}
private synchronized void setState(int state) {
mState = state;
Log.d(TAG, Integer.toString(mState));
mHandler.obtainMessage(MainActivityMemsBT.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}
public synchronized void connect(BluetoothDevice device) {
// start the thread to connect with the given device
if (mConnectThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
Log.d(TAG,"routine connect lancee");
mConnectThread = new ConnectThread(device);
mConnectThread.start();
}
private void ConnectionLost() {
// Send a failure message back to the activity
Message msg = mHandler.obtainMessage(MainActivityMemsBT.CONNECTION_LOST_MESSAGE);
Bundle bundle = new Bundle();
bundle.putString(MainActivityMemsBT.TOAST_CONNECTION_LOST, "Device connection was lost");
msg.setData(bundle);
mHandler.sendMessage(msg);
Log.i("connection","connectionlost");
setState(STATE_NONE);
StopAllThreads();
}
public synchronized void StopAllThreads() {
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
setState(STATE_NONE);
}
public synchronized void connected(BluetoothSocket socket, BluetoothDevice device, final String socketType) {
// cancel the thread they 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 transmission
mConnectedThread = new ConnectedThread(socket, socketType);
mConnectedThread.start();
// Send the name of the connected device back to the UI activity
Message msg = mHandler.obtainMessage(MainActivityMemsBT.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(MainActivityMemsBT.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
public void write(byte[] out) {
// create temporary object
ConnectedThread r;
Log.d(TAG,"dans write" + Integer.toString(mState));
// synchronize a copy of the ConnectedThread
synchronized (this) {
if (handlerCalling == 2) setState(STATE_CONNECTED);
if (mState != STATE_CONNECTED) {
Log.d(TAG, "different de STATE_CONNECTED");
Log.i(TAG, Integer.toString(handlerCalling));
return;}
r= mConnectedThread;
}
r.write(out);
}
Any idea is there is a workaround? Or any obvious mistake in my code
Thanks
// Thread runs while attempting to an 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;
private String mSocketType;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
try {
tmp = device.createRfcommSocketToServiceRecord(STANDARD_UUID);
//tmp = device.createInsecureRfcommSocketToServiceRecord(STANDARD_UUID);
/* try {
Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
try {
tmp = (BluetoothSocket) m.invoke(device, 1);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} */
} catch (IOException e) {
}
mmSocket = tmp;
}
public void run () {
setName("ConnectThread" + mSocketType);
mAdapter.cancelDiscovery();
try {
mmSocket.connect();
} catch (IOException e) {
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() " + mSocketType + "socket during connection failure", e2);
}
return;
}
// reset the CoonectThread because the job is over
synchronized (BluetoothMEMSCommunication.this) {
mConnectThread = null;
}
connected(mmSocket, mmDevice, mSocketType);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
}
}
// close connectThread class
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket, String socketType) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
ConnectionLost();
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
// Thread to listen to input sockets
public void run() {
Log.i(TAG, "Begin mConnectedThread");
byte[] buffer = new byte[1024];
// int bytes;
int bytesRead = -1;
String message = "";
// keep listening to the InputStream while connected
while(true) {
try {
// read from the input stream
// bytesRead = mmInStream.read(buffer);
// message = message+ new String(buffer, 0, bytesRead);
// byte[] byteString = message.getBytes();
Log.i("info","pret a faire read");
bytesRead = mmInStream.read(buffer, 0, 1024);
if (bytesRead != -1 && handlerCalling == 1) {
mHandler.obtainMessage(MainActivityMemsBT.MESSAGE_READ, bytesRead, -1, buffer).sendToTarget(); }
if (bytesRead !=-1 && handlerCalling == 2) {
mHandler.obtainMessage(DemoAccelerometer.MESSAGE_READ, bytesRead, -1, buffer).sendToTarget(); }
}
catch (IOException e) {
ConnectionLost();
break;
}
}
}
public void write(byte[] buffer) {
try{
mmOutStream.write(buffer);
// if (handlerCalling == 1) {
// mHandler.obtainMessage(MainActivityMemsBT.MESSAGE_WRITE, -1, -1, buffer).sendToTarget();
Log.d(TAG,"envoi stream");
// mmOutStream.flush();
// }
} catch (IOException e) {
}
}
public void cancel() {
try{
mmSocket.close();
} catch (IOException e) {
}
}
}
}
We can confirm the Bluetooth disconnect after 6 seconds when communicating from our Nexus 4 app to an external Bluetooth ECG (medical device) after upgrading from Android 4.2 to 4.3. This happens specifically during an ECG measurement with lots of inbound data (from ECG to the Android app) but no outbound data. "Normal" Bluetooth communication with some inbound and outbound data from time to time does not seem to be affected.
After 6 seconds we see the same adb log messages reported by JJM
dm_pm_timer expires
dm_pm_timer expires 0
proc dm_pm_timer expires
btm_sec_disconnected - Clearing Pending flag
This timer expiry on the Android side triggers something (closing output stream because no outbound data?) on the external Bluetooth ECG which in turn sends an ECG specific command we receive on the input stream that we never receive on the Nexus 4 with Android 4.2.
Changing the Android app implementation to occasionally send an arbitrary "keep alive" command to the ECG solves the problem. The timer expiry does not appear in the adb logs anymore and the ECG measurement now behaves the same as with Android 4.2.
Thanks to JJM for the hints.
I found a work around. It is disconnected if there is no streaming activity for a few seconds. I managed to have some output or input streaming several times per second, and it never disconnects now.
I found on StackOverflow an answer that helped me to fix the problem. I guess it has something to do with the inputStream and outputStream not being closed properly and nulled, as well as the bluetooth socket. After using this function:
* Reset input and output streams and make sure socket is closed.
* This method will be used during shutdown() to ensure that the connection is properly closed during a shutdown.
* #return
*/
private void resetConnection() {
setState(STATE_NONE);
Log.d(TAG, "reset connection");
if (mmInStream != null) {
try {
mmInStream.close();
} catch (Exception e) {
Log.d(TAG,"exception in closing inputstream - " + e.getMessage());
}
mmInStream = null;
}
if (mmOutStream != null) {
try {
mmOutStream.close();
} catch (Exception e) {
Log.d(TAG,"exception in closing outputstream - " + e.getMessage());
}
mmOutStream = null;
}
if (mmSocket != null) {
try {
mmSocket.close();
} catch (Exception e) {
Log.d(TAG,"exception in closing socket - " + e.getMessage());
}
mmSocket = null;
}
}
in ConnectedThread and call it when necessary, i removed that problem. It could be also a problem with reading from the inputStream, maybe because there was nothing in there when attempting to read.
I suggest that you do a boolean function readWrite() that whenever you write to outputStream you also read the inputStream and send the readBuffer to UI with mHandler. If both read and write are ok, than return true, if one of them went wrong than return false and use resetConection before closing your ConnectedThread.
It worked very nice for me.
UPDATE: (30-SEPT-2013)
I am running my app and I still get the hci_status = 36 after few minutes. I have an app, that connects to an external bluetooth device. I am sending data and receive data approx. 3 times / sec. I am using a Thread.sleep(300) between writes. In my tests I got this error after few minutes up to almost 30 minutes when running the app.
Any feedback is appreciated!

Format text in bluetooth printer

actually, I have to implement a module the which connect to a BT termical printer and print in it. I have a simple but functionally example, it works with the printer. The problem is that these text are printed in plain text, and i have to give it format, bold, change the font size and others... How can i do it??. I don't know how... I use this Class:
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.edec.aptr;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
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;
// Name for the SDP record when creating server socket
private static final String NAME = "BTPrinter";
// Unique UUID for this application
private static final UUID MY_UUID = UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB"); // change by
// chongqing
// jinou
// Member fields
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private AcceptThread mAcceptThread;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;
// Constants that indicate the current connection state
public static final int STATE_NONE = 0; // we're doing nothing
public static final int STATE_LISTEN = 1; // now listening for incoming
// connections
public static final int STATE_CONNECTING = 2; // now initiating an outgoing
// connection
public static final int STATE_CONNECTED = 3; // now connected to a remote
// device
/**
* Constructor. Prepares a new BTPrinter 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(amarre.MESSAGE_STATE_CHANGE, state, -1)
.sendToTarget();
}
/**
* Return the current connection state.
*/
public synchronized int getState() {
return mState;
}
/**
* Start the service. Specifically start AcceptThread to begin a session in
* listening (server) mode. Called by the Activity onResume()
*/
public synchronized void start() {
if (D)
Log.d(TAG, "start");
// Cancel any thread attempting to make a connection
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Start the thread to listen on a BluetoothServerSocket
if (mAcceptThread == null) {
mAcceptThread = new AcceptThread();
mAcceptThread.start();
}
setState(STATE_LISTEN);
}
/**
* Start the ConnectThread to initiate a connection to a remote device.
*
* #param device
* The BluetoothDevice to connect
*/
public synchronized void connect(BluetoothDevice device) {
if (D)
Log.d(TAG, "connect to: " + device);
// Cancel any thread attempting to make a connection
if (mState == STATE_CONNECTING) {
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Start the thread to connect with the given device
mConnectThread = new ConnectThread(device);
mConnectThread.start();
setState(STATE_CONNECTING);
}
/**
* Start the ConnectedThread to begin managing a Bluetooth connection
*
* #param socket
* The BluetoothSocket on which the connection was made
* #param device
* The BluetoothDevice that has been connected
*/
public synchronized void connected(BluetoothSocket socket,
BluetoothDevice device) {
if (D)
Log.d(TAG, "connected");
// Cancel the thread that completed the connection
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Cancel the accept thread because we only want to connect to one
// device
if (mAcceptThread != null) {
mAcceptThread.cancel();
mAcceptThread = 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(amarre.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(amarre.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
/**
* Stop all threads
*/
public synchronized void stop() {
if (D)
Log.d(TAG, "stop");
setState(STATE_NONE);
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
if (mAcceptThread != null) {
mAcceptThread.cancel();
mAcceptThread = null;
}
}
/**
* Write to the ConnectedThread in an unsynchronized manner
*
* #param out
* The bytes to write
* #see ConnectedThread#write(byte[])
*/
public void write(byte[] out) {
// Create temporary object
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
if (mState != STATE_CONNECTED)
return;
r = mConnectedThread;
}
// Perform the write unsynchronized
r.write(out);
}
/**
* Indicate that the connection attempt failed and notify the UI Activity.
*/
private void connectionFailed() {
setState(STATE_LISTEN);
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(amarre.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(
amarre.TOAST,
"No se puede conectar al dispostivo, verifique que éste se encuentra encendido y cercano a la tablet");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
/**
* Indicate that the connection was lost and notify the UI Activity.
*/
private void connectionLost() {
// setState(STATE_LISTEN);
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(amarre.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(amarre.TOAST,
"La conexión con el dispositivo se ha perdido");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
/**
* This thread runs while listening for incoming connections. It behaves
* like a server-side client. It runs until a connection is accepted (or
* until cancelled).
*/
private class AcceptThread extends Thread {
// The local server socket
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
// Create a new listening server socket
try {
tmp = mAdapter
.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) {
Log.e(TAG, "listen() failed", e);
}
mmServerSocket = tmp;
}
public void run() {
if (D)
Log.d(TAG, "BEGIN mAcceptThread" + this);
setName("AcceptThread");
BluetoothSocket socket = null;
// Listen to the server socket if we're not connected
while (mState != STATE_CONNECTED) {
try {
// This is a blocking call and will only return on a
// successful connection or an exception
socket = mmServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "accept() failed", e);
break;
}
// If a connection was accepted
if (socket != null) {
synchronized (BluetoothService.this) {
switch (mState) {
case STATE_LISTEN:
case STATE_CONNECTING:
// Situation normal. Start the connected thread.
connected(socket, socket.getRemoteDevice());
break;
case STATE_NONE:
case STATE_CONNECTED:
// Either not ready or already connected. Terminate
// new socket.
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close unwanted socket", e);
}
break;
}
}
}
}
if (D)
Log.i(TAG, "END mAcceptThread");
}
public void cancel() {
if (D)
Log.d(TAG, "cancel " + this);
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of server failed", e);
}
}
}
/**
* 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(MY_UUID);
} catch (IOException e) {
Log.e(TAG, "create() failed", e);
}
mmSocket = tmp;
}
public void run() {
Log.i(TAG, "BEGIN mConnectThread");
setName("ConnectThread");
// Always cancel discovery because it will slow down a connection
mAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket.connect();
} catch (IOException e) {
connectionFailed();
// Close the socket
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG,
"unable to close() socket during connection failure",
e2);
}
// Start the service over to restart listening mode
BluetoothService.this.start();
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 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");
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
byte[] buffer = new byte[256];
// Read from the InputStream
bytes = mmInStream.read(buffer);
if (bytes > 0) {
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(amarre.MESSAGE_READ, bytes, -1,
buffer).sendToTarget();
} else {
Log.e(TAG, "disconnected");
connectionLost();
// add by chongqing jinou
if (mState != STATE_NONE) {
Log.e(TAG, "disconnected");
// Start the service over to restart listening mode
BluetoothService.this.start();
}
break;
}
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
// add by chongqing jinou
if (mState != STATE_NONE) {
// Start the service over to restart listening mode
BluetoothService.this.start();
}
break;
}
}
}
/**
* Write to the connected OutStream.
*
* #param buffer
* The bytes to write
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
// Share the sent message back to the UI Activity
mHandler.obtainMessage(amarre.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);
}
}
}
}
I send the data from another class, so:
byte[] send;
try {
send = message.getBytes("GB2312");
} catch (UnsupportedEncodingException e) {
send = message.getBytes();
}
mService.write(send);
message is a String var.. Then, how can I format the text??, or at least, change font size...
Now I know how to do it. I had to apply reverse engineering and de-compile an .apk from the market, using dex2jar on Linux and then opening the jar with java de-compiler... Try this...When you write this command:
out.write(str.getBytes(),0,str.getBytes().length);
you are sending to the method a byte[] array. You can modify the format by sending another byte[] array before sending the real byte[] array...
The default format byte[] array is this:
byte[] arrayOfByte1 = { 27, 33, 0 };
So u can try this:
byte[] format = { 27, 33, 0 };
out.write(format);
out.write(str.getBytes(),0,str.getBytes().length);
These lines will print the default format text, but if you try below code,
byte[] format = { 27, 33, 0 };
format[2] = ((byte)(0x8 | arrayOfByte1[2]));
out.write(format);
out.write(str.getBytes(),0,str.getBytes().length);
it will print text in bold style... You can try these other format arrays:
// Bold
format[2] = ((byte)(0x8 | arrayOfByte1[2]));
// Height
format[2] = ((byte)(0x10 | arrayOfByte1[2]));
// Width
format[2] = ((byte) (0x20 | arrayOfByte1[2]));
// Underline
format[2] = ((byte)(0x80 | arrayOfByte1[2]));
// Small
format[2] = ((byte)(0x1 | arrayOfByte1[2]));
Also you can combine it, then if you like little and bold text, uncomment these array assignments, for example:
byte[] format = { 27, 33, 0 };
// Bold
format[2] = ((byte)(0x8 | arrayOfByte1[2]));
// Height
format[2] = ((byte)(0x10 | arrayOfByte1[2]));
// Width
format[2] = ((byte) (0x20 | arrayOfByte1[2]));
// Underline
// format[2] = ((byte)(0x80 | arrayOfByte1[2]));
// Small
// format[2] = ((byte)(0x1 | arrayOfByte1[2]));
out.write(format);
out.write(str.getBytes(),0,str.getBytes().length);
This last code prints que biggest text size.
I know this is an old thread but it helped me alot so I decided to share my code for simplified use of Formatting.
Sample usage:
final String message = "Example message\n";
// Default format:
writeWithFormat(message.getBytes(), new Formatter().get(), Formatter.leftAlign());
// Bold format center:
writeWithFormat(message.getBytes(), new Formatter().bold().get(), Formatter.centerAlign());
// Bold underlined format with right alignment:
writeWithFormat(message.getBytes(), new Formatter().bold().underlined().get(), Formatter.rightAlign());
Formatter class with Builder pattern:
/**
* Class for formatting
*/
public static class Formatter {
/** The format that is being build on */
private byte[] mFormat;
public Formatter() {
// Default:
mFormat = new byte[]{27, 33, 0};
}
/**
* Method to get the Build result
*
* #return the format
*/
public byte[] get() {
return mFormat;
}
public Formatter bold() {
// Apply bold:
mFormat[2] = ((byte) (0x8 | mFormat[2]));
return this;
}
public Formatter small() {
mFormat[2] = ((byte) (0x1 | mFormat[2]));
return this;
}
public Formatter height() {
mFormat[2] = ((byte) (0x10 | mFormat[2]));
return this;
}
public Formatter width() {
mFormat[2] = ((byte) (0x20 | mFormat[2]));
return this;
}
public Formatter underlined() {
mFormat[2] = ((byte) (0x80 | mFormat[2]));
return this;
}
public static byte[] rightAlign(){
return new byte[]{0x1B, 'a', 0x02};
}
public static byte[] leftAlign(){
return new byte[]{0x1B, 'a', 0x00};
}
public static byte[] centerAlign(){
return new byte[]{0x1B, 'a', 0x01};
}
}
The write method that uses the formatting looks like this:
/**
* Method to write with a given format
*
* #param buffer the array of bytes to actually write
* #param pFormat The format byte array
* #param pAlignment The alignment byte array
* #return true on successful write, false otherwise
*/
public boolean writeWithFormat(byte[] buffer, final byte[] pFormat, final byte[] pAlignment) {
try {
// Notify printer it should be printed with given alignment:
mOutputStream.write(pAlignment);
// Notify printer it should be printed in the given format:
mOutputStream.write(pFormat);
// Write the actual data:
mOutputStream.write(buffer, 0, buffer.length);
// Share the sent message back to the UI Activity
App.getInstance().getHandler().obtainMessage(MESSAGE_WRITE, buffer.length, -1, buffer).sendToTarget();
return true;
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
return false;
}
}
There are two perceptions to this:
you are just trying to print by passing the text. You are leaving option to the printer to choose to print anyway it wants.
check whether your printer supports Basic Printing Profile[BPP] - Job Based Transfer. I had success printing it in html format, both images and text on a bluetooth printer.
Also, check for the UUID you are providing. They are different UUID for Object push profile, BPP Job Based Transfer profile. I suggest you use the UUID assiged for BPP[Job based transfer]
and try passing a xhtml file with formatted text.
Thanks
Mani

Problem connecting to a bluetooth device

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)

Linux Bluetooth not finding Android Service with UUID

I am trying to write a program on an embedded system running GUMSTIX(Linux) to connect and talk to an Android 2.x device over bluetooth. The GUMSTIX is the client and the Android is the server. I am trying to find the channel number that my Android service uses so that the GUMSTIX can connect to it but for some reason my routine isn't returning a channel number because it doesn't seem to find a service with a matching UUID.
I suspect that the UUID provided to the GUMSTIX routine and the UUID on the Android device are not actually the same number. Android requires a 128 bit UUID :
From the Android Documentation:
UUID is an immutable representation of
a 128-bit universally unique
identifier (UUID).
There are multiple, variant layouts of
UUIDs, but this class is based upon
variant 2 of RFC 4122, the Leach-Salz
variant. This class can be used to
model alternate variants, but most of
the methods will be unsupported in
those cases; see each method for
UUID used in android:
public static final String UUID_STRING = "00000000-0000-0000-0000-00000000ABCD";
private static final UUID MY_UUID = UUID.fromString(UUID_STRING);
C Code in GUMSTIX Look for comment indicating where it fails
int main(int argc , char **argv)
{
//Android wants a 128 bit UUID why are we only giving a 32 bit UUID
uint32_t svc_uuid_int[] = { 0 , 0 , 0 , 0xABCD } ;
int status ;
bdaddr_t target ;
uuid_t svc_uuid ;
sdp_list_t *response_list , *search_list , *attrid_list ;
sdp_session_t *session = 0;
uint32_t range = 0x0000ffff ;
uint8_t port = 0;
if(argc < 2)
{
fprintf(stderr , "usage: %s <bt_addr>\n" , argv [ 0 ] ) ;
exit ( 2 ) ;
}
str2ba ( argv[1] , &target ) ;
// connect to the SDP server running on the remote machine
session = sdp_connect ( BDADDR_ANY, &target, SDP_RETRY_IF_BUSY );
// printf("session %u\n",session);
sdp_uuid128_create( &svc_uuid, &svc_uuid_int ) ;
search_list = sdp_list_append( 0, &svc_uuid ) ;
attrid_list = sdp_list_append( 0, &range ) ;
// get a list of service records that have UUID 0xabcd
response_list = NULL ; //ERROR: response_list SHOULD GET INITIALIZED BUT IT STAYS NULL CAUSING THE PROGRAM TO NEVER ENTER THE FOR LOOP BELOW.
status = sdp_service_search_attr_req(session , search_list , SDP_ATTR_REQ_RANGE , attrid_list, &response_list ) ;
printf("status %d\n",status);
if( status == 0 )
{
sdp_list_t *proto_list = NULL ;
sdp_list_t *r = response_list ;
// go through each of the service records
for ( ; r ; r = r->next )
{
sdp_record_t *rec = (sdp_record_t * ) r->data ;
// get a list of the protocol sequences
if( sdp_get_access_protos( rec, &proto_list ) == 0 )
{
// get the RFCOMM port number
port = sdp_get_proto_port( proto_list , RFCOMM_UUID ) ;
sdp_list_free( proto_list, 0 );
}
sdp_record_free( rec ) ;
}
}
sdp_list_free( response_list, 0 );
sdp_list_free( search_list, 0 );
sdp_list_free( attrid_list, 0 );
sdp_close( session ) ;
if( port != 0 )
{
printf( "found service running on RFCOMM port %d\n" , port ) ;
}
return 0;
}
EDIT:
Android code for the acceptThread(accepts connections), ConnectThread(completes the connection), and ConnectedThread(maintains the connection, establish handler)
/**
* This thread runs while listening for incoming connections. It behaves
* like a server-side client. It runs until a connection is accepted
* (or until canceled).
*/
private class AcceptThread extends Thread {
// The local server socket
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
// Create a new listening server socket
try {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) {
Log.e(TAG, "listen() failed", e);
}
mmServerSocket = tmp;
}
public void run() {
if (D) Log.d(TAG, "BEGIN mAcceptThread" + this);
setName("AcceptThread");
BluetoothSocket socket = null;
// Listen to the server socket if we're not connected
while (mState != STATE_CONNECTED) {
try {
// This is a blocking call and will only return on a
// successful connection or an exception
if(D) Log.i("prism", "Waiting to connect************");
socket = mmServerSocket.accept();
if(D) Log.i("prism", "We have accepted connection and are connected***************");
} catch (IOException e) {
Log.e(TAG, "accept() failed", e);
break;
}
// If a connection was accepted
if (socket != null) {
synchronized (BluetoothServer.this) {
switch (mState) {
case STATE_LISTEN:
case STATE_CONNECTING:
// Situation normal. Start the connected thread.
connected(socket, socket.getRemoteDevice());
break;
case STATE_NONE:
case STATE_CONNECTED:
// Either not ready or already connected. Terminate new socket.
try {
if (D) Log.i("prism", "Bluetooth already connected, abandoning request from " + socket.getRemoteDevice().getName());
socket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close unwanted socket", e);
}
break;
}
}
}
}
if (D) Log.i(TAG, "END mAcceptThread");
}
public void cancel() {
if (D) Log.d(TAG, "cancel " + this);
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of server failed", e);
}
}
}
/**
* 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(MY_UUID);
} catch (IOException e) {
Log.e(TAG, "create() failed", e);
}
mmSocket = tmp;
}
public void run() {
Log.i(TAG, "BEGIN mConnectThread");
setName("ConnectThread");
// Always cancel discovery because it will slow down a connection
mAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
Log.i(TAG, "mmSocket.connect() is initiaiting in the ConnectThread");
mmSocket.connect();
Log.i(TAG, "mmSocket.connect() complete...");
} catch (IOException e) {
Log.e(TAG, "Connection attempt failed, closing the socket");
connectionFailed();
// Close the socket
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() socket during connection failure", e2);
}
// Start the service over to restart listening mode
BluetoothServer.this.start();
return;
}
// Reset the ConnectThread because we're done
synchronized (BluetoothServer.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 final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "create ConnectedThread");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(Bluetooth.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
break;
}
}
}
The Android code was adopted from the Bluetooth Chat example here
Do you have any service (typically over RFCOMM/SPP) with UUID { 0 , 0 , 0 , 0xABCD } running on the Android device ?
You will probably (programmatically create the service with the specified UUID and have it running on the device to be able to connect to it.
Quoting from Android Documentation:
**
public BluetoothServerSocket listenUsingRfcommWithServiceRecord (String name, UUID uuid)
Create a listening, secure RFCOMM Bluetooth socket with Service Record.
A remote device connecting to this socket will be authenticated and communication on this socket will be encrypted.
Use accept() to retrieve incoming connections from a listening BluetoothServerSocket.
The system will assign an unused RFCOMM channel to listen on.
The system will also register a Service Discovery Protocol (SDP) record with the local SDP server containing the specified UUID, service name, and auto-assigned channel. Remote Bluetooth devices can use the same UUID to query our SDP server and discover which channel to connect to. This SDP record will be removed when this socket is closed, or if this application closes unexpectedly.
Use createRfcommSocketToServiceRecord(UUID) to connect to this socket from another device using the same UUID.
**

Categories

Resources