Posted on 16 Mar 2014 in android, java, printing, bluetooth by Greg E.
Bluetooth Printing pre-4.1
I was working on an application that prints an image to a bluetooth printer. This application had been working fine on Android 2.3, 3.0, and 4.0, but when we upgraded one of them to Android 4.1 jelly bean, printing stopped working. This is the error in logcat:
But this error doesn’t seem to make sense, because that permission is declared in the Android manifest file.
It turns out that this is just the wrong way to do things - inserting directly into another application’s content provider is a security problem, and with Android 4.1, Google closed that hole in the Bluetooth Application. So how do you print? There is another method, the “right” way, although it isn’t really directly documented anywhere. The right way to do it is with this “share” intent, but there are a few snags you will hit along the way.
Bluetooth Printing 4.1+
First start the print process with a standard Share intent. Target the bluetooth application so the user won’t be prompted who to share it to:
The sharing intent also provides the URI to the image. Note you have to put this image in a place where another application could access it. Don’t put it in your internal private storage. If that’s a problem, you need to expose a content provider to make the image available via a content:// URI, but that’s a whole different blog post.
This works, but the user gets a popup asking them to select which device to print to. This is kind of pointless if there is only one printer paired. And it is really bad if you are running in a kiosk mode like this application.
You can intercept this and handle the android.bluetooth.devicepicker.action.LAUNCH intent action and then broadcasting the message android.bluetooth.devicepicker.action.DEVICE_SELECTED. You don’t show a UI, you just give it the printer you want to use.
First declare a new activity to handle the intent:
In the activity, just broadcast the device selected message, and immediately exit:
I’m calling a utility function to get the selected device. Here is that function:
This just takes the first bluetooth device which can print (IMAGING class).
There is just one problem left - the very first time you print, you get a chooser popup because there are now two applications handling the android.bluetooth.devicepicker.action.LAUNCH. You can’t uninstall the other application, because it’s in the same APK as the code that does all the printing work. In this case it was OK because you can select the “Use as default” option and then you never see it again.
I don’t really know how to resolve that, so feedback is welcomed.