I am developing an android app where users must be able to see other users nearby them and send a message to that user specifically. I was hoping Bluetooth would be a good, low-energy solution to this. My trouble is in identifying nearby Bluetooth devices only if they are using this app, and ignoring all others, such as portable speakers and whatnot. Could anybody maybe point me in the right direction on this one?
As far as limiting the discovery, this seems not possible at this point in time. The only way I can think of where this would really be possible is if their device name had a particular string in it that you used to filter, but this isn't really something I would look into as people probably won't go as far as changing the name of their device just for an app.
You can use the following to change the device name, I would recommend getting permission & maybe appending the device's previous name onto whatever string you want to look for
BluetoothAdapter mBtAdapter = BluetoothAdapter.getDefaultAdapter();
mBtAdapter.setName("");
I don't think if you are in the middle of a connection it would end it, as a bluetooth connection is made using the devices bluetooth MAC address, not the devices name
Related
I'm developing an android BLE app in which i try to establish a stable Connection between the app and a BLE device.
To achieve this i want my app to keep the BLE device data in shared preferences or somewhere.
After app close, i'd like my app to retrive this data and attemp a connection without scan for devices.
I prefer to avoid scanning every time becouse scan gives me a lot of problems and it takes time.
How can do it? Is there a way to save BLE data?
You need to store the Bluetooth Device Address (AB:CD:EF:01:02:03) of the device in for example shared preferences or in a sqlite db. Then use https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getRemoteDevice(java.lang.String) when you later restart the app to retrieve a BluetoothDevice object. Once you have the BluetoothDevice object you can use the connectGatt method as usual.
There are some undocumented things you need to keep in mind however. Due to some horrible design flaws in Android's BLE API there is no way to tell it if you mean the given address is a Public Address or a Random Address. (You can read more about different address types at https://devzone.nordicsemi.com/question/43670/how-to-distinguish-between-random-and-public-gap-addresses/). The getRemoteDevice method should take an additional parameter "random address/public address" but it doesn't. Without the correct address type, the Bluetooth controller cannot connect to the device.
Android's BLE stack has some internal heuristics to "guess" if the address is public or random, but unfortunately that differs between Android versions and also if you use autoConnect=true or false. However if you have bonded the device (https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createBond()) then it will store in its internal DB whether the given address is public or random. If the peripheral you want to connect to uses a random resolvable address it can handle that as well if you use bonding. Therefore I strongly suggest to use bonding.
If you don't use bonding you will need to scan before you connect to the device, since when you start a scan and a device is detected, Android's BLE stack will temporarily (until next restart of Bluetooth) remember the address type for an address.
I will continue on Emil's answer.
Thanks #Emil for the 'big picture'.
Google API is flawed and you can't use getRemoteDevice() because it only understand 48bit address and do not know about all BLE address types.
You can't use Bonding if the device is dumb (anyone would be able to bond to it).
So your only solution is a Bluetooth scan.
However, since Android6 (Marshmallow) the user has to give location permission to apps using Bluetooth scanning. If you don't permit, it won't work.
So if you buy a Bluetooth thermometer (or heart-rate monitor or whatever), you have to permit the app to access location of your phone (or tablet).
That's absurd!
#Emil call it a 'Google flaw'. You may also call it a 'Google machination'.
If I was a thermometer designer, I would add a push-button to accept bonding. It seems ridiculous because the button will only be used once.
[1]: https://www.polidea.com/blog/a-curious-relationship-android-ble-and-location/
Is there any simple way to check if an existing BluetoothDevice object is still reachable without performing a new scan?
I am writing an app that scans for devices and goes through connecting to each one at a time to populate a device list with some information about each device, which I acquire while connected to the device. Every now and again, I would like to go through my device list and remove any devices that are no longer active/in range. What is the best way to do this?
You could try to connect to the devices to find out if they are still around, but keep in mind, that devices will change their mac address from time to time.
I would suggest to use scanning to find out if the devices are still around. Also you may want to add an identifier into the advertisement packages, so you don't need to relay on the mac address.
I have made an app on iOS and Android that can connect to a BLE device. I connect to the "device by service" and things work well.
A customer is asking me why the device is not showing in the list of bonded bluetooth devices. I didn't need pairing to connect because I found code that didn't require it, but now that I think, I wonder :
What would be the benefits to have a paired device ?
Would it connect faster ? Hold connection better ? ...
Security, mainly.
Sending data to a non-paired device requires that the device be discoverable and open to receiving data from random devices. This isn't always the case for reasons of security, and so many devices ship with both disabled.
The attack vector is something like this: you'll always have to pick a device in the list of discovered devices. It's not too difficult to create a device with "<CEO>'s iPhone" as the name and wait until he tries to send the secret memorandum to his iPhone, then intercept it.
Additionally, bluetooth stacks have been known to have vulnerabilities that can be exploited by sending data to the device, which was made more problematic by devices auto-accepting data without confirmation.
Paired devices create a pre-existing relationship between the two, allowing your user to be notified when something out of the ordinary happens. This is always a good thing.
It is indeed also true that not having to go through device discovery (which may take up to a few seconds) improves performance when doing the initial connection setup, but I wouldn't see that as the major reason.
I'd like to use android's bluetooth for some kind of sensing devices. But I don't want to connect to these devices. As far as I know Devices won't react to scanning when their own bluetooth is disabled. But is there any way to get my app noticed when such a scan has been performed by a remote device, even when my app is running with bluetooth turned off?
I don't want to force toggling bluetooth on, but I need to get some kind of Action started in other devices running the same app. So I'm wondering if some there is any description/data field that can be sent with a bluetooth scan, so if scan is rejected the app has the opportunity to read that data just to know there was this specific call?
I need to leverage context-awareness within my system as to users, not knowing each other, still can interchange content (if they agree). But I need to find some ways of sensing while I also don't want to have all sensors activated all the time.
Hope you can give me a hint, or tell me that this is simply not possible, which would also help me not spending any more time on that.
Thanks.
I was reading this
http://developer.android.com/guide/topics/wireless/bluetooth.html#QueryingPairedDevices
which is allot of help on how to pair,connect to a bluetooth device.
I have a situation where I have several BT devices that are in Non-Discover mode always. I know the MAC and the PIN of these devices. IS there a way in Android Dev to manually add devices to the PAIRED list so i can just use the connect as a client.
I understand this maual is written allot for V3. i think i will need to do this on 2.0 ; 2.1- has anybody done this before?
Basically these devices I want to connect to are power saving modules I used pre built BT modules to monitor daylight, another one humidity, etc.. every 3hrs or when interrupted and runs of a single battery for months. So turning off divcory on server saves immense power and prevents other people trying to connect and waste battery.
Not sure what you mean by "manually": Do you mean "manually" as in GUI/user interaction, or "manually" as "I do it in my own application code"?
Some suggestions though:
If you can make your BT devices discoverable at all, you could do it this way:
Make your BT device discoverable
Let Android search for and find the device and then initiate a connection
Android will ask for the PIN for pairing with the device; enter the PIN.
Once pairing was successful, Android stores the pairing information for future use, so that you can
Make your BT device invisible again.
From then on your app should be able to connect to the BT device at any time without further pairing operations.
If the said is not an option for you, maybe you want to go another way:
In current Android versions there are different API routines implemented which are neither documented nor exposed in the normal SDK. A hack kind of solution may be to use some of these "hidden" ("#hide"...) APIs, either via reflection or via modification of your SDK installation.
But be aware that this is always a hack and it may work on a specific device with a specific version of Android and is likely to break your app on another device and/or any other Android version.
Having said that, here comes some reference:
Example of how to access "hidden" bluetooth API.
Then, have a look at the source code for android.bluetooth.BluetoothDevice, e.g. here.
In there, public boolean createBond(){...} may do what you want.