• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

App Inventor Bluetooth UUID API on Android Studio acts randomly

So, another issue came up when doing more tests on an app project I have been working on for a while now. I stumbled upon this issue while making an app that gathers data from surrounding Bluetooth devices to later on connect to the correct one (a custom embedded system using Bluetooth Classic, not Low Energy).

I tried the same app on two different phones (with different android versions), one has Android 5.1.1 and the other has Android 9; taking into consideration their respective permissions and restrictions.

This time, I was specifically trying to collect the UUIDs from my surrounding devices. To be clear, getting the devices' names and their respective MAC addresses was no sweat, and everything shows up perfectly on different phones. But UUIDs are these little beasts annoying me a lot, and it seems like Android Studio's API for fetching UUIDs is flawed and acts randomly and here is why:

To simplify things, I made another very simple app that gathers the UUIDs from a known device, meaning that I hard coded the MAC address I want to fetch UUIDs from.

I created a Button to start fetching by calling this piece of code:

Java:
            isFetchUUIDSButtonPressed = true;
           bluetoothDiscoveredUUID.clear();
           String UUID = "00:00:00:00:00:00"; // MAC ADDRESS IS OBVIOUSLY SOMETHING DIFFERENT, BUT I AM NOT SHOWING IT HERE.
           BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
           BluetoothDevice mBluetoothDevice = bluetoothManager.getAdapter().getRemoteDevice(UUID);

           Log.w(TAG, "BEFORE Check if fetch succeeded: " + checkIfUUIDFetchSucceeded);
           checkIfUUIDFetchSucceeded = mBluetoothDevice.fetchUuidsWithSdp();
           Log.w(TAG, "AFTER Check if fetch succeeded: " + checkIfUUIDFetchSucceeded);
           checkIfUUIDFetchSucceeded = false;


Now, there is a broadcast receiver that shows me when an ACL connection is made, since a low level connection is done in order to get the UUIDs from the wanted device:


Java:
////////////////////////////// BLUETOOTH IN GENERAL BROADCAST RECEIVER //////////////////////////////
BroadcastReceiver bluetoothBroadcastReceiver = new BroadcastReceiver(){

   @Override
   public void onReceive(Context context, Intent intent){

       String action = intent.getAction();

       if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)){

           //STATE_OFF = 10;
           //STATE_TURNING_ON = 11;
           //STATE_ON = 12;
           //STATE_TURNING_OFF = 13;

           int previousBluetoothState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, BluetoothAdapter.ERROR);
           int currentBluetoothState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);

           Log.w(TAG,"Previous Bluetooth Adapter State: " + previousBluetoothState);
           Log.w(TAG,"Current Bluetooth Adapter State: " + currentBluetoothState);


           if( previousBluetoothState == BluetoothAdapter.STATE_ON ){

               //TODO: CANCEL CURRENT OPERATIONS, RESET ALL VARIABLES, LISTVIEWS, BUTTONS, etc, TO THEIR INITIAL STATES.
               // this is to guarantee a fresh restart of operations after the Bluetooth adapter is turned ON again.

               Log.w(TAG, "Bluetooth Turning Off: RESETTING ALL FIELDS AND VIEWS TO THEIR INITIAL STATES");
               resetFields();

           }

       }


       ////////////////////////////// CONNECTION ESTABLISHED //////////////////////////////
       else if(BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)){

               Log.w(TAG, "Provisional Connection to Retrieve UUID");

       }


       ////////////////////////////// DISCONNECTION VERIFIED //////////////////////////////
       else if(BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)){

           Log.w(TAG,"ACTION_ACL_DISCONNECTED: Provisional connection finished!");
           Log.w(TAG,"ACTION_ACL_DISCONNECTED: Disconnected from device");

       }

   }

};


After the low level connection is made, the UUIDs are fetched and caught on another broadcast receiver:

Java:
////////////////////////////// UUIDs BROADCAST RECEIVER //////////////////////////////
private final BroadcastReceiver UUIDBroadcastReceiver = new BroadcastReceiver() {

   @Override
   public void onReceive(Context context, Intent intent) {

       String action = intent.getAction();

       if( BluetoothDevice.ACTION_UUID.equals(action) && isFetchUUIDSButtonPressed){

           Parcelable[] uuids = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID);
           Log.e(TAG,"FROM ACTION_UUID");

           bluetoothDiscoveredUUID.add(new ArrayList<UUID>());

           if (uuids != null) {

               for (Parcelable ep : uuids) {
                   Log.e(TAG, "UUID = " + ep.toString());
                   bluetoothDiscoveredUUID.get((bluetoothDiscoveredUUID.size()) - 1).add(UUID.fromString(ep.toString()));
               }

           }


           else{
               bluetoothDiscoveredUUID.get((bluetoothDiscoveredUUID.size()) - 1).add(nullUUID);
               Log.e(TAG, "Null UUID");
           }

               Log.w(TAG, "UUID data acquired");
               isFetchUUIDSButtonPressed = false;

       }



   }


};

Now, the supposed order in which things are supposed to happen is:

  1. A fetching command is sent
  2. An ACL connection is made to retrieve the UUIDs from the device
  3. UUIDs are retrieved
  4. ACL connection is terminated.
And lets get this clear:

  1. UUID broadcast receiver gets the UUIDs stored in cache if the device was previously discovered during the same session. After the Bluetooth adapter is turned off, all devices discovered during that session that were stored in cache are now erased, so, when turning on the Bluetooth adapter and trying to get the UUID from another device that is now turned off, the value fetched inside the broadcast receiver is now null.
In reality:

  1. When fetching UUIDs from an already searched device, the order in which things are supposed to happen, happen randomly or don't happen at all.
  2. There is not always a provisional ACL connection to retrieve the UUIDs from the device.
  3. An ACL connection and disconnection is performed even after cached UUIDs are fetched.
Here are the logged results after fetching the UUIDs on the same device over and over again:

Java:
D/ViewRootImpl: ViewPostImeInputStage ACTION_DOWN
W/MainActivity: BEFORE Check if fetch succeeded: false
W/MainActivity: AFTER Check if fetch succeeded: true
E/MainActivity: FROM ACTION_UUID
   Null UUID -------------------------------------->>>> //Other device is off and no UUIDs stored in cache
W/MainActivity: UUID data acquired


D/ViewRootImpl: ViewPostImeInputStage ACTION_DOWN
W/MainActivity: BEFORE Check if fetch succeeded: false
W/MainActivity: AFTER Check if fetch succeeded: true
W/MainActivity: Provisional Connection to Retrieve UUID!
E/MainActivity: FROM ACTION_UUID
   UUID = 00001101-0000-1000-8000-00805f9b34fb
   UUID = 00000000-0000-1000-8000-00805f9b34fb
W/MainActivity: UUID data acquired
W/MainActivity: ACTION_ACL_DISCONNECTED: Provisional connection finished!
ACTION_ACL_DISCONNECTED: Disconnected from device


D/ViewRootImpl: ViewPostImeInputStage ACTION_DOWN
W/MainActivity: BEFORE Check if fetch succeeded: false
W/MainActivity: AFTER Check if fetch succeeded: true
E/MainActivity: FROM ACTION_UUID
   UUID = 00001101-0000-1000-8000-00805f9b34fb
   UUID = 00000000-0000-1000-8000-00805f9b34fb
W/MainActivity: UUID data acquired


D/ViewRootImpl: ViewPostImeInputStage ACTION_DOWN
W/MainActivity: BEFORE Check if fetch succeeded: false
W/MainActivity: AFTER Check if fetch succeeded: true
E/MainActivity: FROM ACTION_UUID
   UUID = 00001101-0000-1000-8000-00805f9b34fb
   UUID = 00000000-0000-1000-8000-00805f9b34fb
W/MainActivity: UUID data acquired
W/MainActivity: Provisional Connection to Retrieve UUID!
W/MainActivity: ACTION_ACL_DISCONNECTED: Provisional connection finished!
ACTION_ACL_DISCONNECTED: Disconnected from device

I can confirm this is not a device specific issue since it happens on different phones and when fetching UUIDs from other devices (Bluetooth keyboards, other phones, headsets, etc), I can also confirm that it is not just a lag on the Logs because on the more complete app I am working on, flags related to ACL connections and disconnections don't get triggered at all or don't get triggered in the order they are supposed to happen.

So... after this long post... what is going on in here?
 
Almost a year ago, but I happened upon your post so if it helps you or anyone else...

I can confirm this for apis 10, 17, 19, 24, 27. Even after ensuring Android device has performed and completed discovery, using a Raspberry Pi as the listener, confirmed the Pi's extra SDP record with sdptool, and tested with a variety of UUIDS, from a random type through to the well-known SPP UUID, and even unused reserved UUIDS, I have never received more than these two records from fetchUuidsWithSdp.

I have concluded that this behaviour is one side of the Android Bluetooth Triangle: the other two being the inability to extract channel number from a listen...WithSvcRecord, and the inability to associate a UUID with a listen...On(int channel).

I would be delighted to be told I've missed something obvious, as a solution to this problem would be fantastic.
 
Upvote 0
Oh my!

@Instinctify, I have been waiting a year for someone to even stumble upon the same, it seamed so weird that I would be the only one trying to develop Bluetooth related apps with other embedded systems. I even posted this same thing on StackOverflow and the official Google Issue Tracker for Android, and I haven't had a response since a year ago.

Well, it feels refreshing that someone found out the same and that it wasn't a typo in my code. You even expanded the issue, which makes it more troublesome.

This Bluetooth API doesn't make much sense, it seems as if it is crippling the developers from doing more when it is obvious that you can get that data. Just look at the Bluetooth section on your phone or tablet, it finds all surrounding devices without issue, and when you want to connect to one of them, you just tap, and IT HAS TO fetch the corresponding UUIDs and other information in order to connect properly. So it is there, just not for us apparently.

I may be getting paranoid, but I dealt with this for so long until insanity, and it is even more frustrating when not even the official issue tracker has said a word about it.

If you want to give a look at the official issue posted on September of last year, here is the link: https://issuetracker.google.com/issues/167889912?pli=1

It was on September, but I had been fiddling with this issue since a lot longer.

Thanks for the info as well @Instinctify, lets see what happens from now on.
 
Upvote 0
I know what you mean: often when I find no comments online about an issue I am wrestling with, I discover that the problem is something really simple wrong with my code. There had to be an exception eventually.

I concur that the Android Bluetooth API - whilst apparently well documented - is a much pricklier beast when you try to actually use it. I also agree with you that the data is there, just inaccessible.

For example, my testing confirmed that the same range of APIs are happy to *publish* an SDP record for any UUID you choose.

You may be interested to know that recent API versions return a hard-coded value (20:00:00:00:00:00 if I remember correctly) when an attempt is made to get the local adapter's address. The same API levels also started using randomised bluetooth addresses during part of the discovery phase.

I can see privacy reasons for the latter but I have been unable to imagine a exploit that uses the former... I guess I'm just not evil enough.

I'm afraid I have concluded that whilst Android are locking down more Bluetooth features with every release, the chances of getting a response on a request for increased access is low (even if only back up to the level implied by the documentation.)

Ho hum.
 
Upvote 0

BEST TECH IN 2023

We've been tracking upcoming products and ranking the best tech since 2007. Thanks for trusting our opinion: we get rewarded through affiliate links that earn us a commission and we invite you to learn more about us.

Smartphones