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);
}
}
Related
I need to obtain device's Bluetooth MAC address.
Before Android 6 it was easy as BluetoothAdapter.getDefaultAdapter().getAddress(). After that we had to use a simple workaround: String macAddress = android.provider.Settings.Secure.getString(context.getContentResolver(), "bluetooth_address");. But later(in Android 8 AFAIK) it was also closed, but another workaround was discovered:
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
String bluetoothMacAddress = "";
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M){
try {
Field mServiceField = bluetoothAdapter.getClass().getDeclaredField("mService");
mServiceField.setAccessible(true);
Object btManagerService = mServiceField.get(bluetoothAdapter);
if (btManagerService != null) {
bluetoothMacAddress = (String) btManagerService.getClass().getMethod("getAddress").invoke(btManagerService);
}
} catch (NoSuchFieldException e) {
} catch (NoSuchMethodException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
} else {
bluetoothMacAddress = bluetoothAdapter.getAddress();
}
But starting from Android 8.1 trying to access that method throws exception:
java.lang.reflect.InvocationTargetException Caused by: java.lang.SecurityException: Need LOCAL_MAC_ADDRESS permission: Neither user 10141 nor current process has android.permission.LOCAL_MAC_ADDRESS, which means that this method requires permission, available only for system-level apps.
So the question is if there is any workaround to get Bluetooth address in Android 8.1?
I have a task in which I have to send E-Mail each day once.
I used Service triggered by AlarmManager to achieve this. It's working properly. But the problem is the mail gets send only if the mobile data is available. So I tried to turn on the data connection and send mail. Mobile data is enabled but, Mail not sending. I have posted here what I've tried. Someone please suggest a method to wait until the user turn on mobile data and send mail. Thank you.
cm=(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
ni=cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
isConnected=ni!=null&&ni.isConnected();
Mail m=new Mail("xxxxxxxxx#gmail.com","xxxxxxx");
String[] strTo={"xxxxxxxxx#gmail.com"};
m.setTo(strTo);
m.setFrom("xxxxxxxxxx#gmail.com");
m.setSubject("Subject");
m.setBody("Please find the attachment");
try{
m.addAttachment(Environment.getExternalStorageDirectory() + "/xxxxx/xxxxxx.xx");
if (isConnected){
m.send();
}else {
ConnectivityManager dataManager;
dataManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
Method dataMtd = null;
try {
dataMtd = ConnectivityManager.class.getDeclaredMethod("setMobileDataEnabled", boolean.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
dataMtd.setAccessible(true);
try {
dataMtd.invoke(dataManager, true);
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
NetworkInfo netInfo=dataManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
boolean isOnline=netInfo!=null&&netInfo.isConnected();
if(isOnline){
if (m.send()){
ConnectivityManager dataManager1;
dataManager1 = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
Method dataMtd1 = null;
try {
dataMtd1 = ConnectivityManager.class.getDeclaredMethod("setMobileDataEnabled", boolean.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
dataMtd1.setAccessible(false);
try {
dataMtd1.invoke(dataManager1, false);
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
}catch (final Exception e){
e.printStackTrace();
Log.v("My_Service",e.toString());
}
You need to have BroadcastReceiver listening to change in data connectivity. Refer to - http://developer.android.com/reference/android/content/BroadcastReceiver.html
Check this for reference specific to network connectivity - Check INTENT internet connection
Don't relay on Google shit api... Info to the user to enable data + post delayed eg time task :) u can not handle all problems by enabling data.. But u can check for most : There could by a firewall issue , DNS issue, TTL issue when theter etc
You can register a BroadcastReceiver to be notified when a Mobile data is enabled.
Register the BroadcastReceiver:
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION));
registerReceiver(broadcastReceiver, intentFilter);
And then in your BroadcastReceiver do something like this:
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION))) {
if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)){
// data connection was lost
} else {
// do your stuff
}
}
}
For more info, see the documentation for BroadcastReceiver
You can use below link to send mail :
How to send mail without user interaction from another application
I am developing an application which needs to send sms in pdu mode.
I am using this code but it gives NoSuchElementException on first line.
try {
Method m2 = sms.getClass().getDeclaredMethod("sendRawPdu", pdu.getClass(), pdu.getClass(), piSent.getClass(), piDelivered.getClass());
m2.setAccessible(true);
SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(null, "", "Test", false);
Object[] arrayOfObject2 = new Object[5];
arrayOfObject2[0] = pdus.encodedScAddress;
arrayOfObject2[1] = pdus.encodedMessage;
arrayOfObject2[2] = piSent;
arrayOfObject2[3] = piDelivered;
arrayOfObject2[4] = null;
try {
m2.invoke(sms, arrayOfObject2);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
Any help will be appreciated.
I tried it on Lollipop, but there is no method related to sendRawPdu
Do a little more thing just print the list of methods available to check if there is any method related to sendRawPdu
Method[] methods = sms.getClass().getDeclaredMethods();
boolean methodAvailable = false;
for(Method m : methods) {
Log.d("SmsManager", m.toString());
if(m.toString().contains("sendRawPdu")) {
methodAvailable = true;
}
}
now you have methodAvailable, if it is true you can send Raw PDU, if not then you can't. sendRawPdu was available before JellyBeans. Try to run this on Pre JellyBeans devices.
I am developing an application where I want to connect a Bluetooth device main issue is I don't want user to enter required pin instead application should do that by himself...I don't have any connection related issue...Only want to insert and complete pin authentication process by application itself.
I found following code I am sure it is working but not sure on how to add pin in this code??
private void pairDevice(BluetoothDevice device) {
try {
Log.d("pairDevice()", "Start Pairing...");
Method m = device.getClass().getMethod("createBond", (Class[]) null);
m.invoke(device, (Object[]) null);
Log.d("pairDevice()", "Pairing finished.");
} catch (Exception e) {
Log.e("pairDevice()", e.getMessage());
}
}
Does anyone know how to enter pin in above code or any similar code to solve problem..
Thank You
How can I avoid or dismiss Android's Bluetooth pairing notification when I am doing programmatic pairing?
This seems to give you the answer, with the pin entering and all. It involves sending .setPin() whenever you get the message.
So, I had this question, if someone needs the answer to this working in android 4.4.2.
IntentFilter filter = new IntentFilter(
"android.bluetooth.device.action.PAIRING_REQUEST");
/*
* Registering a new BTBroadcast receiver from the Main Activity context
* with pairing request event
*/
registerReceiver(
new PairingRequest(), filter);
And the code for the Receiver.
public static class PairingRequest extends BroadcastReceiver {
public PairingRequest() {
super();
}
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.bluetooth.device.action.PAIRING_REQUEST")) {
try {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int pin=intent.getIntExtra("android.bluetooth.device.extra.PAIRING_KEY", 0);
//the pin in case you need to accept for an specific pin
Log.d("PIN", " " + intent.getIntExtra("android.bluetooth.device.extra.PAIRING_KEY",0));
//maybe you look for a name or address
Log.d("Bonded", device.getName());
byte[] pinBytes;
pinBytes = (""+pin).getBytes("UTF-8");
device.setPin(pinBytes);
//setPairing confirmation if neeeded
device.setPairingConfirmation(true);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
And in the manifest file.
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
And the broadcastReceiver.
<receiver android:name=".MainActivity$PairingRequest">
<intent-filter>
<action android:name="android.bluetooth.device.action.PAIRING_REQUEST" />
<action android:name="android.bluetooth.device.action.PAIRING_CANCEL" />
</intent-filter>
</receiver>
How to set the pin code has been answered above (and that helped me). Yet, I share my simple code below which works with Android 6:
BluetoothAdapter mBTA = BluetoothAdapter.getDefaultAdapter();
if (mBTA.isDiscovering()) mBTA.cancelDiscovery();
mBTA.startDiscovery();
...
/** In a broadcast receiver: */
if (BluetoothDevice.ACTION_FOUND.equals(action)) { // One device found.
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.d(TAG, "Start Pairing... with: " + device.getName());
device.createBond();
}
// If you want to auto-input the pin#:
else if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)){
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
device.setPin("1234".getBytes());
}
Try this code:
public void pairDevice(BluetoothDevice device)
{
String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
Intent intent = new Intent(ACTION_PAIRING_REQUEST);
String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
intent.putExtra(EXTRA_DEVICE, device);
String EXTRA_PAIRING_VARIANT = "android.bluetooth.device.extra.PAIRING_VARIANT";
int PAIRING_VARIANT_PIN = 0;
intent.putExtra(EXTRA_PAIRING_VARIANT, PAIRING_VARIANT_PIN);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
intent.putExtra(EXTRA_DEVICE, device);
int PAIRING_VARIANT_PIN = 272;
intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, PAIRING_VARIANT_PIN);
sendBroadcast(intent);
Intent intent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
startActivityForResult(intent, REQUEST_PAIR_DEVICE);
I hope this helps
Reference: http://pastebin.com/N8dR4Aa1
Register a BluetoothDevice.ACTION_PAIRING_REQUEST receiver onCreate()
val pairingRequestFilter = IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST)
registerReceiver(pairingReceiver, pairingRequestFilter)
on receiver set your pin using setPin() and call abortBroadcast()
val PAIRING_PIN=1234
private var pairingReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val action = intent!!.action
if (BluetoothDevice.ACTION_PAIRING_REQUEST == action) {
val device: BluetoothDevice? =intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
val type =intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR)
if (type == BluetoothDevice.PAIRING_VARIANT_PIN) {
device?.setPin(PAIRING_PIN.toByteArray())
abortBroadcast()
}
}
}
}
Don't forget to unregister receiver on onDestroy()
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(pairingReceiver)
}
if it doesn't work for you, try setting hight priority to receiver
val pairingRequestFilter = IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST)
pairingRequestFilter.priority = IntentFilter.SYSTEM_HIGH_PRIORITY - 1
registerReceiver(pairingReceiver, pairingRequestFilter)
Also you can register a receiver with BluetoothDevice.ACTION_BOND_STATE_CHANGED to read status of pairing
val filter = IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED)
registerReceiver(receiver, filter)
Try this,
BluetoothDevice device = intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE");
device.getClass().getMethod("setPairingConfirmation", boolean.class).invoke(device, true);
device.getClass().getMethod("cancelPairingUserInput", boolean.class).invoke(device);
BluetoothSocket bluetoothSocket = null;
try {
bluetoothSocket = device.createRfcommSocketToServiceRecord(UUID.fromString(UUID_DIVING));
} catch (IOException e) {
Log.i("Bluetooth", "IOException = " + e.getMessage());
e.printStackTrace();
}
try {
byte[] pin = (byte[]) BluetoothDevice.class.getMethod("convertPinToBytes", String.class).invoke(BluetoothDevice.class, "0000");
Method m = device.getClass().getMethod("setPin", byte[].class);
m.invoke(device, (Object) pin);
device.getClass().getMethod("setPairingConfirmation", boolean.class).invoke(device, true);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
Log.i("Bluetooth", "IOException = " + e.getMessage());
e.printStackTrace();
}
try {
if (bluetoothSocket != null) {
bluetoothSocket.connect();
Log.i("Bluetooth", "bluetoothSocket.connect() ");
InputStream inputStream = bluetoothSocket.getInputStream();
OutputStream outputStream = bluetoothSocket.getOutputStream();
}
} catch (IOException e) {
e.printStackTrace();
}
bluetoothDevice.createBond method , you can use for paring
For checking paring status , you have to register broadcast receiver
BluetoothDevice.ACTION_BOND_STATE_CHANGED
In your receiver class, you can check blueToothDevice.getBondState
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;
}