DEV Community

Cover image for Connecting to Smart Gloves Using Bluetooth in Navigation Glove IoT application Using Kotlin - Part 5
HMS Community
HMS Community

Posted on

Connecting to Smart Gloves Using Bluetooth in Navigation Glove IoT application Using Kotlin - Part 5

Introduction

In this article, we will learn how to connect smart gloves from the paired devices. The process is in the smart gloves application. Smart glove application shows all the paired Bluetooth devices. User has to select the gloves and connect to Bluetooth device.

If you are new to the series of articles, follow articles.

Beginner: Integration of Huawei Account kit in Navigation Glove IoT application Using Kotlin - Part 1

Beginner: Integration of Huawei Map kit in Navigation Glove IoT application Using Kotlin - Part 2

Beginner: Integration of Huawei Site kit in Navigation Glove IoT application Using Kotlin - Part 3

Beginner: Integration of Huawei Direction API in Navigation Glove IoT application Using Kotlin - Part 4

In this article, we learn how to display all the paired device in the application. We will also learn how to integrate the Recyclerview in android. Make sure device is already paired to phone.

Note: Application is built in androidx if you are developing application in the older than androidx you need to add the recyclerview dependencies.

Add the following permission in AndroidManifest.xml

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
Enter fullscreen mode Exit fullscreen mode

Follow the steps

Step 1: Add the recyclerview in the activity_connect_smart_gloves.xml

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_above="@+id/pairedDeviceBtn"
    android:layout_below="@id/messageTv"
    tools:listitem="@layout/paired_device_list_item"/>
Enter fullscreen mode Exit fullscreen mode

Step 2: If you want to display items let us create one xml file.

paired_device_list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:layout_margin="10dp"
    app:cardElevation="6dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:gravity="center|start"
        android:orientation="horizontal"
        android:padding="5dp"
        android:id="@+id/rootLayout">

        <ImageView
            android:id="@+id/imageview"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_marginStart="5dp"
            android:src="@drawable/gloves_ic"
            android:visibility="visible" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginStart="5dp"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_weight="1"
                android:gravity="center|start"
                android:orientation="horizontal">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="10dp"
                    android:layout_marginLeft="15dp"
                    android:text="@string/name"
                    android:textSize="16sp"
                    android:textStyle="bold" />

                <TextView
                    android:id="@+id/deviceName"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="10dp"
                    android:layout_marginLeft="15dp"
                    android:textSize="16sp"
                    android:textStyle="bold" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_weight="1"
                android:gravity="center|start"
                android:orientation="horizontal">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="10dp"
                    android:layout_marginLeft="15dp"
                    android:text="@string/mac_address"
                    android:textSize="16sp"
                    android:textStyle="bold" />

                <TextView
                    android:id="@+id/macAddress"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="10dp"
                    android:layout_marginLeft="15dp"
                    android:textSize="16sp"
                    android:textStyle="bold" />
            </LinearLayout>
        </LinearLayout>
    </LinearLayout>

</androidx.cardview.widget.CardView>
Enter fullscreen mode Exit fullscreen mode

Step 3: Create data class for device model (DeviceModel.kt)

package com.huawei.navigationglove.model

data class DeviceModel(val name: String, val macAddress: String)
Enter fullscreen mode Exit fullscreen mode

Step 4: declare layout manager in activity.

private lateinit var linearLayoutManager: LinearLayoutManager
Enter fullscreen mode Exit fullscreen mode

Step 5: Declare the device model variable and the paired device list.

private var pairedDeviceList = ArrayList<DeviceModel>()
var deviceModel: DeviceModel? = null
Enter fullscreen mode Exit fullscreen mode

Step 6: Initialize the layout manager and set it to recyclerview in onCreate().

linearLayoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = linearLayoutManager
Enter fullscreen mode Exit fullscreen mode

Step 7: Now create PairedDeviceListAdapter.kt for recycler view.

package com.huawei.navigationglove.ui.adapters

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.huawei.navigationglove.R
import com.huawei.navigationglove.callbacks.OnDeviceClickCallback
import com.huawei.navigationglove.model.DeviceModel

class PairedDevicesAdapter(
    private val mList: List<DeviceModel>,
    private val onDeviceClickCallback: OnDeviceClickCallback
) :
    RecyclerView.Adapter<PairedDevicesAdapter.ViewHolder>() {

    // create new views
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.paired_device_list_item, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val deviceModel = mList[position]
        holder.deviceName.text = deviceModel.name
        holder.macAddress.text = deviceModel.macAddress
        holder.rootLayout.setOnClickListener { onDeviceClickCallback.onDeviceClick(deviceModel) }
    }

    // return the number of the items in the list
    override fun getItemCount(): Int {
        return mList.size
    }

    // Holds the views for adding it to image and text
    class ViewHolder(ItemView: View) : RecyclerView.ViewHolder(ItemView) {
        val deviceName: TextView = itemView.findViewById(R.id.deviceName)
        val macAddress: TextView = itemView.findViewById(R.id.macAddress)
        val rootLayout: LinearLayout = itemView.findViewById(R.id.rootLayout)
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 8: Now get all the paired devices, and set the list of devices to adapter.

private fun pairedDevicesList() {
    pairedDeviceList = ArrayList<DeviceModel>()
    pairedDevices = myBluetooth!!.bondedDevices
    val list: ArrayList<String> = ArrayList<String>()
    if ((pairedDevices as MutableSet<BluetoothDevice>?)!!.size > 0) {
        for (bt in (pairedDevices as MutableSet<BluetoothDevice>?)!!) {
            Log.e(TAG, bt.name + "\n" + bt.address)
            list.add(bt.name + "\n" + bt.address) //Get the device's name and the address
            deviceModel = DeviceModel(bt.name, bt.address)
            pairedDeviceList.add(deviceModel!!)
        }
        val adapter = PairedDevicesAdapter(pairedDeviceList, this)
        recyclerView.adapter = adapter
    } else {
        Toast.makeText(
            applicationContext,
            "No Paired Bluetooth Devices Found.",
            Toast.LENGTH_LONG
        ).show()
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 9: By now recyclerview will show the list of paired devices. Now when user clicks on the device it has to connect. So now lets create onclick for recyclerview. To do that we will do it using interface callback.

Create OnDeviceClickCallback.kt interface.


package com.huawei.navigationglove.callbacks

import com.huawei.navigationglove.model.DeviceModel
interface OnDeviceClickCallback {
fun onDeviceClick(deviceModel: DeviceModel)
}
Enter fullscreen mode Exit fullscreen mode

Step 9: Implement this interface in activity.

class ConnectSmartGlovesActivity : AppCompatActivity(), OnDeviceClickCallback {
Enter fullscreen mode Exit fullscreen mode

Now override the function.

override fun onDeviceClick(deviceModel: DeviceModel) {
address = deviceModel.macAddress
ConnectBT(this).execute()
}
Enter fullscreen mode Exit fullscreen mode

Step 10: Now create following variables.

private var progress: ProgressDialog? =null //This progress dialog box while connecting to bluetooth
private var isBtConnected = false
var btSocket: BluetoothSocket? = null //Bridge which sends data to bluetooth from Android app
var myBluetooth: BluetoothAdapter? = null
val myUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB") //Unique
var address: String? = null
Enter fullscreen mode Exit fullscreen mode

Step: 11: Create Async class for connecting.

//This class contains functions that need to be done to connect to the HC-05 module

open class ConnectBT(val context: Context) : AsyncTask<Void?, Void?, Void?>() // UI thread
{
    private var ConnectSuccess = true //if it's here, it's almost connected
    override fun onPreExecute() {
        progress = ProgressDialog.show(
            context,
            "Connecting...",
            "Please wait!!!"
        ) //show a progress dialog
    }


    @SuppressLint("MissingPermission")
    override fun doInBackground(vararg devices: Void?): Void? //while the progress dialog is shown, the connection is done in background
    {
        try {
            if (btSocket == null || !isBtConnected) {
                myBluetooth =
                    BluetoothAdapter.getDefaultAdapter() //get the mobile bluetooth device
                val dispositivo: BluetoothDevice = myBluetooth!!.getRemoteDevice(address) //connects to the device's address and checks if it's available
                Log.e(TAG,"Device: "+Gson().toJson(dispositivo))
                btSocket = dispositivo.createInsecureRfcommSocketToServiceRecord(myUUID) //create a RFCOMM (SPP) connection
                Log.e(TAG,"Device: "+Gson().toJson(btSocket))
                BluetoothAdapter.getDefaultAdapter().cancelDiscovery()
                btSocket!!.connect() //start connection
            }
        } catch (e: IOException) {
            ConnectSuccess = false //if the try failed, you can check the exception here
            Log.e("MapsActivity","Device not connected" +e.message)
        }
        return null
    }

    override fun onPostExecute(result: Void?) //after the doInBackground, it checks if everything went fine
    {
        super.onPostExecute(result)
        if (!ConnectSuccess) {
            val toast =
                Toast.makeText(context, "Failure", Toast.LENGTH_LONG)
            toast.show()
            val handler = Handler()
            handler.postDelayed({ toast.cancel() }, 300)
            //TODO need to check this
            //finish()
        } else {
            val toast = Toast.makeText(context, "Success.", Toast.LENGTH_LONG)
            toast.show()
            val handler = Handler()
            handler.postDelayed({ toast.cancel() }, 300)

            //msg("Connected.");
            SystemClock.sleep(1000)
            isBtConnected = true
        }
        progress!!.dismiss()
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 12: To get the connection and disconnection state create register broadcast receiver in onCreate().

val filter = IntentFilter()
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED)
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED)
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED)
this.registerReceiver(nReceiver, filter)
Enter fullscreen mode Exit fullscreen mode

Step 13: Create broadcast receiver.

//This BroadcastReceiver finds listens the status of bluetooth
private val nReceiver: BroadcastReceiver? = object : BroadcastReceiver() {
    @RequiresApi(Build.VERSION_CODES.M)
    override fun onReceive(context: Context, intent: Intent) {
        val action = intent.action
        val device = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
        if (BluetoothDevice.ACTION_FOUND == action) {
        } else if (BluetoothDevice.ACTION_ACL_CONNECTED == action) {
            co = true
            Log.e("mode:", "Connected")
            requestLocationUpdatesWithCallback()
        } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED == action) {
        } else if (BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED == action) {
            Log.e("mode:", "disConnected")
        } else if (BluetoothDevice.ACTION_ACL_DISCONNECTED == action) {
            co = false
            Log.e("mode:", "disConnected1")
            val vib = context.getSystemService(Vibrator::class.java)
            Log.e("Vibe", "" + vib.hasVibrator())
            //t1.speak("Your Bluetooth Has Been Disconnected", TextToSpeech.QUEUE_FLUSH, null);
            for (i in 0..4) {
                vib.vibrate(700)
                SystemClock.sleep(1000)
            }
            i = 0
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Result

Image description

Tips and Tricks

  1. Make sure you have added Bluetooth permission in AndroidManifest.xml

  2. Make sure you phone Bluetooth is enabled.

  3. If you are building application below androidx, Make sure you have added the recyclerview dependency in build.gradle file.

Conclusion

In this article, we have learnt how to use recyclerview in the android application along with that we have displayed the list of paired devices in the smart gloves application. And also we have learnt how to connect device from the smart gloves application.

Reference

Bluetooth Official document

Recyclerview Document

Top comments (0)