I'm developing an App using BLE and I need to be able to connect to Android and iOS devices.
I have 3 Samsung Devices, 3 iPhones and one Huawei with Android for testing purposes.
I have an issue with the Huawei device..when scanning for advertisements, Huawei finds all Android devices but no iOS ones. But if I turn bluetooth off and on again, it will find the iOS devices this time if I scan. But only the first time, it won't find them again afterwards until I turn bluetooth off/on again.
Again..only the Huawei is having these issues..what can be the cause?
I scan/advertise like this:
val settings = AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
.setConnectable(true)
.build()
val pUuid = ParcelUuid(UUID.fromString(BluetoothStringsValues.SERVICE_UUID))
val data = AdvertiseData.Builder()
.setIncludeDeviceName(false)
.addServiceUuid(pUuid)
.addServiceData(pUuid, stringToAdvertise.toByteArray(Charset.forName("UTF-8")))
.build()
advertiser.startAdvertising(settings, data, advertisingCallback)
val filter = ScanFilter.Builder()
.setServiceUuid(ParcelUuid(UUID.fromString(SERVICE_UUID)))
.build()
val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_BALANCED)
.build()
bluetoothLeScanner.startScan(listOf(filter), settings, bleScanCallback)
thanks for the help!
Related
I have an issue related to the headset mic in my android app.
This headset is working absolutely fine with all other apps on this device, but I can’t get audio from it my app. Also this app works fine with headsets on other devices.
Can’t reproduce with other headsets and devices. Same time other wireless headset works fine with my app
Android 12
Device Samsung A12
SDK 31
I use code below
val playbackAttributes = AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build()
val audioFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
.setAudioAttributes(playbackAttributes)
.setAcceptsDelayedFocusGain(true)
.setOnAudioFocusChangeListener { }
.build()
audioManager.requestAudioFocus(audioFocusRequest)
val wired = audioManager.availableCommunicationDevices.firstOrNull { it.type == TYPE_WIRED_HEADSET }
audioManager.mode = AudioManager.MODE_IN_COMMUNICATION
audioManager.setCommunicationDevice(currentDevice)
I am trying to run a background service which runs all the time and scans for BLE advertisements.
I started a service. It works as expected and runs all the time. When restarting the background service (after closing the activity), I am starting the BLE scan:
mBluetoothLeScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();
ScanFilter.Builder builder = new ScanFilter.Builder();
builder.setManufacturerData(0x0590,new byte[]{});
ScanFilter filter = builder.build();
filters = new ArrayList<ScanFilter>();
filters.add( filter );
ScanSettings settings = new ScanSettings.Builder()
.setScanMode( ScanSettings.SCAN_MODE_LOW_LATENCY )
.build();
// mBluetoothLeScanner.stopScan(mScanCallback);
mBluetoothLeScanner.startScan(filters, settings, mScanCallback);
It works for 30-50 seconds. After that time, the scan callback does not send advertisement data.
Do you have any idea why it is stopped and what can I do? Is iBeacon or Eddystone a better solution? My intention is to continuesly listen for a message from a BLE device in the background while the app is closed. I am using android 8.1 with Xiaomi Redmi 5.
After android 8 google add some Background limits you can read it
As i know you have two option one is use JobScheduler an other way use ForgroundServices(I use this)
I am using pixel with latest android 8.1.0 update.
I am facing issue related to BLE advertisement scanning. Whenever I turned off the screen(i.e power button press) my scanning will stop.
it will restart immediately after turn on the screen.
I have checked latest code for BLE. google newly introduce this feature (Reference Link).
Is there any way to skip this part, I mean scan should not stop regardless of the screen on or off.
As of Android 8.1, unfiltered bluetooth scans are blocked when the screen is turned off. While it is surprising for such a dramatic change to be made in a minor release of Android, this is certainly an intended change based on the comments in the commit:
Stop unfiltered BLE scans when the screen goes off.
The workaround is to use a ScanFilter with all scans. The new 8.1 operating system code simply verifies that any scans active when the screen is off have at least one scan filter. If those conditions are met the scan results are delivered as in Android 8.0.x and earlier.
In order to set up such a scan, you must use the APIs introduced in Android 5.0 and create a ScanFilter with each scan. Below is a filter that will find manufacturer advertisements for any device from Apple with manufacturer ID 0x004c (this will include iBeacons):
ScanFilter.Builder builder = new ScanFilter.Builder();
builder.setManufacturerData(0x004c, new byte[] {});
ScanFilter filter = builder.build();
Similarly, if you are interested in GATT Service advertisements (like the kind used with Eddystone beacons) you can search for a GATT Service UUID with a filter like this:
ScanFilter.Builder builder = new ScanFilter.Builder();
String serviceUuidString = "0000feaa-0000-1000-8000-00805f9b34fb";
String serviceUuidMaskString = "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF";
ParcelUuid parcelUuid = ParcelUuid.fromString(serviceUuidString);
ParcelUuid parcelUuidMask = ParcelUuid.fromString(serviceUuidMaskString);
builder.setServiceUuid(parcelUuid, parcelUuidMask);
ScanFilter filter = builder.build();
If needed, you can add multiple filters to a single scan, and any that match will return results. The only real limitation here is that you must know all of the manufacturer codes or all of the GATT Service UUIDs that you might match up front, at least when scanning with the screen off.
You start your scan with code like this:
bluetoothAdapter.getBluetoothLeScanner().startScan(filters, settings, scanCallback);
EDIT: It is also possible to do this with an empty ScanFilter that looks like this:
ScanFilter.Builder builder = new ScanFilter.Builder();
ScanFilter filter = builder.build();
If you use such a scan filter, it will match any advertising packet, and still allow detections with the screen off on Android 8.1, effectively giving you the same behavior on Android 8.0.x and earlier.
EDIT 2: On the Galaxy Note 9 with Android 8.1 and perhaps other Samsung devices with 8.1, scans are blocked with the screen off even with an empty scan filter. Scans are allowed with the screen off with a non-empty scan filter as described above.
I faced the same issue. I had Scan filters in order to scan BLE devices even if the screen were locked. But on Samsung devices it didn't work, so I search on Samsung forum and I discovered Knox SDK (https://seap.samsung.com/sdk/knox-android).
And it was the solution of my problem. All you have to do is add it to your app, create a license and activate it and finally use this method addPackageToBatteryOptimizationWhiteList to unlock the scan when the Samsung device screen is lock.
Obviously not, unless they missed something. But it will still work in the background if you have scan filters, which you should have anyway. So is it really an issue?
in android 11
scanFilter can't being null
you need to set something then will working
like:
List<ScanFilter> filterList = new ArrayList<>();
filterList.add(new ScanFilter.Builder().setDeviceAddress(address).build());
BluetoothAdapter.getBluetoothLeScanner().startScan(filterList, scanSettings, scanCallback);
I have a small app which just performs a BLE Advertising.
The app runs on a Nexus 5x with Android 8.0
This is the code to start BLE advertising:
private fun startAdvertising() {
val serviceUuid = ParcelUuid.fromString("DAB5D1DC-0000-1000-8000-00805F9B34FB")
val data = AdvertiseData.Builder()
.setIncludeTxPowerLevel(false)
.setIncludeDeviceName(false)
.addServiceUuid(serviceUuid)
.build()
val settings = AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
.setConnectable(true)
.build()
bluetoothLeAdvertiser!!.startAdvertising(settings, data, advertiserCallback)
}
The advertising starts, but the payload is wrong. On Pre-Android 8.0 devices we receive the correct service-uuid when scan for this messages with a 2nd device:
32-bit Service-UUID: 0xDAB5D1DC
But when I start the advertisements on my Nexus 5x with Android 8.0, I receive an incorrect service-uuid:
32-bit Service-UUID: 0x0000D1DC
For the BLE scanning part I use the nrf Connect app from playstore.
Everything works as expected, if I advertise a common 128-bit Service UUID and not an 32-bit one.
Are there any changes for Android 8.0 regarding my issue?
Update 2017-08-28:
Same issue on a Nexus 6P. Created an issue: https://issuetracker.google.com/issues/65099899
Use only ParcelUuid.fromString("DAB5D1DC")
this will make youre packet smaller.
youre problem is probably because youre advertise packet too big i think the max is 32 bytes.
Create Constants
public static final UUID serviceUuid = UUID.fromString("DAB5D1DC-0000-1000-8000-00805F9B34FB");
and than
val data = AdvertiseData.Builder()
.setIncludeTxPowerLevel(false)
.setIncludeDeviceName(true)
.addServiceUuid(new ParcelUuid(Constants.serviceUuid))
.build()
I'm implementing a simple advertise + scan functionality using BLE on android, and for some reason I get a lot of calls to the onScanResult callback passing the same device.
For advertising:
//Advertise settings build
AdvertiseSettings.Builder builder = new AdvertiseSettings.Builder();
builder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY);
builder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);
builder.setConnectable(true);
AdvertiseSettings advSettings = builder.build();
//Advertise data build
AdvertiseData.Builder advDataBuilder = new AdvertiseData.Builder();
advDataBuilder.addServiceUuid(ParcelUuid.fromString(SFGattAttributes.SERVICE));
AdvertiseData advertiseData = advDataBuilder.build();
//Start Advertising
bluetoothLeAdvertiser.startAdvertising(advSettings, advertiseData, advertiseData, new BLEAdvertiserCallback());
For scanning:
BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
bluetoothLeScanner.startScan(getScanFilters(), getScanSettings(), new BLEScanCallback());
The only difference each time seems to be a difference in the rssi value.
Is there a way to avoid this multiple calls?
This is actually a feature and can be for used ranging a (advertising) BLE device. There are also (older) devices that don't get multiple scan results for a specific device during a scan cycle. This then causes problems for ranging other devices including BLE beacons. The multiple calls also let you know (over time) that the device is still reachable/accessible.
So if you don't want the multiple calls just ignore the calls for known devices (MAC addresses). It can not be deactivated.
Keep in mind that many devices (especially phones) change their mac address. Some even every 2 minutes. It's not easy to map the new mac address to the old device (old mac address). You have to handle the behaviour accordingly.