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 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
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" />
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"/>
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>
Step 3: Create data class for device model (DeviceModel.kt)
package com.huawei.navigationglove.model
data class DeviceModel(val name: String, val macAddress: String)
Step 4: declare layout manager in activity.
private lateinit var linearLayoutManager: LinearLayoutManager
Step 5: Declare the device model variable and the paired device list.
private var pairedDeviceList = ArrayList<DeviceModel>()
var deviceModel: DeviceModel? = null
Step 6: Initialize the layout manager and set it to recyclerview in onCreate().
linearLayoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = linearLayoutManager
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)
}
}
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()
}
}
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)
}
Step 9: Implement this interface in activity.
class ConnectSmartGlovesActivity : AppCompatActivity(), OnDeviceClickCallback {
Now override the function.
override fun onDeviceClick(deviceModel: DeviceModel) {
address = deviceModel.macAddress
ConnectBT(this).execute()
}
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
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()
}
}
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)
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
}
}
}
Result
Tips and Tricks
Make sure you have added Bluetooth permission in AndroidManifest.xml
Make sure you phone Bluetooth is enabled.
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.
Top comments (0)