1. Are you ready for the Galaxy S20? Here is everything we know so far!

Bluetooth UUID API on Android Studio acts randomly

Discussion in 'Android Development' started by Alvaro Vargas, Aug 29, 2020.

  1. Alvaro Vargas

    Alvaro Vargas Lurker
    Thread Starter

    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:

    Code (Java):
    1.             isFetchUUIDSButtonPressed = true;
    2.            bluetoothDiscoveredUUID.clear();
    3.            String UUID = "00:00:00:00:00:00"; // MAC ADDRESS IS OBVIOUSLY SOMETHING DIFFERENT, BUT I AM NOT SHOWING IT HERE.
    4.            BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
    5.            BluetoothDevice mBluetoothDevice = bluetoothManager.getAdapter().getRemoteDevice(UUID);
    6.  
    7.            Log.w(TAG, "BEFORE Check if fetch succeeded: " + checkIfUUIDFetchSucceeded);
    8.            checkIfUUIDFetchSucceeded = mBluetoothDevice.fetchUuidsWithSdp();
    9.            Log.w(TAG, "AFTER Check if fetch succeeded: " + checkIfUUIDFetchSucceeded);
    10.            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:


    Code (Java):
    1. ////////////////////////////// BLUETOOTH IN GENERAL BROADCAST RECEIVER //////////////////////////////
    2. BroadcastReceiver bluetoothBroadcastReceiver = new BroadcastReceiver(){
    3.  
    4.    @Override
    5.    public void onReceive(Context context, Intent intent){
    6.  
    7.        String action = intent.getAction();
    8.  
    9.        if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)){
    10.  
    11.            //STATE_OFF = 10;
    12.            //STATE_TURNING_ON = 11;
    13.            //STATE_ON = 12;
    14.            //STATE_TURNING_OFF = 13;
    15.  
    16.            int previousBluetoothState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, BluetoothAdapter.ERROR);
    17.            int currentBluetoothState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
    18.  
    19.            Log.w(TAG,"Previous Bluetooth Adapter State: " + previousBluetoothState);
    20.            Log.w(TAG,"Current Bluetooth Adapter State: " + currentBluetoothState);
    21.  
    22.  
    23.            if( previousBluetoothState == BluetoothAdapter.STATE_ON ){
    24.  
    25.                //TODO: CANCEL CURRENT OPERATIONS, RESET ALL VARIABLES, LISTVIEWS, BUTTONS, etc, TO THEIR INITIAL STATES.
    26.                // this is to guarantee a fresh restart of operations after the Bluetooth adapter is turned ON again.
    27.  
    28.                Log.w(TAG, "Bluetooth Turning Off: RESETTING ALL FIELDS AND VIEWS TO THEIR INITIAL STATES");
    29.                resetFields();
    30.  
    31.            }
    32.  
    33.        }
    34.  
    35.  
    36.        ////////////////////////////// CONNECTION ESTABLISHED //////////////////////////////
    37.        else if(BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)){
    38.  
    39.                Log.w(TAG, "Provisional Connection to Retrieve UUID");
    40.  
    41.        }
    42.  
    43.  
    44.        ////////////////////////////// DISCONNECTION VERIFIED //////////////////////////////
    45.        else if(BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)){
    46.  
    47.            Log.w(TAG,"ACTION_ACL_DISCONNECTED: Provisional connection finished!");
    48.            Log.w(TAG,"ACTION_ACL_DISCONNECTED: Disconnected from device");
    49.  
    50.        }
    51.  
    52.    }
    53.  
    54. };

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

    Code (Java):
    1. ////////////////////////////// UUIDs BROADCAST RECEIVER //////////////////////////////
    2. private final BroadcastReceiver UUIDBroadcastReceiver = new BroadcastReceiver() {
    3.  
    4.    @Override
    5.    public void onReceive(Context context, Intent intent) {
    6.  
    7.        String action = intent.getAction();
    8.  
    9.        if( BluetoothDevice.ACTION_UUID.equals(action) && isFetchUUIDSButtonPressed){
    10.  
    11.            Parcelable[] uuids = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID);
    12.            Log.e(TAG,"FROM ACTION_UUID");
    13.  
    14.            bluetoothDiscoveredUUID.add(new ArrayList<UUID>());
    15.  
    16.            if (uuids != null) {
    17.  
    18.                for (Parcelable ep : uuids) {
    19.                    Log.e(TAG, "UUID = " + ep.toString());
    20.                    bluetoothDiscoveredUUID.get((bluetoothDiscoveredUUID.size()) - 1).add(UUID.fromString(ep.toString()));
    21.                }
    22.  
    23.            }
    24.  
    25.  
    26.            else{
    27.                bluetoothDiscoveredUUID.get((bluetoothDiscoveredUUID.size()) - 1).add(nullUUID);
    28.                Log.e(TAG, "Null UUID");
    29.            }
    30.  
    31.                Log.w(TAG, "UUID data acquired");
    32.                isFetchUUIDSButtonPressed = false;
    33.  
    34.        }
    35.  
    36.  
    37.  
    38.    }
    39.  
    40.  
    41. };
    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:

    Code (Java):
    1. D/ViewRootImpl: ViewPostImeInputStage ACTION_DOWN
    2. W/MainActivity: BEFORE Check if fetch succeeded: false
    3. W/MainActivity: AFTER Check if fetch succeeded: true
    4. E/MainActivity: FROM ACTION_UUID
    5.    Null UUID -------------------------------------->>>> //Other device is off and no UUIDs stored in cache
    6. W/MainActivity: UUID data acquired
    7.  
    8.  
    9. D/ViewRootImpl: ViewPostImeInputStage ACTION_DOWN
    10. W/MainActivity: BEFORE Check if fetch succeeded: false
    11. W/MainActivity: AFTER Check if fetch succeeded: true
    12. W/MainActivity: Provisional Connection to Retrieve UUID!
    13. E/MainActivity: FROM ACTION_UUID
    14.    UUID = 00001101-0000-1000-8000-00805f9b34fb
    15.    UUID = 00000000-0000-1000-8000-00805f9b34fb
    16. W/MainActivity: UUID data acquired
    17. W/MainActivity: ACTION_ACL_DISCONNECTED: Provisional connection finished!
    18. ACTION_ACL_DISCONNECTED: Disconnected from device
    19.  
    20.  
    21. D/ViewRootImpl: ViewPostImeInputStage ACTION_DOWN
    22. W/MainActivity: BEFORE Check if fetch succeeded: false
    23. W/MainActivity: AFTER Check if fetch succeeded: true
    24. E/MainActivity: FROM ACTION_UUID
    25.    UUID = 00001101-0000-1000-8000-00805f9b34fb
    26.    UUID = 00000000-0000-1000-8000-00805f9b34fb
    27. W/MainActivity: UUID data acquired
    28.  
    29.  
    30. D/ViewRootImpl: ViewPostImeInputStage ACTION_DOWN
    31. W/MainActivity: BEFORE Check if fetch succeeded: false
    32. W/MainActivity: AFTER Check if fetch succeeded: true
    33. E/MainActivity: FROM ACTION_UUID
    34.    UUID = 00001101-0000-1000-8000-00805f9b34fb
    35.    UUID = 00000000-0000-1000-8000-00805f9b34fb
    36. W/MainActivity: UUID data acquired
    37. W/MainActivity: Provisional Connection to Retrieve UUID!
    38. W/MainActivity: ACTION_ACL_DISCONNECTED: Provisional connection finished!
    39. 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?
     


Loading...

Share This Page

Loading...