Introduction:
Bluetooth:
The Android platform supports Bluetooth connection, which allows us to exchange data with other Bluetooth devices. The application framework provides Bluetooth related functionality through the Android Bluetooth APIs.All of the Bluetooth APIs are available in the Android Bluetooth package.
There are two types of Bluetooth in Android Classic Bluetooth and Bluetooth devices with low power requirements. Android 4.3 (API level 18) introduces API support for Bluetooth Low EnergyBluetooth(BLE).
Here we will only focus on Classic Bluetooth. Classic Bluetooth is the right choice for more battery-intensive operations, which include streaming and communicating between Android devices.
Steps to use Bluetooth in Android
Step 1:
Bluetooth permissions –
<manifest> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> </manifest>
Note:
1- If your app targets Android 9 (API level 28) or lower, you can declare the ACCESS_COARSE_LOCATION permission instead of the ACCESS_FINE_LOCATION permission.
2- ACCESS_FINE_LOCATION or ACCESS_FINE_LOCATION comes under the dangerous permissions so we need to define the runtime permission for these.
Step 2:
Set up Bluetooth and Scan for Available devices:-
Now let’s build our layout file. So open activity_bluetooth_device_list file and add the below code.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".BluetoothDeviceListActivity"> <Button android:id="@+id/scanBtn" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="20dp" android:gravity="center" android:text="Scan for Devices"> </Button> <ListView android:id="@+id/lvNewDevices" android:layout_width="match_parent" android:layout_height="300dp" android:layout_margin="20dp" android:scrollbars="none" /> <EditText android:gravity="center" android:layout_gravity="center" android:hint="type messgae here.." android:id="@+id/editText" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="20dp"></EditText> <Button android:id="@+id/sendBtn" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="20dp" android:gravity="center" android:text="send message"/> </LinearLayout>
Step 3:
Now in the BluetoothDeviceListActivity, add these below code:
import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.Toast; import java.util.ArrayList; public class BluetoothDeviceListActivity extends AppCompatActivity implements View.OnClickListener, AdapterView.OnItemClickListener { final String[] permissions = {"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}; private ArrayList<BluetoothDevice> mBTDevices; private static final int ENABLE_REQUEST_CODE = 8989; private DeviceListAdapter mDeviceListAdapter; private BluetoothManager bluetoothManager; private BluetoothAdapter bluetoothAdapter; private Button scanBtn; private ListView lvNewDevices; private BluetoothBroadCoast bluetoothBroadCoast; private String TAG = getClass().getName(); private boolean isScanButtonClicked; private BluetoothDevice mBTDevice; private BluetoothConnectionService bluetoothServiceConnection; private EditText editText; private Button sendBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_bluetooth_device_list); inItView(); checksPermission(); } private void inItView() { scanBtn = findViewById(R.id.scanBtn); sendBtn = findViewById(R.id.sendBtn); editText = findViewById(R.id.editText); scanBtn.setOnClickListener(this); sendBtn.setOnClickListener(this); lvNewDevices = (ListView) findViewById(R.id.lvNewDevices); mBTDevices = new ArrayList<>(); mDeviceListAdapter = new DeviceListAdapter(this, R.layout.device_adapter_view, mBTDevices); lvNewDevices.setOnItemClickListener(this); lvNewDevices.setAdapter(mDeviceListAdapter); } @Override protected void onResume() { super.onResume(); registerBluetoothBroadcast(); } @Override protected void onPause() { super.onPause(); unregisterReceiver(bluetoothBroadCoast); } /** * different set of BroadCast Receivers for different bluetooth operations */ private void registerBluetoothBroadcast() { bluetoothBroadCoast = new BluetoothBroadCoast(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothDevice.ACTION_FOUND); intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED); intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED); intentFilter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED); intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); registerReceiver(bluetoothBroadCoast, intentFilter); } /** * checking run time permission for location */ private void checksPermission() { if (!hasPermission()) { ActivityCompat.requestPermissions(this, permissions, 2001); } else { // if permission granted check for check for bluetooth connection setupBlueTooth(); } } private boolean hasPermission() { for (int i = 0; i < permissions.length; i++) { if (ContextCompat.checkSelfPermission(this, permissions[i]) != PackageManager.PERMISSION_GRANTED) { return false; } } return true; } public void setupBlueTooth() { bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); if (bluetoothManager != null) { bluetoothAdapter = bluetoothManager.getAdapter(); bluetoothServiceConnection = new BluetoothConnectionService(this); } if (!bluetoothAdapter.isEnabled()) { } enableBluetooth(); } // enable the bluetooth... public void enableBluetooth() { Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(intent, ENABLE_REQUEST_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == ENABLE_REQUEST_CODE) { if (resultCode == RESULT_OK) { if (isScanButtonClicked) { mBTDevices.clear(); bluetoothAdapter.startDiscovery(); } } } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { case 2001: { setupBlueTooth(); break; } } } @Override public void onClick(View view) { if (view.getId() == R.id.scanBtn) { isScanButtonClicked = true; mBTDevices.clear(); mDeviceListAdapter.notifyDataSetChanged(); if (!bluetoothAdapter.isEnabled()) { enableBluetooth(); } else { if (!bluetoothAdapter.isDiscovering()) { bluetoothAdapter.cancelDiscovery(); bluetoothAdapter.startDiscovery(); } } }else if (view.getId()==R.id.sendBtn){ bluetoothServiceConnection.write(editText.getText().toString().getBytes()); } } @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { //first cancel discovery because its very memory intensive. bluetoothAdapter.cancelDiscovery(); String deviceName = mBTDevices.get(i).getName(); String deviceAddress = mBTDevices.get(i).getAddress(); //create the bond. if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) { Log.d(TAG, "Trying to pair with " + deviceName); mBTDevices.get(i).createBond(); mBTDevice = mBTDevices.get(i); } } class BluetoothBroadCoast extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); // Broadcast for finding bluetooth device... Most Important Broadcast receiver... if (action != null && action.equals(BluetoothDevice.ACTION_FOUND)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // Add new Found Bluetooth device.. Log.i("BT", device.getName() + "\n" + device.getAddress()); if (mBTDevices != null && !mBTDevices.contains(device)) { mBTDevices.add(device); } Log.d(TAG, "device found"); mDeviceListAdapter.notifyDataSetChanged(); } //Broadcast for starting discoverying other bluetooth device... else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED)) { Log.d(TAG, "mBroadcastReceiver: Discovery Started."); } // Broadcast for canceling discovery device... else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) { Log.d(TAG, "mBroadcastReceiver: Discovery Finished."); //BluetoothConnectionManager.getInstance().checkBluetoothDevice(); }// Pairing or bonding Broadcast for device... else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) { BluetoothDevice mDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); //3 cases: //case1: this case is for bonded already and this save connected device // and start Bluetooth connection to paired device... if (mDevice.getBondState() == BluetoothDevice.BOND_BONDED) { Log.d(TAG, "BroadcastReceiver: BOND_BONDED."); bluetoothServiceConnection.startClient(mDevice, BluetoothConnectionService.MY_UUID_INSECURE); } //case2: creating a bone if (mDevice.getBondState() == BluetoothDevice.BOND_BONDING) { Log.d(TAG, "BroadcastReceiver: BOND_BONDING."); } //case3: breaking a bond if (mDevice.getBondState() == BluetoothDevice.BOND_NONE) { Log.d(TAG, "BroadcastReceiver: BOND_NONE."); } } // This broadcast fires when other device is connected... else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) { Log.d(TAG, "mBroadcastReceiver4: Connected."); Toast.makeText(BluetoothDeviceListActivity.this, "connected to device", Toast.LENGTH_SHORT).show(); } // This broadcast fired when other device is disconnected... else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) { Log.d(TAG, "mBroadcastReceiver4: Disconnected."); Toast.makeText(BluetoothDeviceListActivity.this, "disconnected to device", Toast.LENGTH_SHORT).show(); } } } }
Step 4:
Now add these code in class BluetoothConnectionService
import android.app.Activity; import android.app.ProgressDialog; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothServerSocket; import android.bluetooth.BluetoothSocket; import android.content.Context; import android.util.Log; import android.widget.Toast; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charset; import java.util.UUID; public class BluetoothConnectionService { private static final String TAG = "BluetoothConnectionServ"; private static final String appName = "BLEDEMO"; public static final UUID MY_UUID_INSECURE = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); // private static final UUID MY_UUID_INSECURE = UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66"); private AcceptThread mAcceptThread; private ConnectThread mConnectThread; private BluetoothDevice mmDevices; private UUID deviceUUID; ProgressDialog progressDialog; private ConnectedThread mConnectedThread; private final BluetoothAdapter mBluetoothAdapter; Context context; public BluetoothConnectionService(Context context) { this.context = context; this.mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); start(); } private class AcceptThread extends Thread { private final BluetoothServerSocket mmServerSocket; public AcceptThread() { BluetoothServerSocket tmp = null; try { tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(appName, MY_UUID_INSECURE); Log.d(TAG, "AcceptThread: Setting up using: " + MY_UUID_INSECURE); } catch (IOException e) { e.printStackTrace(); } mmServerSocket = tmp; } public void run() { Log.d(TAG, "run: AcceptThread Running."); BluetoothSocket socket = null; try { Log.d(TAG, "run: RFCOM server socket start...."); socket = mmServerSocket.accept(); Log.d(TAG, "run: RFCOM server socket accepted connection."); } catch (IOException e) { Log.e(TAG, "AcceptThread: IOException: " + e.getMessage()); } if (socket != null) { connected(socket, mmDevices); } } public void cancel() { Log.d(TAG, "cancel: Canceling AcceptThread."); try { mmServerSocket.close(); } catch (IOException e) { Log.e(TAG, "cancel: Close of AcceptThread ServerSocket failed. " + e.getMessage()); } } } private class ConnectThread extends Thread { private BluetoothSocket mmSocket; public ConnectThread(BluetoothDevice bluetoothDevice, UUID uuid) { mmDevices = bluetoothDevice; deviceUUID = uuid; BluetoothSocket tmp = null; Log.i(TAG, "RUN: mConnectThread"); try { Log.d(TAG, "ConnectThread: Trying to create InsecureRfcommSocket using UUID: " + MY_UUID_INSECURE); tmp = bluetoothDevice.createRfcommSocketToServiceRecord(deviceUUID); } catch (IOException e) { Log.e(TAG, "ConnectThread: Could not create InsecureRfcommSocket" + e.getMessage()); } mmSocket = tmp; } public void run() { mBluetoothAdapter.cancelDiscovery(); try { mmSocket.connect(); Log.d(TAG, "run: ConnectThread Connected."); if (mmSocket != null) { connected(mmSocket, mmDevices); } } catch (final IOException e) { /*try { mmSocket.close(); Log.d(TAG, "run: Closed Socket."); } catch (IOException ex) { Log.e(TAG, "mConnectThread: run: Unable to close connection in socket." + ex.getMessage()); }*/ Log.e(TAG, "run: ConnectThread: Could not connect ot UUId: " + MY_UUID_INSECURE); ((Activity) context).runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(context, "something went wrong", Toast.LENGTH_SHORT).show(); } }); } } public void cancel() { try { Log.d(TAG, "cancel: Closing client Socket"); mmSocket.close(); } catch (IOException e) { Log.e(TAG, "cancel: close() of mmsocket in ConnectThread failed. " + e.getMessage()); } } } public synchronized void start() { Log.d(TAG, "start"); if (mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; } if (mAcceptThread == null) { mAcceptThread = new AcceptThread(); mAcceptThread.start(); } } public void startClient(BluetoothDevice device, UUID uuid) { Log.d(TAG, "startClient: Started"); // progressDialog = ProgressDialog.show(context, "Connecting bluetooth", "Please wait....", true); mConnectThread = new ConnectThread(device, uuid); mConnectThread.start(); } /* this thread will connected to device by bluetooth and receive data from other bluetooth device...*/ private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream inputStream; private final OutputStream outputStream; public ConnectedThread(BluetoothSocket socket) { Log.d(TAG, "ConnectedThread: Starting"); mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; /*try { progressDialog.dismiss(); } catch (NullPointerException e) { e.printStackTrace(); }*/ try { tmpIn = mmSocket.getInputStream(); tmpOut = mmSocket.getOutputStream(); } catch (IOException e) { e.printStackTrace(); } inputStream = tmpIn; outputStream = tmpOut; } public void run() { byte[] buffer = new byte[1024]; int bytes; while (true) { try { bytes = inputStream.read(buffer); // this is incoming message... final String incomingMessage = new String(buffer, 0, bytes); ((Activity) context).runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(context, incomingMessage, Toast.LENGTH_SHORT).show(); } }); Log.d(TAG, "InputStream: " + incomingMessage); } catch (IOException e) { Log.e(TAG, "write: Error reading inputStream. " + e.getMessage()); break; } } } public void write(byte[] bytes) { String text = new String(bytes, Charset.defaultCharset()); Log.d(TAG, "write: Writing to Output Stream: " + text); try { outputStream.write(bytes); } catch (IOException e) { Log.e(TAG, "write: Error writing to outputStream. " + e.getMessage()); } } public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } } private void connected(BluetoothSocket mmSocket, BluetoothDevice mmDevices) { Log.d(TAG, "connected: Starting"); mConnectedThread = new ConnectedThread(mmSocket); mConnectedThread.start(); } public void write(byte[] out) { Log.d(TAG, "write: Write Called."); mConnectedThread.write(out); } }
Step 5:
Now add these code in DeviceListAdapter for listing Bluetooth devices
import android.bluetooth.BluetoothDevice; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; import java.util.ArrayList; public class DeviceListAdapter extends ArrayAdapter<BluetoothDevice> { private LayoutInflater mLayoutInflater; private ArrayList<BluetoothDevice> mDevices; private int mViewResourceId; private ListView lvNewDevices; public DeviceListAdapter(Context context, int tvResourceId, ArrayList<BluetoothDevice> devices) { super(context, tvResourceId, devices); this.mDevices = devices; mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mViewResourceId = tvResourceId; } public View getView(int position, View convertView, ViewGroup parent) { convertView = mLayoutInflater.inflate(mViewResourceId, null); BluetoothDevice device = mDevices.get(position); if (device != null) { TextView deviceName = (TextView) convertView.findViewById(R.id.tvDeviceName); TextView deviceAdress = (TextView) convertView.findViewById(R.id.tvDeviceAddress); if (deviceName != null) { deviceName.setText(device.getName()); } if (deviceAdress != null) { deviceAdress.setText(device.getAddress()); } } return convertView; } }
Step 6:
Now add these code in device_adapter_view layout
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/tvDeviceName" android:textSize="15sp"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/tvDeviceAddress" android:textSize="15sp"/> </LinearLayout>
Now on running this code, we can see our application will scan for available Bluetooth devices and we see the list of devices and can pair and connect with them for basic data communication(like sending text messages).
You can also read our blogs on Android:
1: Android Navigation Component – Android Jetpack
2: Offline Content Storage and Sync with Server when Modified
3: Custom Camera using SurfaceView
5: How to Use Data Binding in Android
InnovationM is a globally renowned Android app development company in India that caters to a strong & secure Android app development, iOS app development, hybrid app development services. Our commitment & engagement towards our target gives us brighter in the world of technology and has led us to establish success stories consecutively which makes us the best iOS app development company in India. We are also rated as the best Mobile app development company in India.
Thanks for giving your valuable time. Keep reading and keep learning 🙂