Android Bluetooth Printing - android

I am writing an application which sends data to bluetooth printer. Can anyone help me ? how can I use android Bluetooth Stack for printing? or is there any external api or sdk to use?
Here is my code for searching bluetooth...
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
registerReceiver(ActionFoundReceiver,
new IntentFilter(BluetoothDevice.ACTION_FOUND));
private final BroadcastReceiver ActionFoundReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
btArrayAdapter.add(device.getName() + "\n"
+ device.getAddress());
btArrayAdapter.notifyDataSetChanged();
}
}
};
and here is my code for sending data to printer..
BluetoothDevice mDevice = bluetoothAdapter.getRemoteDevice("00:15:FF:F2:56:A4");
Method m = mDevice.getClass().getMethod("createRfcommSocket",
new Class[] { int.class });
mBTsocket = (BluetoothSocket) m.invoke(mDevice, 1);
System.out.println("Connecting.....");
mBTsocket.connect();
System.out.println("Connected");
OutputStream os = mBTsocket.getOutputStream();
os.flush();
os.write(Receipt.getBytes());
// mBTsocket.close();
When I write socket.close() , data is not getting print to printer as socket connection getting closed before printing data..and if I didn't write socket.close() then data is getting printed only once.. I would not be able to print data second time until I restart bluetooth of my phone.
can any one have solution for it??? or is there any other way to get rid of this printing??

I got the solution of my problem...
if i want to print data more than one time then you dont need to create new Socket Connection with the device... instead call outputstream.write(bytes) method.
and in the end if you want to disconnect device then call mBTScoket.close() method to disconnect device.

You can use printooth library for any printer, printooth is simple and well documented,
https://github.com/mazenrashed/Printooth
var printables = ArrayList<Printable>()
var printable = Printable.PrintableBuilder()
.setText("Hello World") //The text you want to print
.setAlignment(DefaultPrinter.ALLIGMENT_CENTER)
.setEmphasizedMode(DefaultPrinter.EMPHASISED_MODE_BOLD) //Bold or normal
.setFontSize(DefaultPrinter.FONT_SIZE_NORMAL)
.setUnderlined(DefaultPrinter.UNDELINED_MODE_ON) // Underline on/off
.setCharacterCode(DefaultPrinter.CHARACTER_CODE_USA_CP437) // Character code to support languages
.setLineSpacing(DefaultPrinter.LINE_SPACING_60)
.setNewLinesAfter(1) // To provide n lines after sentence
.build()
printables.add(printable)
BluetoothPrinter.printer().print(printables)

If you have made connection to the devices and paired it.
So for printing, printer wants the byte. SO I have createed a mothod.
Simply call this method and pass the String inside it to get printed.
String str = new String("This is the text sending to the printer");
private void printData() {
// TODO Auto-generated method stub
String newline = "\n";
try {
out.write(str.getBytes(),0,str.getBytes().length);
Log.i("Log", "One line printed");
} catch (IOException e) {
Toast.makeText(BluetoothDemo.this, "catch 1", Toast.LENGTH_LONG).show();
e.printStackTrace();
Log.i("Log", "unable to write ");
flagCheck = false;
}
try {
out.write(newline.getBytes(),0,newline.getBytes().length);
} catch (IOException e) {
Log.i("Log", "Unable to write the new line::");
e.printStackTrace();
flagCheck = false;
}
flagCheck = true;
}

Related

Android sending info via Bluetooth, fast logging

I am trying to write an app that passes the coordinates of a ball to Arduino via BT. The coordinates are being sent every 4 ms. For this test I send "123" instead of full coordinates. What am I getting now (on Arduino serial monitor) is "123123123123123..." and it refreshes only after I close the application.
What I want to achieve is "123" in every line, that shows immediately after the message is sent.
Android code BT:
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
private OutputStream outStream ;
UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket
// because mmSocket is final.
BluetoothSocket tmp = null;
mmDevice = device;
try {
// Get a BluetoothSocket to connect with the given BluetoothDevice.
// MY_UUID is the app's UUID string, also used in the server code.
tmp = device.createInsecureRfcommSocketToServiceRecord(uuid);
} catch (IOException e) {
Log.e(TAG, "Socket's create() method failed", e);
}
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it otherwise slows down the connection.
mBluetoothAdapter.cancelDiscovery();
try {
// Connect to the remote device through the socket. This call blocks
// until it succeeds or throws an exception.
mmSocket.connect();
Log.i(TAG, "run: CONNECTED");
} catch (IOException connectException) {
Log.i(TAG, "run: NOT CONNECTED");
}
}
// Closes the client socket and causes the thread to finish.
public void cancel() {
try {
mmSocket.close();
if(outStream != null)
outStream.close();
finish();
} catch (IOException e) {
Log.e(TAG, "Could not close the client socket", e);
}
}
//Sending Message
public void writeData(String data){
String info = data;
try {
outStream = mmSocket.getOutputStream();
outStream.write(info.getBytes());
Log.i(TAG, "writeData: MSG SENT");
} catch (IOException e) {
e.printStackTrace();
Log.i(TAG, "run: CANT SEND MSG");
}
}
public boolean isConnected(){
return mmSocket.isConnected();
}
}
In my main function I call:
if(connectThread.isConnected())
connectThread.writeData("123");
Arduino code:
String incomingByte;
void setup() {
//pinMode(53, OUTPUT);
Serial.begin(9600);
}
void loop() {
// see if there's incoming serial data:
if (Serial.available() > 0) {
// read the oldest byte in the serial buffer:
incomingByte = Serial.readString();
Serial.println(incomingByte);
delay(10);
}
}
There is no concept of messages in serial communication, unless you make it yourself.
Serial.readString() delimits your "messages" with time (1 second by default) and you are sending "messages" 4 ms apart. This obviously concatenates your "messages".
To actually send messages you need to delimit them. You can do that by sending lines.
On Android, you need to end the message with a new line character:
outStream.write(info.getBytes());
outStream.write(10); // send a new line character (ASCII code 10)
And on Arduino, you need to read, until you find a new line character:
incomingByte = Serial.readStringUntil('\n');
Serial.read(); // remove the leftover new line character from the buffer
You need to put at least \n (or maybe \r\n) after the coordinates, or the Bluetooth module just keeps buffering.

Pairing two android bluetooth devices without any passkey popup

I want to pair two android bluetooth devices (Kitkat) without any popup for passkey exchange. I tried setpin() and cancelPairingUserInput() methods inside the broadcast receiver for PAIRING_REQUEST intent using reflection, but got no results. Can anyone help me with that ?
if(BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)){
BluetoothDevice localBluetoothDevice = (BluetoothDevice)intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE");
try {
Log.d("setPin()", "Try to set the PIN");
Method m = localBluetoothDevice.getClass().getMethod("setPin", byte[].class);
m.invoke(localBluetoothDevice, ByteBuffer.allocate(4).putInt(1234).array());
Log.d("setPin()", "Success to add the PIN.");
} catch (Exception e) {
Log.e("setPin()", e.getMessage());
}
Class localClass = localBluetoothDevice.getClass();
Class[] arrayOfClass = new Class[0];
try {
localClass.getMethod("setPairingConfirmation", boolean.class).invoke(localBluetoothDevice, true);
localClass.getMethod("cancelPairingUserInput", arrayOfClass).invoke(localBluetoothDevice, null);
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Did you try calling createBond() through reflection?
This works for me, with device being a BluetoothDevice:
Method m = device.getClass().getMethod("createBond", (Class[]) null);
m.invoke(device, (Object[]) null);
Get the device and the PIN (or the pairing key) from the given Intent
if the given PIN is not -1, set it in the device
invoke the device's .setPairingConfirmation() method
My code (which achieves this) in the .bluetoothEventReceived() callback method, looks something like this:
private void bluetoothEventRecieved(Context context, Intent intent)
{
if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int pin = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, -1);
if (pin != -1) {
byte[] pinBytes = String.format(Locale.US, "%04d", pin).getBytes();
device.setPin(pinBytes);
}
device.setPairingConfirmation(true);
}
}

How to send a text message to a paired device through bluetooth in android?

In my app I want to send and receive text message through bluetooth. I can see in my listview a list of paired device name and address.But when I am trying to send a text to a paired device nothing happens. In other device there is no text received.
This is my Code to send message to a paired device.
private void sendDataToPairedDevice(String message, String adress) {
byte[] toSend = message.getBytes();
try {
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(adress);
// BluetoothSocket socket
// =device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"));
BluetoothSocket socket = null;
Method m = null;
try {
m = device.getClass().getMethod("createRfcommSocket",
new Class[] { int.class });
} catch (Exception e) {
e.printStackTrace();
}
try {
socket = (BluetoothSocket) m.invoke(device, 1);
} catch (Exception e) {
e.printStackTrace();
}
OutputStream mmOutStream = socket.getOutputStream();
mBluetoothAdapter.cancelDiscovery();
socket.connect();
mmOutStream.write(toSend);
} catch (Exception e) {
Log.d("TAG", "Exception during write", e);
}
}
the bluetoothchat sample is actually the perfect thing to use if you are new in using the bluetooth api.
assuming that you are using only one Activity for your application which is the BluetoothChat class :
for sending text to the device you are connected to, use the "sendMessage(String message)" method in the BluetoothChat class to send text.
as for receiving and handling the text, you will find also handleMessage(Message msg) method somewhere in the bluetoothchat class then go this part:
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);
see the readMessage String?
this is the text that that you receive from the other device , now you can handle it as you want.
then simply change the main layout that the BluetoothChat class refers to, then in BluetoothChat chat either comment or delete the parts that have errors which actually will be the parts in the UI u have deleted or changed.
i know the code may sound messy but this is the easiest way to use it quickly as possible and watching video tutorials or text tutorials for hours will just make it more complicated, believe me i tried this before.

Android and Bluetooth hang (startActivityForResult)

I'm trying to improve an actual code that make a bluetooth connection with an Android phone to an Atmega with Arduino (An electronic micro-controller). I can receive and send data to the micro-controller but the bluetooth need to be put at ON before lunching my application or it will hang and close. I do check for a bluetooth adapter and request the user to change the bluetooth state if it's at OFF but it seem the program continue and try to make a connection before getting the result of the user selection. I would like some help to find a solution to either block my program until the user input their choice or even get a better solution.
I would like to say that I'm still new to Android programming and I did read the Android activity flowchart.
I can provide logcat, but I inspected it and it clearly state that I am trying to use bluetooth even if it's not enabled ...
Here is my code :
I want to thanks anybody that could point me on the right direction
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnOn = (Button) findViewById(R.id.btnOn); // button LED ON
btnOff = (Button) findViewById(R.id.btnOff); // button LED OFF
txtArduino = (TextView) findViewById(R.id.txtArduino); // for display the received data from the Arduino
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); // get Bluetooth adapter
checkBTState();
h = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case RECIEVE_MESSAGE: // if receive massage
byte[] readBuf = (byte[]) msg.obj;
String strIncom = new String(readBuf, 0, msg.arg1); // create string from bytes array
sb.append(strIncom); // append string
int endOfLineIndex = sb.indexOf("\r\n"); // determine the end-of-line
if (endOfLineIndex > 0) { // if end-of-line,
sbprint = sb.substring(0, endOfLineIndex); // extract string
sb.delete(0, sb.length()); // and clear
txtArduino.setText("Data from Arduino: " + sbprint);
Log.e(TAG, "Arduino"+sbprint);
//Test string value
if(sbprint.matches("-?\\d+(\\.\\d+)?")) {
try{
Float sensorReading = Float.parseFloat(sbprint);
Log.e(TAG, "Sensor value"+sensorReading);
}catch(NumberFormatException e){
Log.e(TAG, "No int format sorry",e);
}
}
if(sbprint.matches("test")){
Log.e(TAG, "garbage");
}
///////
btnOff.setEnabled(true);
btnOn.setEnabled(true);
}
//Log.d(TAG, "...String:"+ sb.toString() + "Byte:" + msg.arg1 + "...");
break;
}
};
};
public void onResume() {
super.onResume();
Log.d(TAG, "...onResume - try connect...");
// Set up a pointer to the remote node using it's address.
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
// Two things are needed to make a connection:
// A MAC address, which we got above.
// A Service ID or UUID. In this case we are using the
// UUID for SPP.
try {
btSocket = createBluetoothSocket(device);
} catch (IOException e) {
errorExit("Fatal Error", "In onResume() and socket create failed: " + e.getMessage() + ".");
}
/*try {
btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
errorExit("Fatal Error", "In onResume() and socket create failed: " + e.getMessage() + ".");
}*/
// Discovery is resource intensive. Make sure it isn't going on
// when you attempt to connect and pass your message.
mBluetoothAdapter.cancelDiscovery();
// Establish the connection. This will block until it connects.
Log.d(TAG, "...Connecting...");
try {
btSocket.connect();
Log.d(TAG, "....Connection ok...");
} catch (IOException e) {
try {
btSocket.close();
} catch (IOException e2) {
errorExit("Fatal Error", "In onResume() and unable to close socket during connection failure" + e2.getMessage() + ".");
}
}
// Create a data stream so we can talk to server.
Log.d(TAG, "...Create Socket...");
mConnectedThread = new ConnectedThread(btSocket);
mConnectedThread.start();
}
You have all your code in onResume. onResume is going to get called right at startup of the activity, so it will execute almost immediately. I don't see any code in there that should delay it at all. If you don't want to try to connect until the user selects something, then all the connection code should be in a button's click handler or something similar.
In addition to #GabeSechan's comment about all of your code being in onResume(), you are also calling the Bluetooth connect() in your main activity thread which according to the this documentation is a blocking call and "should always be performed in a thread separate from the main activity thread".

Finding UUIDs in Android 2.0

I am writing a program which needs to be run in Android 2.0. I am currently trying to connect my android device to an embedded bluetooth chip. I have been given information as to use fetchuidsWithSDP(), or getUuids(), but the page I read explained that these methods are hidden in the 2.0 SDK, and must be called using reflection. I have no idea what that means and there is no explanation. There is example code given, but very little explanation behind it. I was hoping someone could help me understand what is actually going on here, as I am very new to Android development.
String action = "android.bleutooth.device.action.UUID";
IntentFilter filter = new IntentFilter( action );
registerReceiver( mReceiver, filter );
The page I read also says that in the first line bluetooth is spelled "bleutooth" on purpose. If anyone can explain that, I would appreciate that as well as it makes no sense to me, unless the developers made a typo.
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive( Context context, Intent intent ) {
BluetoothDevice deviceExtra = intent.getParcelableExtra("android.bluetooth.device.extra.Device");
Parcelable[] uuidExtra = intent.getParcelableArrayExtra("android.bluetooth.device.extra.UUID");
}
};
I am having trouble grasping how exactly I find the correct UUID for my embedded bluetooth chip. If anyone could help it'd be greatly appreciated.
EDIT: I am going to add the rest of my onCreate() method so you can see what I'm working with.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set up window View
setContentView(R.layout.main);
// Initialize the button to scan for other devices.
btnScanDevice = (Button) findViewById( R.id.scandevice );
// Initialize the TextView which displays the current state of the bluetooth
stateBluetooth = (TextView) findViewById( R.id.bluetoothstate );
startBluetooth();
// Initialize the ListView of the nearby bluetooth devices which are found.
listDevicesFound = (ListView) findViewById( R.id.devicesfound );
btArrayAdapter = new ArrayAdapter<String>( AndroidBluetooth.this,
android.R.layout.simple_list_item_1 );
listDevicesFound.setAdapter( btArrayAdapter );
CheckBlueToothState();
// Add an OnClickListener to the scan button.
btnScanDevice.setOnClickListener( btnScanDeviceOnClickListener );
// Register an ActionFound Receiver to the bluetooth device for ACTION_FOUND
registerReceiver( ActionFoundReceiver, new IntentFilter( BluetoothDevice.ACTION_FOUND ) );
// Add an item click listener to the ListView
listDevicesFound.setOnItemClickListener( new OnItemClickListener()
{
public void onItemClick(AdapterView<?> arg0, View arg1,int arg2, long arg3)
{
// Save the device the user chose.
myBtDevice = btDevicesFound.get( arg2 );
// Open a socket to connect to the device chosen.
try {
btSocket = myBtDevice.createRfcommSocketToServiceRecord( MY_UUID );
} catch ( IOException e ) {
Log.e( "Bluetooth Socket", "Bluetooth not available, or insufficient permissions" );
} catch ( NullPointerException e ) {
Log.e( "Bluetooth Socket", "Null Pointer One" );
}
// Cancel the discovery process to save battery.
myBtAdapter.cancelDiscovery();
// Update the current state of the Bluetooth.
CheckBlueToothState();
// Attempt to connect the socket to the bluetooth device.
try {
btSocket.connect();
// Open I/O streams so the device can send/receive data.
iStream = btSocket.getInputStream();
oStream = btSocket.getOutputStream();
} catch ( IOException e ) {
Log.e( "Bluetooth Socket", "IO Exception" );
} catch ( NullPointerException e ) {
Log.e( "Bluetooth Socket", "Null Pointer Two" );
}
}
});
}
You're probably better off using the synchronous version so you don't have to deal with all the moving parts of setting up the BroadcastReceiver. Since you are always doing this on the heels of discovery, the cached data will always be fresh.
Here the functionality of getting the UUID data encapsulated up into a method. This code was in one of the comments of the blog post you linked:
//In SDK15 (4.0.3) this method is now public as
//Bluetooth.fetchUuisWithSdp() and BluetoothDevice.getUuids()
public ParcelUuid[] servicesFromDevice(BluetoothDevice device) {
try {
Class cl = Class.forName("android.bluetooth.BluetoothDevice");
Class[] par = {};
Method method = cl.getMethod("getUuids", par);
Object[] args = {};
ParcelUuid[] retval = (ParcelUuid[]) method.invoke(device, args);
return retval;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
You can then call this method anywhere in your code, passing it a BluetoothDevice and getting back an array of UUIDs for that device's services (typically for small embedded stacks the array is only 1 item); something like:
// Save the device the user chose.
myBtDevice = btDevicesFound.get( arg2 );
//Query the device's services
ParcelUuid[] uuids = servicesFromDevice(myBtDevice);
// Open a socket to connect to the device chosen.
try {
btSocket = myBtDevice.createRfcommSocketToServiceRecord(uuids[0].getUuid());
} catch ( IOException e ) {
Log.e( "Bluetooth Socket", "Bluetooth not available, or insufficient permissions" );
} catch ( NullPointerException e ) {
Log.e( "Bluetooth Socket", "Null Pointer One" );
}
in the block you posted above.
As a side note, calling all this code in the manner you have will make your application sad later. The block of code calling connect() and obtaining the streams should be done on a background thread because that method will block for a period of time and calling this code on the main thread will freeze your UI temporarily. You should move that code into an AsyncTask or a Thread like the BluetoothChat sample in the SDK does.
HTH
I also faced the same issue and this is how I solved it for Android 2.3.3. I think the same solution will work for android 2.2 also.
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#SuppressLint("NewApi")
#Override
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);
Toast.makeText(getApplicationContext(),"Device: "+device.getName(),Toast.LENGTH_SHORT).show();
devices.add(device.getName() + "\n" + device.getAddress());
list.add(device);
}
else if(BluetoothDevice.ACTION_UUID.equals(action)){
Toast.makeText(getApplicationContext(),"I am Here",Toast.LENGTH_SHORT).show();
}
else {
if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
Toast.makeText(getApplicationContext(),"Done Scanning..",Toast.LENGTH_SHORT).show();
Iterator<BluetoothDevice> itr = list.iterator();
while(itr.hasNext())
{
BluetoothDevice dev=itr.next();
if(dev.fetchUuidsWithSdp())
{
Parcelable a[]=dev.getUuids();
Toast.makeText(getApplicationContext(),dev.getName()+":"+a[0],Toast.LENGTH_SHORT).show();
}
}
}
}
}
};

Categories

Resources