android BluetoothDevice.getName() return null

23,589

Solution 1

Finally, i found out the solution:

1.For device connected:

Read device name from gatt characteristic org.bluetooth.characteristic.gap.device_name of service org.bluetooth.service.generic_access.

2.For device no connected:

    /**
     * Get device name from ble advertised data
     */
    private LeScanCallback mScanCb = new LeScanCallback() {
        @Override
        public void onLeScan(final BluetoothDevice device, final int rssi,
            byte[] scanRecord) {
            final BleAdvertisedData badata = BleUtil.parseAdertisedData(scanRecord);
            String deviceName = device.getName();
            if( deviceName == null ){
                deviceName = badata.getName();
            }
    }


////////////////////// Helper Classes: BleUtil and BleAdvertisedData ///////////////
    final public class BleUtil {        
        private final static String TAG=BleUtil.class.getSimpleName();
        public static BleAdvertisedData parseAdertisedData(byte[] advertisedData) {      
            List<UUID> uuids = new ArrayList<UUID>();
            String name = null;
            if( advertisedData == null ){
                return new BleAdvertisedData(uuids, name);
            }

            ByteBuffer buffer = ByteBuffer.wrap(advertisedData).order(ByteOrder.LITTLE_ENDIAN);
            while (buffer.remaining() > 2) {
                byte length = buffer.get();
                if (length == 0) break;

                byte type = buffer.get();
                switch (type) {
                    case 0x02: // Partial list of 16-bit UUIDs
                    case 0x03: // Complete list of 16-bit UUIDs
                        while (length >= 2) {
                            uuids.add(UUID.fromString(String.format(
                                    "%08x-0000-1000-8000-00805f9b34fb", buffer.getShort())));
                            length -= 2;
                        }
                        break;
                    case 0x06: // Partial list of 128-bit UUIDs
                    case 0x07: // Complete list of 128-bit UUIDs
                        while (length >= 16) {
                            long lsb = buffer.getLong();
                            long msb = buffer.getLong();
                            uuids.add(new UUID(msb, lsb));
                            length -= 16;
                         }
                        break;
                    case 0x09:
                        byte[] nameBytes = new byte[length-1];
                        buffer.get(nameBytes);
                        try {
                            name = new String(nameBytes, "utf-8");
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                        break;
                    default:
                        buffer.position(buffer.position() + length - 1);
                        break;
                    }
                }
            return new BleAdvertisedData(uuids, name);
        }
    }


    public class BleAdvertisedData {
        private List<UUID> mUuids;
        private String mName;
        public BleAdvertisedData(List<UUID> uuids, String name){
            mUuids = uuids;
            mName = name;
        }

        public List<UUID> getUuids(){
            return mUuids;
        }

        public String getName(){
            return mName;
        }
    }

Solution 2

BluetoothDevice.getName() may return null if the name could not be determined. This could be due to any number of factors. Regardless, the name is the friendly name of the device, and shouldn't be used to distinguish it from other devices. Instead, use the hardware address through getAddress().

Solution 3

I know this is old but this more spec-oriented answer may help answer some cases.

In Bluetooth Low Energy, advertisement and scan-response data is only required to have the Bluetooth Address. Advertisement data is how a client BTLE endpoint discovers a service device. A client can request a scan response and get more data. The device name is optional in this data. However, the BTLE spec requires that all Bluetooth Low Energy endpoints support the Generic Access service which is required to support the Device Name characteristic. Unfortunately, to read that characteristic the Android must first connect and do service discovery. If the advertisement/scan response does not provide the information, I do not believe Android connects to the device to get the name. At least I have never seen any indication of connecting without the app specifically requesting a connection. This is not what you want to be required to do if you want to make a decision to connect.

Fortunately, most BTLE devices I have worked with do provide their name in the advertisement or scan response.

Another possibility is that the device may place the name in the scan response part of the advertisement. Depending upon how one has set up Android's BTLE scanner, one might get only the advertisement data and not the scan response. In this case the name will not be found if the device puts it in the scan response. The default scanner settings, however, are such that a scan response must be received before the scan data is passed up to the app.

Solution 4

On Marshmallow, utilize ScanRecord.getDeviceName() to retrieve the local name embedded in the scan record.

BluetoothDevice.getName() is unreliable if the local name is included in a scan response, rather than in the immediate advertising packet.

    @Override
    public void onScanResult(int callbackType, ScanResult scanResult) {
        super.onScanResult(callbackType, scanResult);

        // Retrieve device name via ScanRecord.
        String deviceName = scanResult.getScanRecord().getDeviceName();
    }

Solution 5

I was trying to display name of my RN4020 Bluetooth module and faced the same issue. Found the problem in Microchip's forum:

If you enabled private service or MLDP, the maximum bytes of device name is 6 bytes, due to the 31 byte advertisement payload limitation.

I had set the device name to 9 characters. Setting the name to 4 bytes fixed the issue.

If you recognize the UUID's of your custom services so you know its your device you can also connect to the device and read its name (if its longer than 6 bytes in my case). This was also suggested in Microchips forum.

http://www.microchip.com/forums/m846328.aspx

Share:
23,589
maonanyue
Author by

maonanyue

software developer

Updated on July 10, 2022

Comments

  • maonanyue
    maonanyue almost 2 years

    On sometime, BluetoothDevice.getName() return null. How can i fix it? remoteDeviceName maybe null in following code. And i need distinguish my device and other devices by remoteDeviceName.

    BluetoothAdapter.getDefaultAdapter().startLeScan(new LeScanCallback() {
                @Override
                public void onLeScan(final BluetoothDevice device, final int rssi,
                        byte[] scanRecord) {
                        String remoteDeviceName = device.getName();
                      Log.d("Scanning", "scan device " + remoteDeviceName);
                });
    
  • maonanyue
    maonanyue over 9 years
    Users can not see bluetooth address in our ble device (watch and so on), and just know bluetooth name of the device. So, when getName() return null, it a problem to select exact device to connect.
  • User6006
    User6006 about 8 years
    How you get device name from gatt characteristic? can you give me any example
  • Nagendra Badiganti
    Nagendra Badiganti almost 7 years
    getDeviceName method doesn't exists for ScanRecord class. Can you post a sample code?
  • MSD
    MSD almost 5 years
    Links provided aren't working can you please check? @maonanyue
  • El Sushiboi
    El Sushiboi over 4 years
    What exactly do you mean by "Read device name from gatt characteristic org.bluetooth.characteristic.gap.device_name of service org.bluetooth.service.generic_access."
  • Bauer Marius
    Bauer Marius about 4 years
    This can still return null sometimes.
  • Brian Reinhold
    Brian Reinhold over 2 years
    It will return null if the device does not expose its name in the advertisement or scan response. There is no requirement in the BTLE specs for a device to expose the name in the advertisement.
  • Brian Reinhold
    Brian Reinhold over 2 years
    Once connected you should do service discovery and then the device name characteristic will be present in BluetoothGatt in the Generic Access service. This service is required as is the DeviceName characteristic entry. I can't post code in a comment though.