I want to just discover peripheral devices when i start my Bluetooth Device discovery, my app must not discover/show other devices. is this any how possible?
this is how i am searching for devices
IntentFilter filter = new IntentFilter("android.bluetooth.devicepicker.action.DEVICE_SELECTED");
registerReceiver(mBtPickReceiver,filter);
startActivity(new Intent("android.bluetooth.devicepicker.action.LAUNCH")
.putExtra("android.bluetooth.devicepicker.action.EXTRA_NEED_AUTH",false));
To reduce (filter) the number of searched devices as per your requirements, check the Class Type of your desired bluetooth device. Once you know the type , you may filter the searched bluetooth devices based on their class type. For example:
BluetoothDevice btd = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if(btd.getBluetoothClass().getDeviceClass() == BluetoothClass.Device.bla_bla_bla)
{
//do whatever you want with the filtered device
}
Related
I am developing an Application that has a BLE device that only shows up on scan when some parameters are sent on scanning.
The App nrf Connect do this task very well (When filter by raw data, and use the 0x02010612435542 raw data parameter).
The device won't show its name, neither it's UUID's, nor manufacturer data.
On nrf Connect, the only thing it shares is a raw return like this: 0X020106124355420000080390BECB49400400CB500CF (which is preciselly what I need right now).
And on scan by Mac Address (testing on one unit of the device), it only gets me its rssi)
My question is, just like nrfConnect, how can I code a filter or something like that, that will be sent as a parameter on scanning, so I can find my devices? The devices doesn't have names (it shows N/A on scan), and I can't add a list of Mac Address filters because there will be tons of devices of the same kind, when my application is finished.
private List<ScanFilter> scanFilters() {
List<ScanFilter> list = new ArrayList<ScanFilter>();
ScanFilter scanFilter = new ScanFilter.Builder().build();
list.add(scanFilter);
//What kind of filter do I use to send that data on scanning?
return list;
}
In your BLE scanner, you receive ScanResult containing an instance of BluetoothDevice i.e. the device scanned. At the very least, you should be able to read the BLE address of the device i.e. its hardware address. Use the method:
BluetoothDevice.getAddress();
This hardware address should have a predefined range, such as starting with "A3:B4" which enables filtering scanRecords. Ask your device manufacturer for how these hardware addresses are generated.
Also, if you know the manufacturer id of the devices you are supporting, you can set a filter based on manufacturer data:
ScanFilter scanFilter = new ScanFilter.Builder()
.setManufacturerData(manufacturerId, manufacturerData)
.build();
Note the first two bytes of the manufacturerData array is the manufacturerId.
EDIT: The manufacturerData are part of the bytes array returned by
scanResult.getScanRecord().getBytes()
The scanResult is passed to the ScanCallback you've given to BluetoothLESCanner.startScan(...)
I finally found the solution to my problem.
It wasn't the way I was thinking, but thanks to #matdev, I managed to figure it out somehow. And it does not answer the main question, i.e. if it is possible to send data to devices on scan, but, the solution works for me.
First, I made a filter by name, in which the device name == null.
private List<ScanFilter> scanFilters() {
List<ScanFilter> list = new ArrayList<ScanFilter>();
ScanFilter scanFilterName = new ScanFilter.Builder().setDeviceName(null).build();
list.add(scanFilterName);
return list;
}
It gave me a huge list with tons of devices. So I added another filter, but this time, on the scanResult(). This other filter is by MAC Address suffix, as pointed by #matdev, it is the same for my devices.
private Set<String> btDeviceData = new LinkedHashSet<String>();
private ScanCallback scanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice device = result.getDevice();
ScanRecord record = result.getScanRecord();
byte[] dataByteArray = record.getBytes();
if (device.getAddress().startsWith("F8:36:9B")) {
btDeviceData.add(device.getAddress());
}
}
};
By doing this, I got a list (Set to be specific) with only the devices I was looking for.
I am using blescan with scanfilters to detect beacons it's working very fine in foreground and background up to oreo version but when it comes to android pie it's not able to send pending broadcast in background.
ScanSettings settings = (new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)).build();
final List<ScanFilter> scanFilters = new ArrayList<>();
scanFilters.add(getScanFilter());
BluetoothAdapter bluetoothAdapter;
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
Intent intent = new Intent(this.getApplicationContext(), MyBroadcastReceiver.class);
intent.putExtra("o-scan", true);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
bluetoothAdapter.getBluetoothLeScanner().startScan(scanFilters, settings, pendingIntent);
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int bleCallbackType = intent.getIntExtra(BluetoothLeScanner.EXTRA_CALLBACK_TYPE, -1);
if (bleCallbackType != -1) {
Log.d(TAG, "Passive background scan callback type: "+bleCallbackType);
ArrayList<ScanResult> scanResults = intent.getParcelableArrayListExtra(
BluetoothLeScanner.EXTRA_LIST_SCAN_RESULT);
// Do something with your ScanResult list here.
// These contain the data of your matching BLE advertising packets
}
}
}
Android 9 introduces several behavior changes, such as limiting background apps' access to device sensors and Wi-Fi scans.
These changes affect all apps running on Android 9, regardless of target SDK version.
Sensors that use the continuous reporting mode, such as accelerometers and gyroscopes, don't receive events.
Android 9 Limited access to sensors in background:
Android 9 limits the ability for background apps to access user input and sensor data. If your app is running in the background on a device running Android 9, the system applies the following restrictions to your app:
Sensors that use the continuous reporting mode, such as accelerometers and gyroscopes, don't receive events.
Sensors that use the on-change or one-shot reporting modes don't receive events.
Solution:
If your app needs to detect sensor events on devices running Android 9 while the app is in the background, use a foreground service.
I an example test Android app using Oreo (API 26) and the the code above (slightly modified) to detect beacons. I am using the Pixel 3 XL (with Pie).
I think that the hard part about this is to know for sure if the code in onRecieve() in MyBroadcastReceiver is actually being run upon detection of a beacon when the device is running on battery only (disconnected from Android-studio and Logcat (USB)).
Using Volley (com.android.volley) to submit a HTTP request to a local http server, I was able to demonstrate that it works as documented - ie. I am able to receive the http request when beacon(s) are detected. However, Volley only sends these these requests when Android is awake or when it periodically wakes up and connects to the network - which in my simple tests was about every 15 minutes (plus some variation), but I did get all the beacon ScanResults on my HTTP server, just in delayed up to 15 minutes. I was even able to remove the app from the list of running apps (you know; swiping up to remove the app) and still see that the onRecieve() in MyBroadcastReceiver was receiving BLE ScanResults.
How do you know that the onRecieve() in MyBroadcastReceiver is being killed? I am very interested to know how you know this.
I have an android application related to bluetooth and I have a question. How can I find out which device is connected to a smartphone? I need to know the device model, I can get the device name, but the user can change it, for example “MEIZU EP51” == >> “My favorite headphones”. I need to get the device model or ID, for example, I connected the Meizu EP51 headphones and I need the phone to recognize exactly the model of these headphones. In the Android documentation, I did not find it, maybe I did not read carefully, I would be grateful for the answer.
You can get the connected ble devices by Bluetooth Manager like this,
BluetoothManager bluetoothManager = (BluetoothManager) this.getSystemService(Context.BLUETOOTH_SERVICE);
List<BluetoothDevice> devices = bluetoothManager.getConnectedDevices(BluetoothProfile.GATT);
As i have Mi Band 3 i can see this connected device over it. But as it is BLE device so it is visible to me but not sure about other devices.
By BluetoothDevice object you can get device name and address. Try it.
Can someone explain me why this code give me back always only one bluetooth device, even if i'm working with two galaxy one next to the other one? This code is running on a Samsung Galaxy Tab and i'm using for tests a Samsung Galaxy Gio both with the right Bluetooth activation. If i check on the default research it works ..but not with this code:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
out = new TextView(this);
setContentView(out);
// Getting the Bluetooth adapter
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
out.append("\nAdapter: " + adapter);
// Check for Bluetooth support in the first place
// Emulator doesn't support Bluetooth and will return null
if (adapter == null) {
out.append("\nBluetooth NOT supported. Aborting.");
return;
}
// Starting the device discovery
out.append("\nStarting discovery...");
adapter.startDiscovery();
out.append("\nDone with discovery...");
// Listing paired devices out.append("\nDevices Paired:");
Set<BluetoothDevice> devices = adapter.getBondedDevices();
for (BluetoothDevice device : devices) {
out.append("\nFound device: " + device);
}
}
I think you are misunderstanding what you are doing.
On one hand by calling this ...
Set devices = adapter.getBondedDevices();
for (BluetoothDevice device : devices) {
out.append("\nFound device: " + device);
}
... you are looking up the already paired devices. If you only get one the reason is simple, you have only one paired. Take into account that this will return all the paired devices, no matter if they are live or not.
On the other hand you are starting a discovery with ...
adapter.startDiscovery();
... However you have not registered a broadcast receiver to process the *BluetoothDevice.ACTION_FOUND* intents that you will receive with each discoverable Bluetooth device seen. Discoverable is key here because by default Android devices are not discoverable and they only allow a maximum time of typical 120 seconds.
Look at the API
http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery()
startDiscovery is asynchronous - it will scan for about 12 seconds and then get the device names of any addresses found in the scan. You don't wait for discovery to finish so it's not surprising that not all devices in range are discovered by the time you check the results.
do you say out.append("\nAdapter: " + adapter);
but if do you are work in eclipse with xml OR INTELLIJ
TextView txt;
String text;
....
text += ("Adapter:" + adapter);
txt.setText(text);
Do you see the error?
I'm writing a program that speaks with an external accessory over rfcomm.
My problem is that I don't know what the correct way of identifying my device is.
the way I do it now is like this:
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter
.getBondedDevices();
for (BluetoothDevice device : pairedDevices) {
if (device.getName().equals(MY_DEVICE_NAME)) {
this.myDevice = device;
break;
}
}
This method however relies on the name of the device which to me seems dirty and bad :)
is there a better way to do this?
I tried looking at all the methods of BluetoothDevice but none seemed to help - is the name really the best way to do it?
I saw that in some places people say that I should use UUIDs but that is used to open the socket to the device once I have it:
_socket = myDevice.createRfcommSocketToServiceRecord(MY_UUID);
is there a better way to do it?
Devices of the same kind/functionality and/or brand will usually have a similar name. For example, all RN-41 devices from Roving Networks have the following name:
FireFly-XXXX
where XXXX is the last 4 digits of the device's address. That means you can use the following to connect to any of them:
if (device.getName().startsWith("FireFly-")) {
this.myDevice = device;
break;
}
This is exactly what I do in my app and haven't found any more reliable/consistent way to do it. As a generalization, you should be able to use a regular pattern if the name in the devices you are interested in is any more complex than the example above.
You can use myDevice.getAddress() to get the bluetooth device address and compare, it will always be unique (unlike name)
You can also use BluetoothDevice.getBluetoothClass() for at narrowing down which devices might be relevant.
BluetoothClass.getMajorDeviceClass() will tell you roughly what kind of device it is - a phone, a computer, an audio or video device, or whatever.
BluetoothClass.hasService() further specifies some capabilities of the device.
Within each of the major classes, some minor classes are defined - what kind of computer / audio-video device / phone / health equipment etc. it is.
Also, on recent versions of the Android platform (API level 15+), you can query for the service records of a device, without having to connect to it. See BluetoothDevice.fetchUuidsWithSdp() and BluetoothDevice.getUuids().