I connect bluetooth barcode scanner to my android tablet. barcode scanner is bonded with android device as a input device - HID profile. it shows as keyboard or mouse in system bluetooth manager. i discovered that bluetooth profile input device class exist but is hidden. class and btprofile constants have #hide annotaions in android docs.
hidden class:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.3.1_r1/android/bluetooth/BluetoothInputDevice.java
here they should be also 3 other constants
developer.android.com/reference/android/bluetooth/BluetoothProfile.html#HEADSET
just like
public static final int INPUT_DEVICE = 4;
public static final int PAN = 5;
public static final int PBAP = 6;
that constants are simple accessible by reflection.
What i need to achieve, is list of devices by hid profile(INPUT_DEVICE). it should be simple with small changes using method:
developer.android.com/reference/android/bluetooth/BluetoothA2dp.html#getConnectedDevices()
not for A2dp profile, but for hid profile accessed also by reflection methods.
sadly
Class c = Class.forName("android.bluetooth.BluetoothInputDevice")
won't work..
any ideas how i should approach to the problem ? i need only list of hid devices
I figured out how to solve my problem.
That was very helpful.
First of all I needed to prepare reflection method which return input_device hidden constants of hid profile:
public static int getInputDeviceHiddenConstant() {
Class<BluetoothProfile> clazz = BluetoothProfile.class;
for (Field f : clazz.getFields()) {
int mod = f.getModifiers();
if (Modifier.isStatic(mod) && Modifier.isPublic(mod) && Modifier.isFinal(mod)) {
try {
if (f.getName().equals("INPUT_DEVICE")) {
return f.getInt(null);
}
} catch (Exception e) {
Log.e(LOG_TAG, e.toString(), e);
}
}
}
return -1;
}
Instead of that function, I could use value 4, but i want to do it elegant.
Second step was to define listener of specific profile:
BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
#Override
public void onServiceConnected(int profile, BluetoothProfile proxy) {
Log.i("btclass", profile + "");
if (profile == ConnectToLastBluetoothBarcodeDeviceTask.getInputDeviceHiddenConstans()) {
List<BluetoothDevice> connectedDevices = proxy.getConnectedDevices();
if (connectedDevices.size() == 0) {
} else if (connectedDevices.size() == 1) {
BluetoothDevice bluetoothDevice = connectedDevices.get(0);
...
} else {
Log.i("btclass", "too many input devices");
}
}
}
#Override
public void onServiceDisconnected(int profile) {
}
};
In third step I invoked
mBluetoothAdapter.getProfileProxy(getActivity(), mProfileListener,
ConnectToLastBluetoothBarcodeDeviceTask.getInputDeviceHiddenConstant());
Everything clearly works and mProfileListener returns me list of specific profile bluetooth device/-es.
Most interesting thing takes place in onServiceConnected() method, which returs object of hidden class BluetoothInputDevice :)
Related
We are working on Custom Board having Audio Codec, AM/FM Tuner, BT Headset, BT Classic all controlled by I2S peripheral. We wants to route audio from BT Classic to Audio Codec, BT Classic to BT headset and so on.
We were planning to have seperate threads for connecting 2 audio devices. In application space, we will provide seperate device IDs which will indicate what device should play the Audio.
I needs to know how we can create a thread interlinking 2 audio devices? Also, is there any other ways to route various audio devices output to another audio devices?
BluetoothAdapter.getDefaultAdapter().getProfileProxy(this, mScanCallback, BluetoothProfile.A2DP);
BluetoothProfile.ServiceListener mScanCallback = new BluetoothProfile.ServiceListener() {
#Override
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.A2DP) {
proxy.getConnectedDevices().forEach(device -> {
if (selectedDevice1 != null
&& selectedDevice1.getDeviceMAC().equalsIgnoreCase(device.getAddress())) {
try {
Class clazz = Class.forName("android.bluetooth.BluetoothA2dp");
Method method = clazz.getMethod("setActiveDevice", BluetoothDevice.class);
method.invoke(proxy, device);
} catch (Exception e) {
Log.e("TEST", "", e);
}
}
});
}
}
#Override
public void onServiceDisconnected(int i) {
}
};
I am using an Epson TM-P80 printer that is connected to my Android 7 device using Epsons Android SDK. The printer is connected through bluetooth and I can print from my app.
I am having trouble setting up the setReceiveEventListener(), setConnectionEventListener(), and setStatusChangeEventListener() listeners so that I can continuously monitor the status of the printer and display warnings for low battery, low paper, paper jam, cover open, disconnection etc.
Calling connectPrinter() (using a button for testing) will fire off the onPtrStatusChange() listener but only once. I expected mPrinter.setInterval(1000); to report back every second, but this isn't the case. onConnection() is never called. What am I doing wrong?
public class MainActivity extends Activity implements View.OnClickListener, ReceiveListener, ConnectionListener, StatusChangeListener {
private Printer mPrinter = null;
private boolean connectPrinter() {
boolean isBeginTransaction = false;
if (mPrinter == null) {
return false;
}
try {
//mPrinter.connect(mEditTarget.getText().toString(), Printer.PARAM_DEFAULT);
mPrinter.connect("BT:00:01:03:AA:BB:CC", Printer.PARAM_DEFAULT);
// Register the Event Listners
mPrinter.setReceiveEventListener(this);
mPrinter.setConnectionEventListener(this);
mPrinter.setStatusChangeEventListener(this);
// Start monitoring
mPrinter.startMonitor();
mPrinter.setInterval(1000);
}
catch (Exception e) {
ShowMsg.showException(e, "connect", mContext);
return false;
}
#Override
public void onPtrStatusChange(Printer printer, int i) {
// This is only called once
System.out.println("onPtrStatusChange ");
}
#Override
public void onConnection(Object o, int i) {
// This is never outputted
System.out.println("onConnection");
}
}
}
You can view the SDK docs here Epson EPos Android SDK docs
Does anyone have a complete working example of how to programmatically pair with a BLE (not Bluetooth Classic) device that uses passkey entry (i.e. a 6-digit PIN) or Numeric Comparison on Android 4.4 or later? By 'programmatically' I mean I tell Android the PIN - the user isn't prompted.
There are many similar questions about this on SO but they are either a) about Bluetooth Classic, b) old (before setPin() and createBond() were public), or c) unanswered.
My understanding is as follows.
You connect to the device and discover its services.
You try to read a 'protected' characteristic.
The device returns an authentication error.
Android somehow initiates pairing and you tell it the PIN.
You can now read the characteristic.
I have created a device using mBed running on the nRF51-DK and given it a single characteristic.
I set up the security parameters like so:
ble.securityManager().init(
true, // Enable bonding (though I don't really need this)
true, // Require MitM protection. I assume you don't get a PIN prompt without this, though I'm not 100% sure.
SecurityManager::IO_CAPS_DISPLAY_ONLY, // This makes it us the Passkey Entry (PIN) pairing method.
"123456"); // Static PIN
And then in the characteristic I used
requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
Now when I try to read it with the Nordic Master Control Panel, I get a pairing request notification like this:
And I can put this PIN in, and then MCP says I'm bonded, and can read the characteristic.
However, in my app I would like to avoid having the user enter the PIN, since I know it already. Does anyone have a complete recent example of how to do this?
Edit: By the way this is the most relevant question I found on SO, but the answer there doesn't seem to work.
I almost have it working. It pairs programmatically but I can't get rid of the "Pairing request" notification. Some answers to this question claim to be able to hide it just after it is shown using the hidden method cancelPairingUserInput() but that doesn't seem to work for me.
Edit: Success!
I eventually resorted to reading the source code of BluetoothPairingRequest and the code that sends the pairing request broadcast and realised I should be intercepting the ACTION_PAIRING_REQUEST. Fortunately it is an ordered intent broadcast so you can intercept it before the system does.
Here's the procedure.
Register to receive BluetoothDevice.ACTION_PAIRING_REQUEST changed broadcast intents. Use a high priority!
Connect to the device.
Discover services.
If you have disconnected by now, it's probably because the bond information is incorrect (e.g. the peripheral purged it). In that case, delete the bond information using a hidden method (seriously Google), and reconnect.
Try to read a characteristic that requires encryption MitM protection.
In the ACTION_PAIRING_REQUEST broadcast receiver, check that the pairing type is BluetoothDevice.PAIRING_VARIANT_PIN and if so, call setPin() and abortBroadcast(). Otherwise you can just let the system handle it, or show an error or whatever.
Here is the code.
/* This implements the BLE connection logic. Things to watch out for:
1. If the bond information is wrong (e.g. it has been deleted on the peripheral) then
discoverServices() will cause a disconnect. You need to delete the bonding information and reconnect.
2. If the user ignores the PIN request, you get the undocumented GATT_AUTH_FAILED code.
*/
public class ConnectActivityLogic extends Fragment
{
// The connection to the device, if we are connected.
private BluetoothGatt mGatt;
// This is used to allow GUI fragments to subscribe to state change notifications.
public static class StateObservable extends Observable
{
private void notifyChanged() {
setChanged();
notifyObservers();
}
};
// When the logic state changes, State.notifyObservers(this) is called.
public final StateObservable State = new StateObservable();
public ConnectActivityLogic()
{
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Tell the framework to try to keep this fragment around
// during a configuration change.
setRetainInstance(true);
// Actually set it in response to ACTION_PAIRING_REQUEST.
final IntentFilter pairingRequestFilter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
pairingRequestFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY - 1);
getActivity().getApplicationContext().registerReceiver(mPairingRequestRecevier, pairingRequestFilter);
// Update the UI.
State.notifyChanged();
// Note that we don't actually need to request permission - all apps get BLUETOOTH and BLUETOOTH_ADMIN permissions.
// LOCATION_COARSE is only used for scanning which I don't need (MAC is hard-coded).
// Connect to the device.
connectGatt();
}
#Override
public void onDestroy()
{
super.onDestroy();
// Disconnect from the device if we're still connected.
disconnectGatt();
// Unregister the broadcast receiver.
getActivity().getApplicationContext().unregisterReceiver(mPairingRequestRecevier);
}
// The state used by the UI to show connection progress.
public ConnectionState getConnectionState()
{
return mState;
}
// Internal state machine.
public enum ConnectionState
{
IDLE,
CONNECT_GATT,
DISCOVER_SERVICES,
READ_CHARACTERISTIC,
FAILED,
SUCCEEDED,
}
private ConnectionState mState = ConnectionState.IDLE;
// When this fragment is created it is given the MAC address and PIN to connect to.
public byte[] macAddress()
{
return getArguments().getByteArray("mac");
}
public int pinCode()
{
return getArguments().getInt("pin", -1);
}
// Start the connection process.
private void connectGatt()
{
// Disconnect if we are already connected.
disconnectGatt();
// Update state.
mState = ConnectionState.CONNECT_GATT;
State.notifyChanged();
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(macAddress());
// Connect!
mGatt = device.connectGatt(getActivity(), false, mBleCallback);
}
private void disconnectGatt()
{
if (mGatt != null)
{
mGatt.disconnect();
mGatt.close();
mGatt = null;
}
}
// See https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/master/stack/include/gatt_api.h
private static final int GATT_ERROR = 0x85;
private static final int GATT_AUTH_FAIL = 0x89;
private android.bluetooth.BluetoothGattCallback mBleCallback = new BluetoothGattCallback()
{
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState)
{
super.onConnectionStateChange(gatt, status, newState);
switch (newState)
{
case BluetoothProfile.STATE_CONNECTED:
// Connected to the device. Try to discover services.
if (gatt.discoverServices())
{
// Update state.
mState = ConnectionState.DISCOVER_SERVICES;
State.notifyChanged();
}
else
{
// Couldn't discover services for some reason. Fail.
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
}
break;
case BluetoothProfile.STATE_DISCONNECTED:
// If we try to discover services while bonded it seems to disconnect.
// We need to debond and rebond...
switch (mState)
{
case IDLE:
// Do nothing in this case.
break;
case CONNECT_GATT:
// This can happen if the bond information is incorrect. Delete it and reconnect.
deleteBondInformation(gatt.getDevice());
connectGatt();
break;
case DISCOVER_SERVICES:
// This can also happen if the bond information is incorrect. Delete it and reconnect.
deleteBondInformation(gatt.getDevice());
connectGatt();
break;
case READ_CHARACTERISTIC:
// Disconnected while reading the characteristic. Probably just a link failure.
gatt.close();
mState = ConnectionState.FAILED;
State.notifyChanged();
break;
case FAILED:
case SUCCEEDED:
// Normal disconnection.
break;
}
break;
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status)
{
super.onServicesDiscovered(gatt, status);
// Services have been discovered. Now I try to read a characteristic that requires MitM protection.
// This triggers pairing and bonding.
BluetoothGattService nameService = gatt.getService(UUIDs.NAME_SERVICE);
if (nameService == null)
{
// Service not found.
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
return;
}
BluetoothGattCharacteristic characteristic = nameService.getCharacteristic(UUIDs.NAME_CHARACTERISTIC);
if (characteristic == null)
{
// Characteristic not found.
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
return;
}
// Read the characteristic.
gatt.readCharacteristic(characteristic);
mState = ConnectionState.READ_CHARACTERISTIC;
State.notifyChanged();
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status)
{
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS)
{
// Characteristic read. Check it is the right one.
if (!UUIDs.NAME_CHARACTERISTIC.equals(characteristic.getUuid()))
{
// Read the wrong characteristic. This shouldn't happen.
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
return;
}
// Get the name (the characteristic I am reading just contains the device name).
byte[] value = characteristic.getValue();
if (value == null)
{
// Hmm...
}
disconnectGatt();
mState = ConnectionState.SUCCEEDED;
State.notifyChanged();
// Success! Save it to the database or whatever...
}
else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION)
{
// This is where the tricky part comes
if (gatt.getDevice().getBondState() == BluetoothDevice.BOND_NONE)
{
// Bonding required.
// The broadcast receiver should be called.
}
else
{
// ?
}
}
else if (status == GATT_AUTH_FAIL)
{
// This can happen because the user ignored the pairing request notification for too long.
// Or presumably if they put the wrong PIN in.
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
}
else if (status == GATT_ERROR)
{
// I thought this happened if the bond information was wrong, but now I'm not sure.
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
}
else
{
// That's weird.
disconnectGatt();
mState = ConnectionState.FAILED;
State.notifyChanged();
}
}
};
private final BroadcastReceiver mPairingRequestRecevier = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction()))
{
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int type = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR);
if (type == BluetoothDevice.PAIRING_VARIANT_PIN)
{
device.setPin(Util.IntToPasskey(pinCode()));
abortBroadcast();
}
else
{
L.w("Unexpected pairing type: " + type);
}
}
}
};
public static void deleteBondInformation(BluetoothDevice device)
{
try
{
// FFS Google, just unhide the method.
Method m = device.getClass().getMethod("removeBond", (Class[]) null);
m.invoke(device, (Object[]) null);
}
catch (Exception e)
{
L.e(e.getMessage());
}
}
}
I also faced the same problem and after all the research, I figured out the below solution to pair to a BLE without any manual intervention.
(Tested and working!!!)
I am basically looking for a particular Bluetooth device (I know MAC address) and pair with it once found. The first thing to do is to create pair request using a broadcast receiver and handle the request as below.
IntentFilter intentFilter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
registerReceiver(broadCastReceiver,intentFilter);
You need to write the broadcastReceiver and handle it as below.
String BLE_PIN = "1234"
private BroadcastReceiver broadCastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action))
{
BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
bluetoothDevice.setPin(BLE_PIN.getBytes());
Log.e(TAG,"Auto-entering pin: " + BLE_PIN);
bluetoothDevice.createBond();
Log.e(TAG,"pin entered and request sent...");
}
}
};
Voila! You should be able to pair to Bluetooth device without ANY MANUAL INTERVENTION.
Hope this helps :-) Please make it right answer if it works for you.
I am trying to send all the audio of an application via SCO.
I am able to successfully send the audio,
But when an incoming call comes I need to disconnect form SCO so that the application audio will not interfere with the call,
The problem is that, when I try to reroute the audio to SCO after the call, it does not work.
Here is the code I use to send the audio to SCO:
public class BluetoothManager {
// For Bluetooth connectvity
private static String TAG = "BluetoothManager";
private static BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
private static AudioManager aM;
/**
* Set the audio manager of the device.
* #param c: The context this method is called from
*/
public static void setAudioManager(Context c) {
aM = (android.media.AudioManager)c.getSystemService(Context.AUDIO_SERVICE);
}
/**
* Check if a Bluetooth headset is connected. If so, route audio to Bluetooth SCO.
*/
private static void initializeAudioMode(Context context) {
BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET) {
BluetoothHeadset bh = (BluetoothHeadset) proxy;
List<BluetoothDevice> devices = bh.getConnectedDevices();
if (devices.size() > 0) {
enableBluetoothSCO();
}
}
mBluetoothAdapter.closeProfileProxy(profile, proxy);
}
public void onServiceDisconnected(int profile) {}
};
mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET);
}
/**
* Bluetooth Connectvity
* The following methods are associated with enabling/disabling Bluetooth.
* In the future we may want to disable other sources of audio.
*/
private static void enableBluetoothSCO() {
aM.setMode(AudioManager.MODE_IN_CALL);
aM.startBluetoothSco();
aM.setBluetoothScoOn(true);
}
/** Right now, this simply enables Bluetooth */
#SuppressLint("NewApi")
public static boolean enableBluetooth(Context c) {
// If there is an adapter, enable it if not already enabled
if (mBluetoothAdapter != null) {
if (!mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.enable();
}
setAudioManager(c);
initializeAudioMode(c);
Log.e(TAG, "SCO: " + aM.isBluetoothScoOn());
Log.e(TAG, "A2DP: " + aM.isSpeakerphoneOn());
return true;
} else {
Log.v(TAG, "There is no bluetooth adapter");
return false;
}
}
/** Right now, this simply disables Bluetooth */
public static void disableBluetooth() {
// If there is an adapter, disabled it if not already disabled
if (mBluetoothAdapter != null) {
if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.disable();
}
} else {
Log.v(TAG, "There is no bluetooth adapter");
}
}
public static void restartBluetooth(){
aM.setMode(AudioManager.MODE_IN_CALL);
}
public static void stopBluetooth(){
aM.setMode(AudioManager.MODE_NORMAL);
}
}
When I call stopBluetooth() correctly the audio of the application is not sent to the headset anymore,
But when I call restartBluetooth() the audio plays NOT form the headset as intended, but from the phone speakers.
Is it possible that the SCO link was brought down after the call ended? If this is the case then the SCO link would also have to be brought up along with routing the audio.
Have you tried calling enableBluetoothSCO() within restartBluetooth()
You probably need to call:
aM.startBluetoothSco();
aM.setBluetoothScoOn(true);
after you set the mode.
inside your restart function initialize everything again, and see if it works. like so:
public static void restartBluetooth(){
enableBluetooth(getApplicationContext());
}
if this works then it means that when the call is ended the last initialization is lost for some reason.
Google Doc say's that
"Phone application always has the priority on the usage of the SCO connection for telephony. If this method is called while the phone is in call it will be ignored. Similarly, if a call is received or sent while an application is using the SCO connection, the connection will be lost for the application and NOT returned automatically when the call ends."
So when call is disconnected you must have to re-establish the connection by calling startBluetoothSco()
For anyone that is still having issues with this, there are a few things that need to be done. The first thing you need to do is to keep track of the phone state. You can see how to do that here:
How to know Phone call has ended?
When the state is idle that means the incoming call has ended. Now if you try to reconnect the bluetooth at this point you'll find it still does not work since it takes a while (roughly 2 seconds) for the call to "release" the bluetooth device.
So you have two option, wait a bit then try to reconnect, or you can add another listener to BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED.
You can then add a global boolean value isIdle that is true when TelephonyManager.CALL_STATE_IDLE or false when TelephonyManager.CALL_STATE_OFFHOOK (Otherwise you'll reconnect to BlueTooth during the incoming call). At this point when BluetoothHeadset.STATE_DISCONNECTED and isIdle is true, then reconnect to Bluetooth.
#Override public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals((BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED))){
int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
switch(state) {
case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
if (isIdle){
//reconnect bluetooth
}
break;
}
}
if(("OFFHOOK").equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE))) {
isIdle = false;
// turn bluetooth off
}
if(("IDLE").equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE))) {
isIdle = true;
}
}
The Android bluetooth class is fairly easy to use with regards to enabling, discovering, listing paired devices, and connecting to bluetooth devices.
My plan was to initiate a connection to another bluetooth device that provides tethering via bluetooth.
After a bit of investigation, this doesn't look feasible - it looks like I'd have to implement the profile myself, and have root access to do the networking, and do everything in an app.
There also doesn't seem to be an intent I can trigger via Settings to initiate a bluetooth connection, the best I can do is turn it on.
Am I missing something - if the system doesn't expose a method for initiating a system level bluetooth connection, am I out of luck?
A private profile is already present in the API: BluetoothPan
Bluetooth PAN (Personal Area Network) is the correct name to identify tethering over Bluetooth.
This private class allows you to connect to and disconnect from a device exposing the PAN Bluetooth Profile, via the public boolean connect(BluetoothDevice device) and public boolean disconnect(BluetoothDevice device) methods.
Here is a sample snippet connecting to a specific device:
String sClassName = "android.bluetooth.BluetoothPan";
class BTPanServiceListener implements BluetoothProfile.ServiceListener {
private final Context context;
public BTPanServiceListener(final Context context) {
this.context = context;
}
#Override
public void onServiceConnected(final int profile,
final BluetoothProfile proxy) {
Log.e("MyApp", "BTPan proxy connected");
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice("AA:BB:CC:DD:EE:FF"); //e.g. this line gets the hardware address for the bluetooth device with MAC AA:BB:CC:DD:EE:FF. You can use any BluetoothDevice
try {
Method connectMethod = proxy.getClass().getDeclaredMethod("connect", BluetoothDevice.class);
if(!((Boolean) connectMethod.invoke(proxy, device))){
Log.e("MyApp", "Unable to start connection");
}
} catch (Exception e) {
Log.e("MyApp", "Unable to reflect android.bluetooth.BluetoothPan", e);
}
}
#Override
public void onServiceDisconnected(final int profile) {
}
}
try {
Class<?> classBluetoothPan = Class.forName(sClassName);
Constructor<?> ctor = classBluetoothPan.getDeclaredConstructor(Context.class, BluetoothProfile.ServiceListener.class);
ctor.setAccessible(true);
Object instance = ctor.newInstance(getApplicationContext(), new BTPanServiceListener(getApplicationContext()));
} catch (Exception e) {
Log.e("MyApp", "Unable to reflect android.bluetooth.BluetoothPan", e);
}