I have a problem with my bluetooth scanner.I'm using a samsung A50 with android 11 .So my Bluetooth is supposed to check the surrounding bluetooth devices and then add them into an ArrayList and display it on screen with a recyclerview. The problem is I don't find any device. I tried to debug my code and It seems that my code doesn't go to mReceiver that's why I don't detect any device. The code was working last week I found the devices (I found the same device multiple times it's normal) but they didn't add to the ArrayList. So Now I'm asking you guys here is my code.
I'm pretty sure I gave all the permissions necessary and even more and I also given the location permission to my app.
This is The Activity:
class ConnectionActivity : AppCompatActivity(),BluetoothOnItemClickListener{
private lateinit var binding : ActivityConnectionBinding
private lateinit var manager : RecyclerView.LayoutManager
val dataset = Datasource().loadDataBluetooth()
private val devices_list : ArrayList<BluetoothDevice> = ArrayList()
var m_bluetoothAdapter : BluetoothAdapter? = null
val REQUEST_ENABLE_BLUETOOTH = 1
companion object{
val EXTRA_ADDRESS :String = "Device_address"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityConnectionBinding.inflate(layoutInflater)
setContentView(binding.root)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = "Bluetooth"
m_bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
if(m_bluetoothAdapter == null){
Toast.makeText(this, "not supported", Toast.LENGTH_SHORT).show()
return
}
if (!m_bluetoothAdapter!!.isEnabled){
val enableBluetoothIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
startActivityForResult(enableBluetoothIntent,REQUEST_ENABLE_BLUETOOTH)
val discoverableIntent: Intent = Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE).apply {
putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300)
}
startActivity(discoverableIntent)
}else{
discoverDevices()}
}
private val mReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
if (BluetoothDevice.ACTION_FOUND == action) {
// A Bluetooth device was found
// Getting device information from the intent
val device = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
if (device != null) {
devices_list.add(device)
println("SIZE : ${devices_list.size}")
}
}
}
}
private fun discoverDevices(){
if (m_bluetoothAdapter!!.isDiscovering) {
// Bluetooth is already in mode discovery mode, we cancel to restart it again
m_bluetoothAdapter!!.cancelDiscovery()
}
val bool = m_bluetoothAdapter?.startDiscovery()
Log.i("", bool.toString())
val filter = IntentFilter(BluetoothDevice.ACTION_FOUND)
registerReceiver(mReceiver, IntentFilter(BluetoothDevice.ACTION_FOUND))
println("Count : ${devices_list.size}")
manager = LinearLayoutManager(this)
binding.recycleView.adapter = ItemAdapter(devices_list,this)
binding.recycleView.layoutManager = manager
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_ENABLE_BLUETOOTH) {
if (resultCode == Activity.RESULT_OK) {
if (m_bluetoothAdapter!!.isEnabled) {
Toast.makeText(this, "Bluetooth enabled", Toast.LENGTH_SHORT).show()
discoverDevices()
} else {
Toast.makeText(this, "Bluetooth disabled", Toast.LENGTH_SHORT).show()
}
} else if (resultCode == Activity.RESULT_CANCELED) {
Toast.makeText(this, "Bluetooth enabling has been canceled", Toast.LENGTH_SHORT).show()
}
}
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val inflater: MenuInflater = menuInflater
inflater.inflate(R.menu.menu_connection, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.ic_ip -> Toast.makeText(this, "IP", Toast.LENGTH_SHORT).show()
}
return super.onOptionsItemSelected(item)
}
override fun onStop() {
super.onStop()
unregisterReceiver(mReceiver)
}
}
And This is the Adapter :
class ItemAdapter(private val devices : ArrayList<BluetoothDevice>, var clickListener: BluetoothOnItemClickListener): RecyclerView.Adapter<ItemAdapter.ItemViewHolder>(){
inner class ItemViewHolder(val binding: ListItemBinding) : RecyclerView.ViewHolder(binding.root){
fun bind(item : BluetoothDevice,action: BluetoothOnItemClickListener){
binding.item?.StringNameB = item.name
itemView.setOnClickListener {
binding.item?.checked = true
notifyItemChanged(bindingAdapterPosition)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
val inflater = LayoutInflater.from(parent.context)
val adapterlayout = ListItemBinding.inflate(inflater,parent,false)
return ItemViewHolder(adapterlayout)
}
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
holder.bind(devices[position],clickListener)
holder.binding.executePendingBindings()
}
override fun getItemCount(): Int {
return devices.size
}
}
interface BluetoothOnItemClickListener{
}
And this is my the permissions I have in my manifest
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
You also need to request permissions at runtime. Have a look at the links below for more information:-
Bluetooth scanner not discovering devices
Turn on LE scanning without asking for user permission
How to request location permission at runtime
The ultimate guide to Android BLE
Related
I am trying to implement the most simple app to scan for a BLE device. I have given the necessary rights:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
However, onScanResult never gets called. Bluetooth is enabled on my phone and the BLE device is on, this is my code:
class MainActivity : AppCompatActivity() {
private val bleScanner = object :ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
Log.d("DeviceListActivity", "onScanResult()")
super.onScanResult(callbackType, result)
val device = result.device
Log.d("DeviceScanner", "Device found: ${device.address} - ${device.name ?: "Unknown"}")
//Log.d("DeviceListActivity","onScanResult: ${result.device?.address} - ${result.device?.name}")
}
}
private val bluetoothLeScanner: BluetoothLeScanner
get() {
val bluetoothManager = applicationContext.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
val bluetoothAdapter: BluetoothAdapter = bluetoothManager.adapter
return bluetoothAdapter.bluetoothLeScanner
}
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
Log.d("DeviceListActivity", "onCreate()")
super.onCreate(savedInstanceState, persistentState)
setContentView(R.layout.activity_device_list)
}
override fun onStart() {
Log.d("DeviceListActivity", "onStart()")
super.onStart()
enableLocation()
bluetoothLeScanner.startScan(bleScanner)
}
override fun onStop() {
Log.d("DeviceListActivity", "onStop()")
bluetoothLeScanner.stopScan(bleScanner)
super.onStop()
}
private fun enableLocation(): Boolean {
val service = applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val enabled = service.isProviderEnabled(LocationManager.GPS_PROVIDER)
return enabled
}
}
What am I missing?
Yes it was the missing requested permission. I inserted following function into onResume()
if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
0
)
} else {
leDeviceScanner.start()
}
It now workes like a charm. Thanks!
For a few days, I'm trying to implement a BLE connection in my app. I do that in secondary Fragment rather than the main one. But when I scan to find a BLE device (with startScan(leScanCallback)), it never goes in the callback method leScanCallback. I followed some tutorial but I can't find out why it's not working.
Here is my MainActivity.kt
package com.example.start
class MainActivity : AppCompatActivity() {
private lateinit var drawerLayout: DrawerLayout
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
drawerLayout = binding.drawerLayout
val navController = this.findNavController(R.id.myNavHostFragment)
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout) //link the navigation controller & drawer layout to the app bar
NavigationUI.setupWithNavController(binding.navView, navController) //allows the user to display the navigation drawer
//PERMISSION
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (ContextCompat.checkSelfPermission(baseContext,
Manifest.permission.ACCESS_BACKGROUND_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
val PERMISSION_CODE = 0 //Should be >= 0
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
PERMISSION_CODE)
}
}
//==========================Bluetooth Part==========================================
val REQUEST_ENABLE_BT : Int = 1 //Will stock the result of enabling the bluetooth
//RESULT_OK = -1 (0xffffffff)
//RESULT_CANCELLED = 0 (0x00000000)
//val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter()
val bluetoothAdapter: BluetoothAdapter by lazy {
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
bluetoothManager.adapter
}
if (bluetoothAdapter == null) {
// Device doesn't support Bluetooth
}
if (bluetoothAdapter?.isEnabled == false) { //If bluetooth is disable, we active it
val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT)
}
}
}
And here is my ConnectFragment.kt where I push the button "btnScan" to start the research
package com.example.start
private const val SELECT_DEVICE_REQUEST_CODE = 0
class ConnectFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
//return inflater.inflate(R.layout.fragment_connect, container, false)
val binding = DataBindingUtil.inflate<FragmentConnectBinding>(
inflater, R.layout.fragment_connect, container, false
)
binding.btnScan.setOnClickListener {
view : View ->
scanLeDevice()
}
return binding.root
}
private val bluetoothLeScanner: BluetoothLeScanner
get() {
val bluetoothManager = requireContext().getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
val bluetoothAdapter = bluetoothManager.adapter
return bluetoothAdapter.bluetoothLeScanner
}
// Device scan callback.
private val leScanCallback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
super.onScanResult(callbackType, result)
//TODO TEST TEST TEST
Log.d("ScanDeviceActivity", "leScanCallback >>")
Log.d("ScanDeviceActivity", "onScanResult(): ${result?.device?.address} - ${result?.device?.name}")
}
override fun onBatchScanResults(results: MutableList<ScanResult>?) {
super.onBatchScanResults(results)
Log.d("DeviceListActivity","onBatchScanResults:${results.toString()}")
}
override fun onScanFailed(errorCode: Int) {
super.onScanFailed(errorCode)
Log.d("DeviceListActivity", "onScanFailed: $errorCode")
}
}
private var scanning = false
private val handler = Handler()
// Stops scanning after 10 seconds.
private val SCAN_PERIOD: Long = 10000
fun scanLeDevice() {
if (!scanning) { // Stops scanning after a pre-defined scan period.
handler.postDelayed({
scanning = false
bluetoothLeScanner.stopScan(leScanCallback)
}, SCAN_PERIOD)
scanning = true
//PERMISSION COARSE LOCATION
Log.d("ScanDeviceStart", "startScan()")
when (PermissionChecker.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION)) {
PackageManager.PERMISSION_GRANTED -> bluetoothLeScanner.startScan(leScanCallback)
else -> requestPermissions(arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), 1)
}
} else {
scanning = false
bluetoothLeScanner.stopScan(leScanCallback)
}
}
//Permission
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
1 -> when (grantResults) {
intArrayOf(PackageManager.PERMISSION_GRANTED) -> {
Log.d("ScanDevices", "onRequestPermissionsResult(PERMISSION_GRANTED)")
bluetoothLeScanner.startScan(leScanCallback)
}
else -> {
Log.d("ScanDevices", "onRequestPermissionsResult(not PERMISSION_GRANTED)")
}
}
else -> super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
}
}
After I pushed my button, the debug's console ends with:
D/BluetoothLeScanner: Stop Scan with callback
I am currently developing an Android NFC application. This application contains a NavigationDrawer in which I can access 3 different fragments which each correspond to 3 different NFC features.
First, I want to verify that my application can scan an NFC tag (here I have an NXP NTAG 5 boost tag, which is an NFC Forum Type 5 tag).
My problem is that when my application is running, the onNewIntent of my MainActivity is never called.
I'm sure it's not due to the hardware as I can detect this tag with common applications, but it may be due to parameters I passed to a function in the NfcManager file, like activity.applicationContext but I'm not sure.
For now, I specify that I don't want a particular activity to launch when a tag is detected, I just want to detect an NFC tag when the application runs.
Can you help me?
MainActivity:
class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
private val TAG = MainActivity::class.java.simpleName
var tag: Tag? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
checkNFC(this)
setupNFC(this)
configureToolbar()
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
appBarConfiguration = AppBarConfiguration(setOf(
R.id.nav_memory, R.id.nav_tag, R.id.nav_product), drawerLayout)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main, menu)
return true
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
private fun configureToolbar() {
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == ENABLE_NFC_REQUEST_CODE) {
onActivityResultOutSourced(this)
} else {
super.onActivityResult(requestCode, resultCode, data)
}
}
override fun onResume() {
super.onResume()
onResumeOutSourced(this)
}
override fun onPause() {
super.onPause()
onPauseOutSourced(this)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
Log.d(TAG, "Card ID: " + Tools.byteArrayToHex(tag!!.id))
val techList = tag!!.techList
//Check that the discovered tag is a vicinity tag
if (techList[0] == "android.nfc.tech.NfcV") {
val tagUid = tag!!.id
nfcvTag = NfcV.get(tag)
//ISO/IEC 15693 tags can be operated in two modes:
// Select mode and Addressed mode.
//To work in the select mode it is needed to send a SELECT
// command at the beginning of communic.
//In the address mode, the tag UID is sent within each command.
//This application works in SELECT MODE.
val select_command: ByteArray = RFCommands.cmd_select
System.arraycopy(tagUid, 0, select_command, 2, 8)
if (nfcvTag != null) {
try {
nfcvTag!!.connect()
val select_respo = nfcvTag!!.transceive(select_command)
Log.d(TAG, "Select response: " +
Tools.byteArrayToHex(select_respo))
} catch (e: IOException) {
e.printStackTrace()
}
}
}
}
companion object {
const val ENABLE_NFC_REQUEST_CODE = 0x11
private var nfcvTag: NfcV? = null
}
}
NfcManager:
class NfcManager {
companion object {
private var mNfcAdapter: NfcAdapter? = null
private var mPendingIntent: PendingIntent? = null
private lateinit var writeTagFilters: Array<IntentFilter>
private lateinit var mTechLists: Array<Array<String>>
/**
* Check the availability of NFC interface and let the user enable them
* if not active during the activity creation
*/
fun checkNFC(#NonNull activity: Activity) {
if (activity.packageManager.hasSystemFeature(PackageManager.FEATURE_NFC)) {
mNfcAdapter = NfcAdapter.getDefaultAdapter(activity.applicationContext)
if (mNfcAdapter != null && !mNfcAdapter!!.isEnabled) {
AlertDialog.Builder(activity.applicationContext)
.setTitle(activity.resources.getString(R.string.dialog_nfc_not_enabled_title))
.setMessage(activity.resources.getString(R.string.dialog_nfc_not_enabled_msg))
.setPositiveButton(activity.resources.getString(R.string.dialog_nfc_not_enabled_positive_btn)
) { _, _ -> activity.startActivityForResult(Intent(Settings.ACTION_NFC_SETTINGS), MainActivity.ENABLE_NFC_REQUEST_CODE) }
.setNegativeButton(activity.resources.getString(R.string.dialog_nfc_not_enabled_negative_btn)
) { _, _ ->
Toast.makeText(activity.applicationContext, activity.resources.getString(R.string.nfc_not_enabled), Toast.LENGTH_LONG).show()
activity.finish()
}.show()
}
} else {
Toast.makeText(activity.applicationContext, activity.resources.getString(R.string.nfc_not_enabled), Toast.LENGTH_LONG).show()
activity.finish()
}
}
/**
* Create a generic PendingIntent that will be delivered to this activity.
* The NFC stack will fill in the intent with the details of the discovered
* tag before delivering it to this activity.
*/
fun setupNFC(#NonNull activity: Activity) {
mPendingIntent = PendingIntent.getActivity(activity, 0, Intent(
activity, javaClass)
.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0)
val tagDetected = IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED)
writeTagFilters = arrayOf(tagDetected)
mTechLists = arrayOf(arrayOf(
NfcV::class.java.name
))
}
fun onActivityResultOutSourced(#NonNull activity: Activity) {
mNfcAdapter = NfcAdapter.getDefaultAdapter(activity)
if (mNfcAdapter!!.isEnabled) {
Toast.makeText(activity.applicationContext, activity.resources.getString(R.string.nfc_not_enabled), Toast.LENGTH_LONG).show()
activity.finish()
}
}
fun onResumeOutSourced(#NonNull activity: Activity) {
if (mNfcAdapter != null) {
mNfcAdapter!!.enableForegroundDispatch(activity, mPendingIntent, writeTagFilters, mTechLists)
}
}
fun onPauseOutSourced(#NonNull activity: Activity) {
if (mNfcAdapter != null) mNfcAdapter!!.disableForegroundDispatch(activity)
}
}
}
EDIT:
The objective of the "NfcManager" class was to encapsulate as much as possible the NFC functions, in order to avoid having them in the "MainActivity".
The problem is that the previous code doesn't work, while the following code, in which the logic is contained in the "MainActivity" works well.
I really don't understand what the problem is.
MainActivity:
class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
private val TAG: String = this::class.java.simpleName
private val ENABLE_NFC_REQUEST_CODE = 0x11
private var mNfcAdapter: NfcAdapter? = null
private var nfcvTag: NfcV? = null
var tag: Tag? = null
private var mPendingIntent: PendingIntent? = null
private lateinit var writeTagFilters: Array<IntentFilter>
private lateinit var mTechLists: Array<Array<String>>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
checkNFC()
mNfcAdapter = NfcAdapter.getDefaultAdapter(this)
setNfcIntent()
configureToolbar()
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
appBarConfiguration = AppBarConfiguration(setOf(
R.id.nav_memory, R.id.nav_tag, R.id.nav_product), drawerLayout)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main, menu)
return true
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
private fun configureToolbar() {
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
}
private fun setNfcIntent() {
// Create a generic PendingIntent that will be delivered to this activity. The NFC stack will fill
// in the intent with the details of the discovered tag before delivering it to this activity.
mPendingIntent = PendingIntent.getActivity(this, 0, Intent(
applicationContext, javaClass)
.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0)
val tagDetected = IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED)
writeTagFilters = arrayOf(tagDetected)
mTechLists = arrayOf(arrayOf(
NfcV::class.java.name
))
}
override fun onActivityResult(requestCode: Int,
resultCode: Int, data: Intent?) {
if (requestCode == ENABLE_NFC_REQUEST_CODE) {
mNfcAdapter = NfcAdapter.getDefaultAdapter(this)
if (mNfcAdapter!!.isEnabled) {
Toast.makeText(applicationContext, resources.getString(R.string.nfc_not_enabled), Toast.LENGTH_LONG).show()
finish()
}
} else {
super.onActivityResult(requestCode, resultCode, data)
}
}
/**
* Check the availability of NFC and BLE interfaces and let the user enable them
* if not active during the activity creation
*/
private fun checkNFC() {
if (packageManager.hasSystemFeature(PackageManager.FEATURE_NFC)) {
mNfcAdapter = NfcAdapter.getDefaultAdapter(this)
if (mNfcAdapter != null && !mNfcAdapter!!.isEnabled) {
AlertDialog.Builder(this)
.setTitle(resources.getString(R.string.dialog_nfc_not_enabled_title))
.setMessage(resources.getString(R.string.dialog_nfc_not_enabled_msg))
.setPositiveButton(resources.getString(R.string.dialog_nfc_not_enabled_positive_btn)
) { dialog, which -> startActivityForResult(Intent(Settings.ACTION_NFC_SETTINGS), ENABLE_NFC_REQUEST_CODE) }
.setNegativeButton(resources.getString(R.string.dialog_nfc_not_enabled_negative_btn)
) { dialog, which ->
Toast.makeText(applicationContext, resources.getString(R.string.nfc_not_enabled), Toast.LENGTH_LONG).show()
finish()
}.show()
}
} else {
Toast.makeText(applicationContext, resources.getString(R.string.nfc_not_enabled), Toast.LENGTH_LONG).show()
finish()
}
}
override fun onResume() {
super.onResume()
if (mNfcAdapter != null) {
mNfcAdapter!!.enableForegroundDispatch(this, mPendingIntent, writeTagFilters, mTechLists)
}
}
override fun onPause() {
super.onPause()
if (mNfcAdapter != null) mNfcAdapter!!.disableForegroundDispatch(this)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
Log.d(TAG, "Card ID: " + Tools.byteArrayToHex(tag!!.id))
val techList = tag!!.techList
//Check that the discovered tag is a vicinity tag
if (techList[0] == "android.nfc.tech.NfcV") {
val tagUid = tag!!.id
nfcvTag = NfcV.get(tag)
//ISO/IEC 15693 tags can be operated in two modes:
// Select mode and Addressed mode.
//To work in the select mode it is needed to send a SELECT
// command at the beginning of communic.
//In the address mode, the tag UID is sent within each command.
//This application works in SELECT MODE.
val select_command: ByteArray = RFCommands.cmd_select
System.arraycopy(tagUid, 0, select_command, 2, 8)
if (nfcvTag != null) {
try {
nfcvTag!!.connect()
val select_respo: ByteArray = nfcvTag!!.transceive(select_command)
Log.d(TAG, "Select response: " +
Tools.byteArrayToHex(select_respo))
} catch (e: IOException) {
e.printStackTrace()
}
}
}
}
}
I have a small bluetooth project in kotlin. The code for it is below:
var mArrayAdapter: ArrayAdapter<String>? = null
val bluetoothAdapter: BluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
var myList: MutableList<String> = mutableListOf<String>()
var devices = ArrayList<BluetoothDevice>()
var devicesMap = HashMap<String, BluetoothDevice>()
class MainActivity : AppCompatActivity(), View.OnClickListener {
private val REQUEST_ENABLE_BT = 1000
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<View>(R.id.btn_scan).setOnClickListener(this)
checkBluetoothStatus()
val filter = IntentFilter(BluetoothDevice.ACTION_FOUND)
registerReceiver(receiver, filter)
mArrayAdapter = ArrayAdapter(this, R.layout.dialog_select_device)
}
private val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action: String? = intent.action
when(action) {
BluetoothDevice.ACTION_FOUND -> {
val device: BluetoothDevice =
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
val deviceName = device.name
myList.add(deviceName)
}
}
}
}
override fun onClick(v: View?) {
when (v?.id) {
R.id.btn_scan ->
startScan()
}
}
fun startScan() {
if (BluetoothAdapter.getDefaultAdapter().startDiscovery()) {
val myToast = Toast.makeText(this, myList.toString(), Toast.LENGTH_SHORT)
myToast.show()
}
}
}
When a user clicks a button, I want to be able to see a list of other bluetooth devices (which I thought the onReceive method would enable me to do). So I'm adding device names to the myList variable, which I'm then displaying in a toast. But at the moment when they click, nothing comes up. Grateful for your advice.
I'm trying to list all BLE devices on an Android device, using Kotlin (the Java-version don't work either) but I don't get any devices or any call back at all, except for a "scan was already started"
I have the correct uses-permission in the manifest.
Here is the current minimum of code, I'm trying with.
But even the sample code from Google is listing any devices.
I'm running on a Pixel with Android version 8.1.0.
I have it working on iOS, with the basic BLE device list (Swift)!
private val bleScanner = object :ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult?) {
super.onScanResult(callbackType, result)
Log.d("DeviceListActivity","onScanResult: ${result?.device?.address} - ${result?.device?.name}")
}
override fun onBatchScanResults(results: MutableList<ScanResult>?) {
super.onBatchScanResults(results)
Log.d("DeviceListActivity","onBatchScanResults:${results.toString()}")
}
override fun onScanFailed(errorCode: Int) {
super.onScanFailed(errorCode)
Log.d("DeviceListActivity", "onScanFailed: $errorCode")
}
}
private val bluetoothLeScanner: BluetoothLeScanner
get() {
val bluetoothManager = applicationContext.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
val bluetoothAdapter = bluetoothManager.adapter
return bluetoothAdapter.bluetoothLeScanner
}
class ListDevicesAdapter(context: Context?, resource: Int) : ArrayAdapter<String>(context, resource)
override fun onCreate(savedInstanceState: Bundle?) {
Log.d("DeviceListActivity", "onCreate()")
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_device_list)
}
override fun onStart() {
Log.d("DeviceListActivity","onStart()")
super.onStart()
bluetoothLeScanner.startScan(bleScanner)
}
override fun onStop() {
bluetoothLeScanner.stopScan(bleScanner)
super.onStop()
}
You need to declare permission:
uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
and you for devices with android 6.0 + request manually this permission:
override fun onStart() {
Log.d("ScanDeviceActivity", "onStart()")
super.onStart()
when (PermissionChecker.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)) {
PackageManager.PERMISSION_GRANTED -> bluetoothLeScanner.startScan(bleScanner)
else -> requestPermissions(arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), 1)
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
1 -> when (grantResults) {
intArrayOf(PackageManager.PERMISSION_GRANTED) -> {
Log.d("ScanDevices", "onRequestPermissionsResult(PERMISSION_GRANTED)")
bluetoothLeScanner.startScan(bleScanner)
}
else -> {
Log.d("ScanDevices", "onRequestPermissionsResult(not PERMISSION_GRANTED)")
}
}
else -> super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
}