I have implemented Companion device pairing and it works great for most devices without requiring any location permission or location services enabled. However, we found for example Xiaomi Redmi Note 10 Pro (Android 11) where the BLE scan timeouts when Location services are disabled.
Do I still need to implement requiring Location services enabled before the scan or this is undesirable behavior? I hoped it is not needed anymore with this system-level BLE scan.
If so, is there a way how to distinguish which device needs it? I don't want to force all people when it is not needed (for example my Pixel 5)
In my opinion the Companion Device feature was implemented and designed in a rush. You could expect bugs like the "Location services" must be turned on and the Companion Device pairing dialog doesn't warn when it is not enabled. Until Xiaomi or Google fixes this bug, you will need to have workarounds in your app, for example telling the user to first enable Location services if you think that will be needed.
I am also facing issues with applying a scan filter. It is completely a nightmare.
I have started with this:
val filter = ScanFilter.Builder().apply {
setManufacturerData(SOME_INDEX, byteArrayOf(1))
setDeviceName(SOME_NAME)
setServiceUuid(ParcelUuid.fromString(SOME_UUID))
}.build()
Finally, I have only this:
ScanFilter.Builder().apply {
setManufacturerData(SOME_INDEX, byteArrayOf(1))
}.build()
Because setServiceUuid() is not working for example on all tested Huawei phones and Sony Xperia X.
And setDeviceName() is not working for example on Samsung S10e. Finally I have found solution for name filtering by applying directly:
BluetoothLeDeviceFilter.Builder()
.setNamePattern(Pattern.compile(SOME_NAME))
.setScanFilter(filter)
Related
I have a flutter app, that uses the location library, found here
I import with
import 'package:location/location.dart';
and later call with
location.onLocationChanged().listen((Map<String,double> currentLocation) {
print("LocationListener " + currentLocation.toString());
}
This works fine when run on an avd phone emulator, and also on a real phone. I get periodic updates with new gps locations coming through.
However, I want to get this working on an Android Wear 2 device/watch.
If I try it in either an emulator or actual android watch (Huawei watch 2), the stream never seems to trigger. I'm also trying to update the location via the emulator, which again works with a phone, but doesn't work with a watch.
The adv device I'm trying is Android Wear Round API 26.
The actual device is
Wear OS By Google 1.6, Google Play Services 14.3.67, android o.s 8.0
Location is enabled on the phone. It's possible the avd watch location is expecting it from a phone, but the actual watch device isn't, as it can work standalone, and things like Google Maps work fine with it GPS wise.
Does Android Wear 2 treat GPS/listeners different in anyway that I should be aware of, and any way to get that working ?
I've got this working finally as I hadn't realised permissions requirements had changed, as per here.
So I've added one of these...
<!--<uses-permission android:name="android.hardware.location.gps" />-->
<uses-permission android:name="android.hardware.location" />
location permission seems to work, but you can add gps specifically if that is required.
Yesterday I updated my Samsung Galaxy S5 Neo to the new Android Version 6.0.1. Since then the beacons won't be detected anymore. It does connect the Beacon Service, Updates the scan perios, etc. but it doesn't find any beacons.
Bluetooth is activated and the Beacon scanner of the Beacon Manifacturer still works fine (finds all the beacons). But not my app... It all worked before the new Android Update.
A few things to check:
Verify Location is enabled in Settings -> Location. This must be set to High Accuracy or Battery Saving. If set to Device Only, it won't work. Starting with Android 6, Location must be enabled to do bluetooth scans.
Make sure your app has been granted location permission. Check Settings -> Apps -> Your App -> Permissions, and verify the Location slider is set to on. Starting with Android 6, each app must dynamically request location access at runtime. If your app doesn't have code to do this, you'll need to add it. (Although it is possible to override in settings as described here.)
Make sure your app's manifest declares either FINE_LOCATION or COARSE_LOCATION in its declared permissions.
If the above don't help check LogCat (not just filtering on your application) for bluetooth errors.
See here for more info on the above.
My app is working fine, until Android 5.0.2 doesn't allow third party app to connect to HID device over Bluetooth low energy.
myGatt.setCharacteristicNotification(gattChar, true);
06-01 17:39:35.356: W/BluetoothGatt(21599):
java.lang.SecurityException: Need BLUETOOTH_PRIVILEGED permission:Neither
user 10157 nor current process has android.permission.BLUETOOTH_PRIVILEGED.
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
BLUETOOTH_PRIVILEGED permission doesn't work on a third party app. It's only for system or manufacturer apps.
The latest changes from Android note:
Enforce BLUETOOTH_PRIVILEGED permission for HID-over-GATT
https://android.googlesource.com/platform/packages/apps/Bluetooth/+/02bebee
Code snippet:
private static final UUID[] HID_UUIDS = {
UUID.fromString("00002A4A-0000-1000-8000-00805F9B34FB"),
UUID.fromString("00002A4B-0000-1000-8000-00805F9B34FB"),
UUID.fromString("00002A4C-0000-1000-8000-00805F9B34FB"),
UUID.fromString("00002A4D-0000-1000-8000-00805F9B34FB") };
if (isHidUuid(charUuid)) enforcePrivilegedPermission();
My question: is there a way to overwrite HID_UUIDS or enforcePrivilegedPermission? Can I use reflection to by pass it?
Every times Android released a new version, it breaks the previous code.
Thanks!
The question is old, but still worth answering.
The HID (and FIDO https://fidoalliance.org/) service is protected and indeed requires system permission source. Only apps signed with the system key may use this service, that is only Bluetooth settings. This is to ensure that 3rd party apps are not able to listen to keys typed on a wireless keyboards, as all notifications and indications are transferred to all BluetoothGatt objects. Without this protection you would be able to connect to a HID device (you still can), enable notifications using gatt.setCharacteristicNotification(.., true) and receive updates whenever a key is typed. With a bit of knowledge about Report characteristics you can then get all the keys and mouse positions, including passwords, etc. So it's not a break, but a bug fix. On KitKat you still may do this.
The only solution is to compile your own AOSP Android version and sign your app with the same key. Otherwise it would be useless protection.
Btw, starting form Android 8 or perhaps earlier you don't get SecurityException. The call just returns true as if any other and you never get any callback.
This might have been changed here: https://android.googlesource.com/platform/packages/apps/Bluetooth/+/32dc7a6b919375aede777f3c821fa316d85449ae%5E%21/#F2
Alright here's the deal. I got two Galaxy Nexus phones both with bluetooth enabled.
I've written a bluetooth connection management app that I use for device discovery and connectivity. It also outputs all the available UUIDs the devices can support.
Looking from http://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm the following standard UUIDs are exposed from Galaxy Nexus devices.
0x1116 - NAP
0x112f - PBAP (Phonebook Access Profile)
0x111f - HFP (Hands free)
0x1105 - OPP (Object Push Profile)
0x1112 - HSP (Headset Profile)
0x110c - AVRCP
0x110a - A2DP
I am trying to connect via the OPP profile (UUID 00001105-0000-1000-8000-00805F9B34FB) and push objects (files) between the devices. I've gone though the entire Android API documentation on how to discover, pair/bond (threading etc.) and manage all bluetooth connections. I've managed to successfully connect and talk to a legacy board device via the SPP (0x1101) profile.
However, when I try to use socket.connect() between the two galaxy nexus phones, the pairing dialog shows up and I click Pair button on both devices. After that, I immediately get a Connection Refused IOException. Note that after pairing has occurred once I never get asked again which makes sense since the secure link is cached.
If I can't connect to these standard profiles using these standard UUIDs why are they exposed? How can I connect from my app to any of these profiles and interact with them? Is it because my app is not somehow trusted? What's weird is that even the Share functionality on Android does not work at all either. Is this something completely broken on Android?
Please avoid giving me hints to use the "well known UUID SPP one 0x1101" like the docs say. This is not what I want. I have a fairly good understanding of how this stuff works and I am looking for a real solution or explanation of the problem.
I've seen the typical "reflection" solution but I do not understand why is this still a problem on Android? Why do people use reflection to make this work? Can we file a bug on Android to fix this?
If those UUIDs are standard any app should be able to connect and interact with them. Why is this an issue and why do I get this exception?
Thanks in advance.
UPDATE
So for some reason the object push in the Android system started working. I actually attempted to connect via my app and it was not working. Then, I went to the Contacts app and tried to share a contact which magically worked. Then, I went back to my app and it now it works...wow. That is very weird and there must be an explanation to this.
I ran into this same issue and managed to find a solution that worked for me.
In my case I using three different test devices (Nexus 5, Galaxy S4, Note 2) and for some reason, the Note 2 wouldn't connect to my Bluetooth module yet the other two would.
The reasoning I've found is that Bluetooth drivers vary, and slightly different connection methods are needed to create a connection between different devices.
The three methods I use are called 'Secure', 'Insecure' and 'Reflection method'/'hax'.
switch(connType)
{
case Secure:
tmpSocket = device.createRfcommSocketToServiceRecord(_uuid);
break;
case Insecure:
tmpSocket = device.createInsecureRfcommSocketToServiceRecord(_uuid);
break;
case Hax:
Method createSocket = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
tmpSocket = (BluetoothSocket)createSocket.invoke(device, Integer.valueOf(1));
break;
}
In my case, the Secure mode worked for both the Nexus 5 and Galaxy S4 however it didn't work for the Note 2.
After some testing I discovered the Note 2 only works using 'Insecure' mode, so to cater to this, I basically attempt a connection and cycle through the different modes if necessary. When attempting a different connection mode I simply prompt 'retrying connection'. So, if the connection fails using secure, then I will attempt using Insecure and then using the reflection method.
I haven't run into the case where one of these three methods haven't worked.
Have you tried using a nonstandard profile? i.e. a custom UUID just for your app. This will also help you know your are (most likely) only connecting to your own app rather than some other app that is registered with the same profile.
From my experience, Bluetooth pairing is very buggy for the first pair attempt. However, using a custom UUID helps this somewhat.
The reflection method (I think) was originally an attempt to fix a bug with a specific device, however I think some people found success in using it elsewhere as well. The device was called the Spica or something similar.
As one of the comments also posted, I would also try connecting again after failing.
Basically write code that plans to fail the first attempt, but then the code tries to connect again in 5 seconds if there was a failure.
These are imperfect solutions but Bluetooth implementation on Android is also imperfect (IMHO). Hope that helps
EDIT
Based on the question update and comments:
I agree something is definitely buggy. Part of the problem I think is the BT drivers vary and each has a different BT stack with different quirks. I also found a question that makes use of both the reflection method AND custom UUID, AND other standard methods. This seems extreme to me but it does cover the most ground. Unfortunately as app developers we have no control over the low level stack/code/drivers.
I have found with my two Bluetooth sharing apps that the first pairing is always tricky.
I'm glad to know it's not just me.
Has anyone gotten Multicast to work on Android 2.2, specifically JmDNS for Bonjour service detection. There are many questions & answers from the Android 1.5->2.0 timeframe, including on stackOverflow, that indicate varying levels of success, and a bug in the bug tracker that indicate it was fixed, and closed, for 2.2 (http://code.google.com/p/android/issues/detail?id=2323) . I've tried the "TuneControl" source code, but that worked on ~1.5 and has not been updated, and does not work for me on 2.2.
So, the questions...
1) Has anyone seen multicast work on 2.2, specifically JmDNS, and specifically for Bonjour service detection?
2) What is necessary in code to make this work?
I'm using the appropriate permissions:
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
I acquire the multicast lock:
WifiManager wifi = (WifiManager)getSystemService( Context.WIFI_SERVICE );
if(wifi != null)
{
MulticastLock mcLock = wifi.createMulticastLock("mylock");
mcLock.acquire();
...
And then try to start jmDNS to look for servers:
mdns = JmDNS.create(addr, HOSTNAME);
jmdns.addServiceListener(TOUCH_ABLE_TYPE, listener);
jmdns.addServiceListener(DACP_TYPE, listener);
...
The listener never sees any services. I've verified using Wireshark that the request packets are sent, and that the server responds, but the response packet are never seen by the socket listener code in the jmDNS library.
So... am I missing something? Is this still a bug? Has ANYONE gotten anything even remotely like this to work???
To (rudely) answer my own question, more information was provided at http://code.google.com/p/android/issues/detail?id=2917#c48 by another person. For posterity, as they say, here is brian.ro...#gmail.com's answer...
"I've spent quite a bit of time
debugging mDNS issues with JmDNS on my
Evo and HTC Hero (CDMA). What I found
is there appears to be a filter in
place in the broadcom wireless driver
on the Evo (and since I'm getting a
similiar reprt from an HTC Desire user
- with the same chipset, presumably that handset as well). The filter, by
default, blocks any non-unicast or
network broadcast traffic, including
multicast. Apparently the theory was
it's a battery saver.
The problem appears to be the
wpa_supplicant on the Evo does not
support removing those filters when
you get a MulticastLock. (Check the
log output right after you get the
lock and you'll see what I mean).
Unfortunately what has happened is the
hardware vendors have fragmented
multicast support.... :("
So... it appears this is a device problem more than a coding problem. D'oh. :( If I get an opportunity to test on another device...
I've been doing a bit of research into this, and I believe it is a problem with Android in general, and fixed in or around Android 2.3.7.
It's a bit too anecdotal, but here's what I tested:
HTC Desire, 2.2, stock: fail
HTC Desire, 2.3.7, CyanogenMod: success
Motorola Milestone, 2.1-update1: fail
HTC Desire S, 2.3.3: fail
Acer Iconia A501, 3.2.1: success
Samsung something, 2.3.3: fail
HTC Legend, 2.2 I think: fail
When I say 'fail', in fact they were all able to send multicast messages to the 'success' devices, but never receive anything back except their own messages - as jldupont describes.
Note that the multicast IM app Kouchat is only available for 2.3.7 onwards, even though it can be made to compile for as far back as 2.1, which gives further credence to this theory.
I think the other reason is your AP does not support.
Other:Computer send/recieve to/from Android
your computer must only use WIFI,Best off all other network