Reputation: 2964
I've added <uses-permission android:name="android.permission.BLUETOOTH" />
to my manifest but the error
Missing permission required by BluetoothAdapter.isEnabled: android.permission.BLUETOOTH. is still there.
Also, in ContextCompat.checkSelfPermission(...)
what is the first parameter CONTEXT
? The documentation https://developer.android.com/training/permissions/requesting does not say.
And am I correct that I need to disconnect and reconnect bluetooth whenever the app is not being used?
class MainActivity : AppCompatActivity() {
var bt: BluetoothAdapter? = null
var bts: BluetoothSocket? = null
val REQUEST_BLUETOOTH_PERMISSION: Int = 1
val REQUEST_BLUETOOTH_ENABLE: Int = 2
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE))
{
Toast.makeText(
getApplicationContext(),
"Device does not support Bluetooth therefore this application cannot run.",
Toast.LENGTH_SHORT
).show();
return;
}
bt = BluetoothAdapter.getDefaultAdapter()
if (bt == null) {
// This device does not have Bluetooth.
Toast.makeText(
getApplicationContext(),
"Device does not have a Bluetooth adapter therefore this application cannot run.",
Toast.LENGTH_SHORT
).show();
return;
}
bluetoothConnect();
}
fun bluetoothConnect() {
if (ContextCompat.checkSelfPermission(
CONTEXT, // What is this? It's not explained at https://developer.android.com/training/permissions/requesting
Manifest.permission.BLUETOOTH
) == PackageManager.PERMISSION_GRANTED
) {
if (bt.isEnabled == false) { // Error: Missing permission required by BluetoothAdapter.isEnabled: android.permission.BLUETOOTH.
val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
startActivityForResult(enableBtIntent, REQUEST_BLUETOOTH_ENABLE)
} else {
val pairedDevices: Set<BluetoothDevice>? = bt.bondedDevices
pairedDevices?.forEach { device ->
val deviceName = device.name
val deviceHardwareAddress = device.address // MAC address
}
}
}
else {
// Request permission. That will call back to onActivityResult which in the case of success will call this method again.
// Ask for permission.
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.BLUETOOTH),
REQUEST_BLUETOOTH_PERMISSION
)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_BLUETOOTH_PERMISSION) {
if (resultCode == RESULT_OK) {
bluetoothConnect();
} else {
Toast.makeText(
getApplicationContext(),
"This application cannot run because it does not have Bluetooth permission.",
Toast.LENGTH_SHORT
).show();
// Do we need to quit? How?
}
}
else if( requestCode == REQUEST_BLUETOOTH_ENABLE)
{
if(resultCode == RESULT_OK)
{
// try again
bluetoothConnect();
}
else {
Toast.makeText(
getApplicationContext(),
"This application cannot run because Bluetooth is not enabled and could not be enabled.",
Toast.LENGTH_SHORT
).show();
// Do we need to quit? How?
}
}
}
override fun onPause() {
super.onPause()
// Release Bluetooth
}
override fun onResume() {
super.onResume()
// Connect Bluetooth
}
override fun onStop() {
super.onStop()
// Release Bluetooth
}
override fun onStart() {
super.onStart()
// Connect Bluetooth
}
}
Edit:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.rwb.btconnectortest">
<uses-permission android:name="android.permission.BLUETOOTH" />
<!--<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />-->
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/btconnectortestTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Upvotes: 0
Views: 7595
Reputation: 11
in manifest file add these two permission
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH"
#########################################################
*NOTE:i attached my bluetooth kotlin code , and its work with me. I enter code here
hope this helpful
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var myBluetooth:BluetoothAdapter? = null
lateinit var mypairedDevices:Set<BluetoothDevice>
val Request_Enable_Blutooth=1
companion object {
val EXTRA_ADDRESS :String= "Device_Address"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
myBluetooth= BluetoothAdapter.getDefaultAdapter()
if (myBluetooth == null)
{
Toast.makeText(applicationContext, "Bluetooth Device Not Available", Toast.LENGTH_LONG).show()
}
if (!myBluetooth!!.isEnabled)
{
val enableBlutoothIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
startActivityForResult(enableBlutoothIntent, Request_Enable_Blutooth)
}
binding.BTNPairedDevices.setOnClickListener {
pairedDeviceList()
}
}
private fun pairedDeviceList (){
mypairedDevices = myBluetooth!!.bondedDevices
val list : ArrayList<BluetoothDevice> = ArrayList()
if (!mypairedDevices.isEmpty())
{
for ( device:BluetoothDevice in mypairedDevices)
list.add(device)
//list.add(device.name() + "\n" + device.address())
Log.i("Device", "This is messeage")
}
else {
Toast.makeText(applicationContext, " NO PAIRED DEVICES FOUND", Toast.LENGTH_LONG).show()
}
val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, list)
binding.DeviceListView.adapter = adapter
binding.DeviceListView.onItemClickListener = AdapterView.OnItemClickListener{ _, _, position, _ ->
val device: BluetoothDevice = list[position]
val address: String = device.address
val intent = Intent(this, LedController::class.java)
intent.putExtra(EXTRA_ADDRESS, address)
startActivity(intent)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == Request_Enable_Blutooth)
{
if(resultCode ==Activity.RESULT_OK)
{
if (myBluetooth!!.isEnabled)
{ Toast.makeText(applicationContext, "Bluetooth Enabled", Toast.LENGTH_LONG).show()
}
else ( Toast.makeText(applicationContext, "Bluetooth Disabled", Toast.LENGTH_LONG).show()
)
}
} else if(resultCode == Activity.RESULT_CANCELED)
Toast.makeText(applicationContext, "Bluetooth has been canceled", Toast.LENGTH_LONG).show()
}
}
Upvotes: 1
Reputation: 2964
I restarted AndroidStudio and now the error has disappeared. What a complete piece of rubbish.
But now the layout is broken...
Upvotes: 0
Reputation: 27226
Just because comments are not good for this, let me give you a list of things you ought to do before you can act with Bluetooth. (apologies this is in Java because that's what I have right now, but very easy to translate to Kotlin if needed)
I'm doing this for BT LE (low energy) which is the preferred way for.. obvious reasons.
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
<uses-permission android:name="android.permission.BLUETOOTH"/>
// Does BLE exist?
if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)){
final BluetoothManager manager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
Now that you have a manager, you need to get the BluetoothAdapter
:
BluetoothAdapter bluetoothAdapter = manager.getAdapter();
All this is fine in onCreate, but keep in mind that you have to check if BT is enabled every time the user resumes the activity (For it could have been turned off/disabled/revoked/etc).
Likely in onResume:
// obviously, you need to check that Bt adapter isn't null and all that,
// otherwise you ought to go back and "construct" it again, check permissions, etc.
adapter = getBTAdapter(); // do all the checks in there...
boolean bluetoothEnabled = adapter != null && adapter.isEnabled();
If the BT radio is off (user turning it off), you can programmatically enable it, if you have the corresponding permission (which I think is BT admin or similar, you're gonna have to search on that one, because it's been a while).
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
I believe it was.
Since BT is a radio that needs power, it will take a while (seconds) to turn on and be available. For this you need to "listen" with Yet Another broadcast receiver...
In other words, the activity will fire an intent (startActivityForResult(...)
) telling Android to enable BT, you will subscribe to that broadcast to listen to the callback. Once android informs you that BT is on, you can go back to step 1 and start checking if it's enabled, you have permission, etc.
The callback is if I have not forgotten too much... looked like
public void onReceive(Context context, Intent intent) {
In there you ought to check for various BluetoothAdapter
states... among them:
BluetoothAdapter.ACTION_STATE_CHANGED
This signals that the state changed, but another nested if is needed to determine to what state...
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE);
switch (state) {
case BluetoothAdapter.STATE_OFF:
case BluetoothAdapter.STATE_TURNING_OFF:
case BluetoothAdapter.STATE_TURNING_ON:
case BluetoothAdapter.STATE_ON:
}
Those are all the ones you care (check the BluetoothAdapter enum for more info).
In the ON
you know BT is on... so..
Now you can tell the adapter that you want to scan
...
adapter.startLeScan(callback);
(remember to call stopLeScan(callback)
when you're done).
As each device is found, the callback
will be called with the info you need to attempt to connect and pair (if needed).
The signature of the callback (LeScanCallback
) is something like:
public void onScan(final BluetoothDevice device, int rssi, byte[] record);
(I'm typing by memory, so it may be a different name but you get the idea)
This is, as far as I can remember the old API.
API 21 has a ScanSettings.Builder()
where you can specify how you want to scan, but it's essentially a similar method. Initiate scan, pass a callback and wait for results to show up.
You have various modes too:
SCAN_MODE_BALANCED: Balance battery efficiency and scan speed
SCAN_MODE_LOW_LATENCY: Prefer scan speed over battery
SCAN_MODE_LOW_POWER: Prefer battery efficiency over scan speed
SCAN_MODE_OPPORTUNISTIC: can't remember :) I think it was to use other scanner results 'around' you. Never used it.
Once you have identified the device you were looking for the BluetoothDevice
has everything you need to tell BT to "connect" to it.
public void onScanResult(int callbackType, ScanResult scanResult) {
^ this is the signature of the "new" Scanner.
From that ScanResult, you can do:
int rssi = result.getRssi();
BluetoothDevice device = result.getDevice();
String advertiseName = device.getName();
String macAddress = device.getAddress();
If the scan fails for any reason, you get a callback on onScanFailed(int errorCode)
.
And again, there are various "reasons" (check the errorCode
) why the scan failed.
Remember I may be mixing API 18 or API 21 "apis" here, but the concept is very similar in both.
Once you have finally grabbed a Device's MAC address... you can ask the adapter to try to connect to it:
BluetoothDevice device = adapter.getRemoteDevice(macAddress);
device.connectGatt(context, false, anotherCallback);
The callback is of BluetoothGattCallback
and again, it has a bunch of methods among them onConnectionStateChange...
At this point you ought to read more about how Bluetooth works (and how it works on Android) because there are various modes (Gatt being one way) of operating with BT. It's impossible to know each and how/what you want to do once connected.
The rule of thumb will be: make sure you're prepared to having to re-pair or re-request permissions, because it's ultimately the user's choice to disable, turn off, walk-away, revoke permission, etc. at any point during this.
Good luck!
Upvotes: 2