Bluetooth module | #14

DeviceListFragment

import android.Manifest
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.SharedPreferences
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.snackbar.Snackbar
import com.neco_dev.bt_def.databinding.FragmentListBinding

class DeviceListFragment : Fragment(), ItemAdapter.Listener {
private var preferences: SharedPreferences? = null
private lateinit var itemAdapter: ItemAdapter
private lateinit var discoveryAdapter: ItemAdapter
private var bAdapter: BluetoothAdapter? = null
private lateinit var binding: FragmentListBinding
private lateinit var btLauncher: ActivityResultLauncher<Intent>
private lateinit var pLauncher: ActivityResultLauncher<Array<String>>

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentListBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
preferences = activity?.getSharedPreferences(BluetoothConstants.PREFERENCES, Context.MODE_PRIVATE)
binding.imBluetoothOn.setOnClickListener {
btLauncher.launch(Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE))
}
binding.imBluetoothSearch.setOnClickListener {
try{
if(bAdapter?.isEnabled == true){
bAdapter?.startDiscovery()
it.visibility = View.GONE
binding.pbSearch.visibility = View.VISIBLE
}
} catch (e: SecurityException){
}
}
intentFilters()
checkPermissions()
initRcViews()
registerBtLauncher()
initBtAdapter()
bluetoothState()
}

private fun initRcViews() = with(binding){
rcViewPaired.layoutManager = LinearLayoutManager(requireContext())
rcViewSearch.layoutManager = LinearLayoutManager(requireContext())
itemAdapter = ItemAdapter(this@DeviceListFragment, false)
discoveryAdapter = ItemAdapter(this@DeviceListFragment, true)
rcViewPaired.adapter = itemAdapter
rcViewSearch.adapter = discoveryAdapter
}

private fun getPairedDevices(){
try {
val list = ArrayList<ListItem>()
val deviceList = bAdapter?.bondedDevices as Set<BluetoothDevice>
deviceList.forEach{
list.add(
ListItem(
it,
preferences?.getString(BluetoothConstants.MAC, "") == it.address
)
)
}
binding.tvEmptyPaired.visibility = if(list.isEmpty()) View.VISIBLE else View.GONE
itemAdapter.submitList(list)
} catch (e: SecurityException){

}

}

private fun initBtAdapter(){
val bManager = activity?.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
bAdapter = bManager.adapter
}

private fun bluetoothState(){
if (bAdapter?.isEnabled == true){
changeButtonColor(binding.imBluetoothOn, Color.GREEN)
getPairedDevices()
}
}

private fun registerBtLauncher(){
btLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
){
if (it.resultCode == Activity.RESULT_OK){
changeButtonColor(binding.imBluetoothOn, Color.GREEN)
getPairedDevices()
Snackbar.make(binding.root, "Блютуз включен!", Snackbar.LENGTH_LONG).show()
} else {
Snackbar.make(binding.root, "Блютуз выключен!", Snackbar.LENGTH_LONG).show()
}
}
}

private fun checkPermissions(){
if(!checkBtPermissions()){
registerPermissionListener()
launchBtPermissions()
}
}

private fun launchBtPermissions(){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
pLauncher.launch(arrayOf(
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.ACCESS_FINE_LOCATION
))
} else {
pLauncher.launch(arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION
))
}
}

private fun registerPermissionListener(){
pLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
){

}
}

private fun saveMac(mac: String){
val editor = preferences?.edit()
editor?.putString(BluetoothConstants.MAC, mac)
editor?.apply()
}

override fun onClick(item: ListItem) {
saveMac(item.device.address)
}

private val bReceiver = object : BroadcastReceiver(){
override fun onReceive(p0: Context?, intent: Intent?) {
if(intent?.action == BluetoothDevice.ACTION_FOUND){
val device = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
val list = mutableSetOf<ListItem>()
list.addAll(discoveryAdapter.currentList)
if(device != null) list.add(ListItem(device, false))
discoveryAdapter.submitList(list.toList())
binding.tvEmptySearch.visibility = if(list.isEmpty()) View.VISIBLE else View.GONE
try{
Log.d("MyLog", "Device: ${device?.name}")
} catch (e: SecurityException){

}
} else if(intent?.action == BluetoothDevice.ACTION_BOND_STATE_CHANGED){
getPairedDevices()
} else if(intent?.action == BluetoothAdapter.ACTION_DISCOVERY_FINISHED){
binding.imBluetoothSearch.visibility = View.VISIBLE
binding.pbSearch.visibility = View.GONE
}
}
}

private fun intentFilters(){
val f1 = IntentFilter(BluetoothDevice.ACTION_FOUND)
val f2 = IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED)
val f3 = IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)
activity?.registerReceiver(bReceiver, f1)
activity?.registerReceiver(bReceiver, f2)
activity?.registerReceiver(bReceiver, f3)
}

}

fragment_list.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="match_parent"
android:background="#454545">

<androidx.cardview.widget.CardView
android:id="@+id/cardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="3dp"
android:layout_marginTop="3dp"
android:layout_marginEnd="3dp"
android:backgroundTint="#191919"
app:cardCornerRadius="6dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="horizontal">

<TextView
android:id="@+id/tvPaired"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="9dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="9dp"
android:text="@string/paired_devices"
android:textColor="@color/blue" />

<ImageButton
android:id="@+id/imBluetoothOn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
app:srcCompat="@drawable/ic_bluetooth_on" />
</LinearLayout>
</androidx.cardview.widget.CardView>

<androidx.cardview.widget.CardView
android:id="@+id/cardView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="3dp"
android:layout_marginEnd="3dp"
android:backgroundTint="#191919"
app:cardCornerRadius="6dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline2">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="horizontal">

<TextView
android:id="@+id/tvSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="9dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="9dp"
android:text="@string/search_devices"
android:textColor="@color/blue" />

<ProgressBar
android:id="@+id/pbSearch"
style="?android:attr/progressBarStyle"
android:layout_width="20dp"
android:layout_height="20dp"
android:visibility="gone" />

<ImageButton
android:id="@+id/imBluetoothSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
app:srcCompat="@drawable/ic_search" />
</LinearLayout>
</androidx.cardview.widget.CardView>

<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rcViewPaired"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="3dp"
android:layout_marginBottom="3dp"
app:layout_constraintBottom_toTopOf="@+id/guideline2"
app:layout_constraintEnd_toEndOf="@+id/cardView"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/cardView"
app:layout_constraintTop_toBottomOf="@+id/cardView"
app:layout_constraintVertical_bias="1.0" />

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rcViewSearch"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="3dp"
android:layout_marginBottom="3dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/cardView2"
app:layout_constraintStart_toStartOf="@+id/cardView2"
app:layout_constraintTop_toBottomOf="@+id/cardView2" />

<TextView
android:id="@+id/tvEmptyPaired"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/empty"
android:textColor="@color/white_dark"
android:textStyle="italic"
app:layout_constraintBottom_toTopOf="@+id/cardView2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/cardView" />

<TextView
android:id="@+id/tvEmptySearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/empty"
android:textColor="@color/white_dark"
android:textStyle="italic"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/cardView2" />
</androidx.constraintlayout.widget.ConstraintLayout>

Добавить комментарий

Ваш адрес email не будет опубликован.