All posts
Android, Blog

Bluetooth Classic vs. Bluetooth Low Energy on Android – Hints & Implementation Steps

Dawid Kliszowski

Dawid Kliszowski

Do you want to create a connection between wearable devices and smartphones? Find out about the possibilities of Bluetooth Classic & Bluetooth Low Energy (BLE) and read about the basic steps that are useful when developing a Bluetooth app on Android.


In most cases, designers of wearable, peripheral devices, as well as all other items that extend our smartphone’s functionality, are facing a common issue. Most of these devices need to communicate with our smartphone somehow. The problem is which technology to choose. Bluetooth Classic and BLE seem to be good enough. Find out which one would fit your situation the best.

Bluetooth is not an answer

Today’s customers are expecting hands-free, wireless solutions. The first thing that comes to mind is Bluetooth. Yet is this already an answer to the question? Not exactly. There are many different solutions hidden under this name. Since Bluetooth 4.0 was introduced, there is Bluetooth High Speed, Bluetooth Classic (BC) and Bluetooth Low Energy (BLE). The first one is a solution which combines Bluetooth and WiFi (as the transport layer) in order to reach a high transfer speed, but it requires a combo chip (BT + WiFi), which is relatively expensive. The other two solutions are widely used and they meet most expectations.

Bluetooth Classic & Bluetooth Low Energy on Android

Which of these is better? It depends on our requirements. We need to compare the parameters and features of both standards. Yet we also need to keep in mind that, usually, we need to create an application that allows us to handle the communication between our smartphone and the device. So, it’s also important to know what is offered by the operating system (Android – in this case) in terms of using each solution.

Bluetooth Classic – highly effective for short distances

Basically, Bluetooth Classic is designed for continuous two-way data transfer with high Application throughput (up to 2.1 Mbps); highly effective, but only for short distances. So, it’s a perfect solution in the case of streaming audio and video, or mice and other devices that need a continuous, broadband link.

Bluetooth Low Energy – as much as 100x lower power consumption

On the other hand, Bluetooth Low Energy provides only 0.3 Mbps of Application throughput. The data is sent in small (20 bytes) packages, but the range can be even more than 100 meters (330 feet) and the minimum latency between unconnected state to data transfer can be counted in a handful of milliseconds, while in BT Classic it’s about 100 ms.

Yet the main advantage of using BLE is its very low power consumption. Although the peak current of BLE (up to 15 mA) is half of the BT Classic current (up to 30 mA). But the power consumption can be even 100x lower for BLE!

So, for the 1W reference value for BT Classic, BLE offers 0.01W – 0.5 W power consumption. This means that simple BLE devices, like beacons, may function for 1–2 years with a 1,000 mAh coin cell battery.

How to use them on Android – basic steps

Thankfully, we can use both BT Classic and BLE technologies on the Android system. But if there is no need to use BT classic, it’s better to use BLE, because of its low power consumption. The implementation of BLE is provided by Android version 4.3 (API 18) and above. So, if we have already decided which solution will be suitable for our needs, lets start the implementation process. Here are the basic steps.

1. Requesting permissions and features

This is the first step before using Bluetooth Classic or BLE features. We need to make sure all required permissions and features are applied and enabled. What do we need?


    • android.permission.BLUETOOTH – basic BC and BLE features
    • android.permission.BLUETOOTH_ADMIN – advanced BC and BLE operations like enabling/disabling bluetooth module, device discovery, creating sockets
    • android.permission.ACCESS_COARSE_LOCATION – required for BLE scanning on Android 5.0 (API 21) or higher. Note: This is a dangerous permission from API 23.

So, to use all the features, our manifest file should look like this:


We need also to make sure that the smartphone or tablet actually has a built-in Bluetooth adapter. If we just want to make our app unavailable for devices without Bluetooth, we can just add a proper manifest tag:
<uses-feature android:name="android.hardware.bluetooth"/>
But, according to the documentation on, it’s not actually required if we declare the Bluetooth permission and set the target SDK version to 5 or above.

We also need to keep in mind that using Bluetooth requires the Bluetooth adapter to be enabled. We can check its current state by BluetoothAdapter.getDefaultAdapter().isEnabled(). If its disabled, we can enable it in many different ways:

  • inform the user to enable it manually (in a drop-down menu from the status bar)
  • use an intent to show system-provided dialog for the user:
  • enable it programmatically by BluetoothAdapter.getDefaultAdapter().enable()

This method requires the android.permission.BLUETOOTH_ADMIN permission and it’s an asynchronous call: it will return immediately. So, in this case, we still need to wait until the Bluetooth adapter enables, so we can use a broadcast receiver to catch the BluetoothAdapter.ACTION_STATE_CHANGED intent:

If we want to use BLE scanning, location services also need to be enabled, which can be done by the user in a drop-down menu from the status bar (we need to register a broadcast receiver for LocationManager.MODE_CHANGED_ACTION or LocationManager.PROVIDERS_CHANGED_ACTION). Location services can be also enabled using a system-provided dialog, using GooglePlayServices:

Note: Add a dependency to your app/build.gradle file

2. Getting BluetoothDevice object

In order to do some BC or BLE actions on a particular Bluetooth device, we need to obtain a BluetoothDevice object. If we already know the MAC address of our Bluetooth device and we want to hardcode it in our app, we can just use:

Otherwise, we need to start a discovery process. This starts scanning in order to find nearby devices and uses an SDP protocol to obtain advertisement data from the devices. It’s used to acknowledge the smartphone and what kind of services are provided by a Bluetooth device, such as an audio headset, keyboard etc.

Basic discovery (BC and BLE):

In this case, we need to start the discovery and register a BroadcastReceiver, which will catch BluetoothDevice.ACTION_FOUND and BluetoothDevice.ACTION_DISCOVERY_FINISHED intents. The discovery process usually involves an inquiry scan of about 12 seconds.

Dedicated BLE discovery:

If we want to find only BLE devices, it’s enough to implement BLE scanning:

3. Connecting to Bluetooth device

If we need a high-speed connection (up to 2.1 Mbps) to stream big amounts of data between the smartphone and Bluetooth device, we can use one of the BT Classic features – the RFCOMM socket. If the large bandwidth is not needed in our case and we only need to exchange small packets of data, we should just use a GATT profile.


RFCOMM is a Bluetooth protocol emulating RS-232 serial ports. It can be used to create an InputStream and OutputStream to a Bluetooth device. First, we need to obtain a Bluetooth socket. It can be secure, as the data will be encrypted then:

RFCOMM – creating the socket:

Note: The device.createInsecureRfcommSocketToServiceRecord() was officially introduced in Android 2.3.3 (Gingerbread – API 10). We can call it using reflection, but it’s not guaranteed to work.

Note 2: In some older devices like HTC Desire, using the standard createRfcommSocketToServiceRecord() method always causes the connect() to fail. We can also use reflection as a workaround:

RFCOMM – pairing:

In the case of using RFCOMM sockets, the device we want to transfer data with needs to firstly be paired with our smartphone. To check if a device is already paired, we can use:

Devices can be paired manually by the user in Android Bluetooth Settings. We can also request pairing programmatically. The pairing request can be done by:

but the user still needs to accept the pairing by tapping on a system-provided dialog.

Tip: If we want to make a hands-free solution, we can try a workaround, but it’s not recommended and not guaranteed to work. It relies on catching system intent (action BluetoothDevice.ACTION_PAIRING_REQUES), applying pairing by device.setPairingConfirmation(true) and aborting the broadcast. If we set a high priority for the IntentFilter, the intent would never reach the system classes, which are handling the pairing dialog, so it will never be shown. This can throw SecurityException on android 7.1+.

RFCOMM – data transfer

After creating a socket, we can connect to it and start reading and writing data using the input and output stream. Please keep in mind that it needs to be handled in background threads and it’s recommended to cancel the discovery process before connecting to a socket.


The Generic Attributes (GATT) define a hierarchical data structure that is exposed to connected BLE devices. GATT allows us to read or write values on available characteristics. We can also get asynchronous notifications and indications when a characteristic value has changed.

GATT Characteristics

A GATT Characteristic is a data value transferred between client and server – for example, the current battery level. Each of them is identified by a UUID (unique identifier). There are some standard characteristics like:

GATT allows us to read or write values on available characteristics. We can also get asynchronous notifications and indications when a characteristic value has changed. We can use a maximum of 20 Byte data packets that we want to write on a characteristic. If we want to send bigger amounts of data, we need to split them. Each characteristic can offer a few basic operations:

    • read – read the current value of characteristic features
    • write – update the current value (it needs to be queued on our side) operations like enabling/disabling bluetooth module, device discovery, creating sockets
    • notification / indication – asynchronous call – notifies about the changed value of characterisctic

GATT handling is provided by native Android classes, but I really recommend using dedicated libraries, like this one:

It wraps GATT functionality into RxJava and makes it much easier to use.

Wrap up

So, Bluetooth technology allows us to configure communication between devices in many different ways. It offers some sub-solutions that we can use, but we first need to analyze what our goals and priorities are to choose the proper one. I hope my advice, together with these basic steps, will help you to create a great and useful Android app.


The post is created by Droids On Roids Team Member.
We would love to take care of your business.

Leave comment