I'm developing an Android app that has to exchange some data through BT by automatically create a communication between two devices. To do so the only way (I've found) is to first make the device find each other and then negotiate a master who will open a ServerSocket and host the connection.
My problem then is how to toggle BT discoverability without prompting the request to the user!
I've searched the net with no success, so I start thinking about possible solution.
First I thought about something like a BroadcastReceiver that would catch the request instead the default activity launched by StartActivity(new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE)), but then I wouldn't know what to do to actually make the device discoverable.
Recently I've thought about hiding or dismissing the dialog raised by the precedent call by automatically selecting the positive button. Once again I've no clue on how to do it!
Any help will be really appreciate, thank you in advance to everyone and sorry for my bad English!
I can't point to any explicit documentation, but I'm pretty sure you're not allowed to silently turn on and off Bluetooth in android. Bluetooth discoverability is something that at the end of the day is always up to the user. To subvert their authority presents a huge security concern.
You can call .enable() on an instance of BluetoothAdapter
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
bluetoothAdapter.enable();
Related
How can we listen for special BT device commands like redial from our app? For now, I'm only able to listen to the only one - play/pause/start/end call button (KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE).
Using common BroadcastReceiver for "android.intent.action.MEDIA_BUTTON" doesn't help.
Solution with BluetoothSocket, BluetoothServerSocket won't help too since it requires our code to be invoked on BT device side.
During my redial button tests I see the next line in the logs:
01-20 05:52:30.486 942-1060/com.android.bluetooth E/bt-rfcomm: PORT_DataInd, p_port:0x5526c200, p_data_co_callback is null
It looks like there is something sending an event from BT device to the android device. But how can we catch it on app side, what should we use? I work on some system app by the way and theoretically can do very specific, low-level and system things, so maybe there could be some solution.
afaik, this isn't possible, sadly...
I've been working on custom handling BT headset keys, like VOL UP, DOWN, eventually ANSWER/DISCONNECT/REDIAL. Even made rich question, but without single answer or comment...
After some research (days, weeks...) and digging into Android source I've found that these buttons are sending some AT commands. I've also found methods which are checking these AT commands and if system is able to respond/handle them then it TRY to do it and further won't pass any event to any app/socket/rfcomm/anything... E.g. under VOL UP button we have some well-known AT command, system can handle it, so try to do so, even when we already have volume set to max. Any app won't be noticed that this happened...
btw. I don't think this logcat line posted in question is strictly relevant to button press (but may be indirectly), but you have bt-rfcomm keyword in there, so you may try to establish some RFCOMM connection with Bluetooth device, maybe you will get some luck on this topic... (personally I gave up...)
I am tring to setup WIFI P2P on 2 devices using
manager.addLocalService(channel, service, ActionListener)
and then connect both devices using
manager.connect(channel, config, ActionListener).
I would like to know which method is called before the popup to accept/reject connection is shown on the target device. All I was able to find was onConnectionInfoAvailable(WifiP2pInfo p2pInfo), but it is called after the connection is established.
I basically want to receive the "instance name" of the device trying to connect to me using WIFI P2P and then reject the connection request without showing system dialog(that allows the user to accept/reject connection).
I can't anything that can help me do this on docs or any other place. If anyone knows how to do it or can point me in the right direction then please let me know.
I solved it. I can put the instancename and devicename (of device I want to connect to) in Map that is passed when setting up service. From other device I can retrieve map of all devices available using this and find the instancename of one I need.
I've a simple service to pair bluetooth devices and it look like this:
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
if(!extras.containsKey("bluetoothAddress"))
return;
String bluetoothAddress = extras.getString("bluetoothAddress");
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if(!adapter.isEnabled()) {
adapter.enable();
}
BluetoothDevice device = adapter.getRemoteDevice(bluetoothAddress);
device.createBond();
}
It works perfectly fine except that sometimes the pair dialogue pop up and sometimes it show up in my notifications bar and I have to open it manually. Is there any way to make sure that it always pop up to the front?
I've tried to google on it and only thing I can find is that if you stay in bluetooth settings it always pop up, but that seems like a ugly solution. The reason for all of this is that I'm working with automation and want to make sure that when I run my service I get the pair dialogue can just click "Pair".
I had the same problem. I've found this post that explains when the dialog is shown or not: Bluetooth pairing request on notification bar?
Resuming, it depends on the result of the shouldShowDialogInForeground() method.
Quoting from the post:
... there are ways of making the dialog show:
If the device was in discoverable mode recently
If the device was discovering recently
If the device was picked in the device picker recently
If Bluetooth Settings is visible
In my case to force the dialog to appear, I started and canceled a discovery before trying to pair...
Code/Hack
BluetoothAdapter.getDefaultAdapter().startDiscovery();
//Give it some time before cancelling the discovery
Thread.sleep(1000);
BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
//Then do the LeScan and connect to the device
PS:I know it's a horrible hack but is the only way I got this to work, and the pairing must be done only once for device so it's not so terrible... Also, if anybody finds a better way I'm open to suggestions
I use following code to resolve the issue
if(!BluetoothAdapter.getDefaultAdapter().isDiscovering())
BluetoothAdapter.getDefaultAdapter().startDiscovery();
//make sure that the device is in discovering
while (!BluetoothAdapter.getDefaultAdapter().isDiscovering());
BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
Does anyone know if its possible (programatically) to enable both 3G and WiFi to be used simultaneously, both receiving and sending packets?
I have seen various other questions on here, but with the Tethering ability inside Android now, I was wondering if this is a possibility? This has to be on a standard/stock device, and no modifications via root to the OS.
Thanks
Adam
I don't believe it is, as soon as wifi is turned on, 3g will automatically disconnect. As far as I know there is no way round it.
The only way you can achieve this is by using a APN name with the HttpConnection. This is possible in Java ME, Please visit this answer, however i have never tried it.
You need to check for the active connection, if not active first one the switch to the next connection.
public void shutup(){
SuDroid cmd = new SuDroid();
cmd.sh.runWaitFor("svc wifi enable");
cmd.sh.runWaitFor("svc data enable");
cmd.sh.runWaitFor("svc data prefer");
}
Using SuDroido
I have an app where I am programmatically controlling Bluetooth pairing and unpairing. I can pair before connection and unpair afterwards. The reason I need to do this is specific to my application and not in the scope of my question.
Basically what I am doing is:
Get a reference ib to IBluetooth object as described in this answer
Register a BroadcastReceiver for android.bluetooth.device.action.PAIRING_REQUEST
Call ib.createBond(address)
Wait for BroadcastReceiver to trigger
Convert user pin into bytes with convertPinToBytes()
Call ib.setPin(address, pinBytes) from within BroadcastReceiver
Anyways, this approach works great, except for the fact that when I do the pairing, I get a notification in the Status bar requesting that the user enter a PIN to complete the pairing. But this is in fact unnecessary, because by the time the user sees this, my app has already used setPin(). I'd really like for that notification to either a) not appear at all, or b) be dismissed automatically somehow.
I realize this may not even be possible, but I thought I would ask in case someone has a creative idea.
Try setting the confirmation first in the PAIRING_REQUEST
BluetoothDevice device = intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE");
device.getClass().getMethod("setPairingConfirmation", boolean.class).invoke(device, true);
device.getClass().getMethod("cancelPairingUserInput").invoke(device);
This worked for me between two Android devices using RFCOMM but I'm not entering any PINs
Since Android API 19 Google switched these Methods to public Methods, so there is no need for Reflection any more. :)
Do this in the PAIRING_REQUEST notification event:
BluetoothDevice localBluetoothDevice = (BluetoothDevice)intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE");
Class localClass = localBluetoothDevice.getClass();
Class[] arrayOfClass = new Class[0];
localClass.getMethod("cancelPairingUserInput", arrayOfClass).invoke(paramBluetoothDevice, null)).booleanValue();
But you gotta tell me how did you pair your remote device without the user to enter Passkey/PIN? off course, you know the PIN for the remote device which is trying to pair to your device but how did you provide that PIN to the remote device.