I am trying to make an application like "Bluetooth auto tethering" on play store. I read on the forum that Android is very security-aware and will not enable this setting without user interaction.
I need some explanations about how enable bluetooth tethering.
Thank you
I don't know if this is still an issue or not, but I found that using the connect
method in the reflection call works. Working off of the code that pmont used from the link in Lorelorelore's answer:
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Class<?> classBluetoothPan = null;
Constructor<?> BTPanCtor = null;
Object BTSrvInstance = null;
Method mBTPanConnect;
try {
classBluetoothPan = Class.forName("android.bluetooth.BluetoothPan");
mBTPanConnect = classBluetoothPan.getDeclaredMethod("connect", BluetoothDevice.class);
BTPanCtor = classBluetoothPan.getDeclaredConstructor(Context.class, BluetoothProfile.ServiceListener.class);
BTPanCtor.setAccessible(true);
BTSrvInstance = BTPanCtor.newInstance(myContext, new BTPanServiceListener(myContext));
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
try{
mBTPanConnect.invoke(BTSrvInstance, device);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
Of course, this assumes that the bluetooth is enabled, and you only have one paired device. But enabling bluetooth is pretty straightforward using standard (not reflection) calls, and you can just check for the paired device that you want to connect to in the for
loop. Also, don't forget the BTPanServiceListener
class from the other answer as well.
Hope this helps.
The solution above required some modification in order to work for me. Specifically, the code to enable tethering needs to be in the OnServiceConnected() method. Also I have the following permissions set in the manifest:
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
Here is my solution:
public class BluetoothTethering extends ActionBarActivity {
Object instance = null;
Method setTetheringOn = null;
Method isTetheringOn = null;
Object mutex = new Object();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bluetooth_tethering);
String sClassName = "android.bluetooth.BluetoothPan";
try {
Class<?> classBluetoothPan = Class.forName(sClassName);
Constructor<?> ctor = classBluetoothPan.getDeclaredConstructor(Context.class, BluetoothProfile.ServiceListener.class);
ctor.setAccessible(true);
// Set Tethering ON
Class[] paramSet = new Class[1];
paramSet[0] = boolean.class;
synchronized (mutex) {
setTetheringOn = classBluetoothPan.getDeclaredMethod("setBluetoothTethering", paramSet);
isTetheringOn = classBluetoothPan.getDeclaredMethod("isTetheringOn", null);
instance = ctor.newInstance(getApplicationContext(), new BTPanServiceListener(getApplicationContext()));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public 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) {
//Some code must be here or the compiler will optimize away this callback.
try {
synchronized (mutex) {
setTetheringOn.invoke(instance, true);
if ((Boolean)isTetheringOn.invoke(instance, null)) {
Toast.makeText(getApplicationContext(), "BT Tethering is on", Toast.LENGTH_LONG).show();
}
else {
Toast.makeText(getApplicationContext(), "BT Tethering is off", Toast.LENGTH_LONG).show();
}
}
}
catch (InvocationTargetException e) {
e.printStackTrace();
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(final int profile) {
}
}
}
The below code works perfectly for me
String sClassName = "android.bluetooth.BluetoothPan";
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()));
// Set Tethering ON
Class[] paramSet = new Class[1];
paramSet[0] = boolean.class;
Method setTetheringOn = classBluetoothPan.getDeclaredMethod("setBluetoothTethering", paramSet);
setTetheringOn.invoke(instance,true);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
public 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) {
//Some code must be here or the compiler will optimize away this callback.
Log.e("MyApp", "BTPan proxy connected");
}
@Override
public void onServiceDisconnected(final int profile) {
}
}
Here you find a similar question: Bluetooth question
Just replace "isTetheringOn" with "setBluetoothTethering" in the reflection call and pass in a boolean parameter. It should work.