I'm using an USB-Receiver to handle the Communication with a Temperature Sensor attached via USB to the Phone.
Everything is working fine so far, but if i restart the Phone, the App throws an USB-Permission pop-up directly after restarting, even if there isn't any USB-Device attached to the Phone at that Moment.
Has anyone an Idea of what's causing this strange Problem?
[ EDIT: I'm Sorry, the App isn't asking for USB Permission, the popup asks if i want to Open the app if "this device is connected" but there's obviously no device attached.]
Here is the Code of the USB-Receiver:
//Initial USB Settings Receiver
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
#Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized (this) {
final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
// is usb permission has been granted, try to open a connection
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
if (device != null) {
// call method to set up device communication
Constants result = mcp2221.open();
if (result != Constants.SUCCESS) {
//nothing by now
} else {
openConnectionToMCP2221();
}
}
}
}
}
if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
// close the connection and release all resources
closeAllResources();
// leave a bit of time for the COM thread to close
try {
Thread.sleep(20);
}catch(InterruptedException e){e.printStackTrace();}
mcp2221Comm = null;
Toast.makeText(getApplicationContext(), "Device detached",
Toast.LENGTH_SHORT).show();
}
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device != null) {
Toast.makeText(getApplicationContext(), "Device attached",
Toast.LENGTH_SHORT).show();
mStopUSBThread=false;
// only try to connect if an MCP2221 is attached
if (device.getVendorId() == MCP2221_VID && device.getProductId() == MCP2221_PID) {
Constants result = mcp2221.open();
switch (result) {
case SUCCESS:
openConnectionToMCP2221();
break;
case CONNECTION_FAILED:
Toast.makeText(getApplicationContext(), "ERROR: connection failed", Toast.LENGTH_SHORT).show();
break;
case NO_USB_PERMISSION:
Toast.makeText(getApplicationContext(), "ERROR: no USB permission", Toast.LENGTH_SHORT).show();
mcp2221.requestUsbPermission(mPermissionIntent);
break;
default:
break;
}
}
}
}
}
};
And here is the onCreate() part:
//USB Connection
mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
final IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
registerReceiver(mUsbReceiver, filter);
//Checking if theres a Device already connected
.......
Got it!
It was an
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
</intent-filter>
that was declared in AndroidManifest.xml under <activity>.
I don't fully understand, why it caused this Bug, but removing it kept the functionality of my App while getting rid of the Problem.
Only 'negative' aspect might be, that now the App doesn't ask to open if the Sensor is attached to the phone.
Related
I'm stuck on figuring out how to ask for permission to access a USB com device, wait for the user input, then proceed accordingly if permission granted. I can't figure out what the "onRequestPermissionsResult" is for when UsbManager asks for permissions. I noticed that listener never gets called when UsbManager requests permission, so its not used in the way I originally thought.
This code is all in the MainActivity.
Here I'm setting my Intent for when my USB device is connected or disconnected, and initializing UsbManager.
Note I'm not using LOGCAT to log debug messages because my Android device has to be disconnected from Android Studio to plug in the USB com device I'm developing the app for. Instead I'm logging to the app UI.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DoIntent();
m_manager = (UsbManager) getSystemService(Context.USB_SERVICE);
}
private void DoIntent () {
m_usbReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action) || UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) {
try {
OnDeviceConnected();
// m_textViewDebug.setText("USB Connected");
} catch (Exception e) {
m_textViewDebug.setText(e.getMessage());
}
} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action) || UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
m_port = null;
m_serialIoManager = null;
m_isInitialized = false;
m_textViewDebug.setText("USB Disconnected");
}
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(m_usbReceiver , filter);
Then here is what happens when a device is connected. I want to establish permission as soon as its connected.
private void OnDeviceConnected () throws Exception {
ProbeTable customTable = new ProbeTable();
customTable.addProduct(0x239a, 0x800c, CdcAcmSerialDriver.class);
UsbSerialProber prober = new UsbSerialProber(customTable);
List<UsbSerialDriver> drivers = prober.findAllDrivers(m_manager);
UsbDeviceConnection connection = null;
UsbSerialDriver driver = drivers.get(0);
PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(INTENT_ACTION_GRANT_USB), 0);
m_manager.requestPermission(driver.getDevice(), usbPermissionIntent);
/// Need some kind of pause or check for permissions here before executing forward.or
/// handle everything after on a different routine called after permission has been selected.
/// Continues to execute before user has time to respond to permissions.
try {
connection = m_manager.openDevice(driver.getDevice());
} catch (Exception e) {
throw new Exception(e.getMessage());
}
if (connection == null) {
throw new Exception ("Could not open device.");
}
m_port = driver.getPorts().get(0);
try {
m_port.open(connection);
m_port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
m_port.setDTR(true);
} catch (Exception e) {
throw new Exception(e.getMessage());
}
m_serialIoManager = new SerialInputOutputManager(m_port, m_listener);
m_executor.submit(m_serialIoManager);
m_isInitialized = true;
}
Then here is what I'm originally trying to do once permission has been granted.
I can't get any logging message to appear from this scope, so I believe it's never being called and I'm using it incorrectly.
#Override
public void onRequestPermissionsResult(final int requestCode, String[] permissions, int[] grantResults) {
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
/// Never gets called :/
m_textViewDebug.setText(Integer.toString(requestCode));
}
});
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
/// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
/// permission was granted, yay! Do the
/// contacts-related task you need to do.
} else {
/// permission denied, boo! Disable the
/// functionality that depends on this permission.
}
return;
case USB_PERMISSION_GRANTED: { /// Not the real enum because I'm not sure where to find what it is.
try {
/// Need to somehow pass driver from OnDeviceConnected to this scope, or make it class property.
connection = m_manager.openDevice(driver.getDevice());
} catch (Exception e) {
throw new Exception(e.getMessage());
}
if (connection == null) {
throw new Exception ("Could not open device.");
}
m_port = driver.getPorts().get(0);
try {
m_port.open(connection);
m_port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
m_port.setDTR(true);
} catch (Exception e) {
throw new Exception(e.getMessage());
}
m_serialIoManager = new SerialInputOutputManager(m_port, m_listener);
m_executor.submit(m_serialIoManager);
m_isInitialized = true
}
/// other 'case' lines to check for other
/// permissions this app might request.
}
}
I'm trying to log what requestCode is so I can write a case for whatever the USB permission code is. I can't find a compiled list anywhere in the docs of what all the options are that requestCode could be.
MY_PERMISSIONS_REQUEST_READ_CONTACTS actually throws a compile error because I have no idea where it comes from. This guide isn't very detail with USB specifically. That guide is also where I got the switch statement in my above routine.
EDIT:
I tried messing around with UsbManager.EXTRA_PERMISSION_GRANTED to see if that could work. I added it as an action to my intent filter.
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
filter.addAction(UsbManager.EXTRA_PERMISSION_GRANTED);
registerReceiver(m_usbReceiver, filter);
Then I'm logging what the action of the intent is coming into my Broadcast Receiver, but nothing happens when a USB permission is granted or denied.
What kind of action or event is triggered when "OK" is tapped in this above image? Been scratching my head at this for a few days poking at the API.
I finally figured it out taking a closer look at this.
I have this before trying to establish an intent filter.
public static final String INTENT_ACTION_GRANT_USB = BuildConfig.APPLICATION_ID + ".GRANT_USB";
PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(INTENT_ACTION_GRANT_USB), 0);
IntentFilter filter = new IntentFilter();
And I changed it to this.
private static final String ACTION_USB_PERMISSION = BuildConfig.APPLICATION_ID + ".USB_PERMISSION";
m_permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
The key difference was that new IntentFilter needed that ACTION_USB_PERMISSION string.
Now in my Broadcast Receiver, I have this condition that is being called as expected.
else if (ACTION_USB_PERMISSION.equals(action)) {
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
m_textViewDebug.setText("USB Permission Granted");
try {
OnDevicePermissionGranted();
} catch (Exception e) {
m_textViewDebug.setText(e.getMessage());
}
}
else {
m_textViewDebug.setText("USB Permission Denied");
}
}
Took me a while to figure out how to use EXTRA_PERMISSION_GRANTED.
When this here says "EXTRA_PERMISSION_GRANTED containing boolean indicating whether permission was granted by the user" I'm thinking this whole time I'm trying to find a boolean flag on some object to verify permission. I didn't realize I had to call a special method on the intent and supply that string to get my true or false. Seems very counter intuitive to me.
I realize the biggest mistake was not supplying the correct string when making the new intent filter. I found a bunch of other examples that had it without any arguments.
For my application, I need to establish a connection with an attached Arduino device, here is the code:
public String openConnection(UsbManager manager, Context context) {
// getting the driver with an external library...
UsbSerialDriver driver = availableDrivers.get(0);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
manager.requestPermission(driver.getDevice(), pi);
UsbDeviceConnection connection = manager.openDevice(driver.getDevice());
if (connection == null) {
return "Found a device, but cannot connect";
}
// otherwise, continue and do stuff
}
The problem is that, when a device is attached, the first time I open the app it shows the alert asking for the permission, but if I click "OK", the connection is null, so it returns early. However, the second time it does not ask for any permission but the connection is opened and everything works fine.
Why does this happen?
I know this is not the most correct approach to open an USB connection, but I have other issues that are not inherent to the question, so I'm rather intrested to understand why does this happen than what should I do instead
I'm testing this on Android 8.1.0
Try to previously ask for permission and start the rest of your code from a Broadcast Receiver that listens for the USB permission granted.
This is showed in Google's docs:
private static final String ACTION_USB_PERMISSION =
"com.android.example.USB_PERMISSION";
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized (this) {
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
if(device != null){
//call method to set up device communication
}
}
else {
Log.d(TAG, "permission denied for device " + device);
}
}
}
}
};
Here's how you register the Broadcast Receiver:
UsbManager mUsbManager = (UsbManager)
getSystemService(Context.USB_SERVICE);
private static final String ACTION_USB_PERMISSION =
"com.android.example.USB_PERMISSION";
...
mPermissionIntent = PendingIntent.getBroadcast(this, 0, new
Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbReceiver, filter);
And then you start it all with:
UsbDevice device;
...
mUsbManager.requestPermission(device, mPermissionIntent);
In the way you do it, the device tries to connect to USB even before the permission has been granted and so it fails.
I want to ask that there are application available in which user can connect USB to Android via OTG cable device and play the media (specially videos) contained by it.
i have made a Broadcast Receiver to detect the attached USB, i want to read the content also. I am using this code snippet.
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
synchronized (this) {
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if(device != null){
//
Log.d("1","DEATTCHED-" + device);
}
}
}
//
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
synchronized (this) {
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
if(device != null){
//
Log.d("1","ATTACHED-" + device);
}
}
else {
PendingIntent mPermissionIntent;
mPermissionIntent = PendingIntent.getBroadcast(MainActivity.this, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_ONE_SHOT);
mUsbManager.requestPermission(device, mPermissionIntent);
}
}
}
//
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized (this) {
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
if(device != null){
//
Log.d("1","PERMISSION-" + device);
}
}
}
}
}
};
I want to make such kind of application.
Do anyone have some idea about that?
After researches of many days i have found the solution
https://github.com/1hakr/AnExplorer
Dividing the video in multiple sub videos may work for you.
What I suggest : instead of saving full video in one temp path, divide that video in multiple sub videos and then replaced AVPlayerItem property of AVPlayer accordingly.
So now functionality is working same as video streaming . :)
You can also convert the CMSampleBuffer that the AVAssetReader returns into a CGImage and then a UIImage and display that in a UIImageView, to render the frames as they are pulled out of the original video file.
There is example code inside the AVFoundation Programming Guide that shows how to do this conversion.
In my app I need pairing bluetooth device and immediately connect with it.
I have the following function in order to pairing devices:
public boolean createBond(BluetoothDevice btDevice)
{
try {
Log.d("pairDevice()", "Start Pairing...");
Method m = btDevice.getClass().getMethod("createBond", (Class[]) null);
Boolean returnValue = (Boolean) m.invoke(btDevice, (Object[]) null);
Log.d("pairDevice()", "Pairing finished.");
return returnValue;
} catch (Exception e) {
Log.e("pairDevice()", e.getMessage());
}
return false;
}
And I use it as the following way:
Boolean isBonded = false;
try {
isBonded = createBond(bdDevice);
if(isBonded)
{
//Connect with device
}
}
And it show me the dialog to pairing devices and enter the pin.
The problem is that createBond functions always return true, and it doen's wait until I enter the pin and paired with device, so I don't use correctly:
isBonded = createBond(bdDevice);
if(isBonded) {...}
So the question is How can I paired with device and when it is paired connect to it?
P.D My code is based in the first answer of the following thread: Android + Pair devices via bluetooth programmatically
I found the solution.
First I need a BroadcastReceiver like:
private BroadcastReceiver myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
// CONNECT
}
} else if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// Discover new device
}
}
};
And then I need register the receiver as follow:
IntentFilter intentFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
context.registerReceiver(myReceiver, intentFilter);
In this way the receiver is listening for ACTION_FOUND (Discover new device) and ACTION_BOND_STATE_CHANGED (Device change its bond state), then I check if the new state is BOND_BOUNDED and if it is I connect with device.
Now when I call createBond Method (described in the question) and enter the pin, ACTION_BOND_STATE_CHANGED will fire and device.getBondState() == BluetoothDevice.BOND_BONDED will be True and it will connect.
I understand how to get a list of paired devices, but how can I tell if they are connected?
It must be possible since I see them listed in my phone's Bluetooth device list and it states their connection status.
Add the Bluetooth permission to your AndroidManifest,
<uses-permission android:name="android.permission.BLUETOOTH" />
Then use intent filters to listen to the ACTION_ACL_CONNECTED, ACTION_ACL_DISCONNECT_REQUESTED, and ACTION_ACL_DISCONNECTED broadcasts:
public void onCreate() {
...
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
this.registerReceiver(mReceiver, filter);
}
//The BroadcastReceiver that listens for bluetooth broadcasts
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
... //Device found
}
else if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
... //Device is now connected
}
else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
... //Done searching
}
else if (BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED.equals(action)) {
... //Device is about to disconnect
}
else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
... //Device has disconnected
}
}
};
A few notes:
There is no way to retrieve a list of connected devices at application startup. The Bluetooth API does not allow you to query, instead it allows you to listen to changes.
A hoaky workaround to the above problem would be to retrieve the list of all known/paired devices... then trying to connect to each one (to determine if you're connected).
Alternatively, you could have a background service watch the Bluetooth API and write the device states to disk for your application to use at a later date.
In my use case I only wanted to see if a Bluetooth headset is connected for a VoIP app. The following solution worked for me.
Kotlin:
fun isBluetoothHeadsetConnected(): Boolean {
val mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
return (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled
&& mBluetoothAdapter.getProfileConnectionState(BluetoothHeadset.HEADSET) == BluetoothHeadset.STATE_CONNECTED)
}
Java:
public static boolean isBluetoothHeadsetConnected() {
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()
&& mBluetoothAdapter.getProfileConnectionState(BluetoothHeadset.HEADSET) == BluetoothHeadset.STATE_CONNECTED;
}
Of course you'll need the Bluetooth permission:
<uses-permission android:name="android.permission.BLUETOOTH" />
There is an isConnected function in the BluetoothDevice system API in https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/bluetooth/BluetoothDevice.java.
If you want to know if a bounded (paired) device is currently connected or not, the following function works fine for me:
public static boolean isConnected(BluetoothDevice device) {
try {
Method m = device.getClass().getMethod("isConnected", (Class[]) null);
boolean connected = (boolean) m.invoke(device, (Object[]) null);
return connected;
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
For some reason, BluetoothAdapter.ACTION_ACL_CONNECTED could not be resolved by Android Studio. Perhaps it was deprecated in Android 4.2.2?
Here is a modification of Skylarsutton's code (Big thanks to Skylarsutton for his answer.) . The registration code is the same; the receiver code differs slightly. I use this in a service which updates a Bluetooth-connected flag that other parts of the app reference.
public void onCreate() {
//...
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
this.registerReceiver(BTReceiver, filter);
}
//The BroadcastReceiver that listens for bluetooth broadcasts
private final BroadcastReceiver BTReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
//Do something if connected
Toast.makeText(getApplicationContext(), "BT Connected", Toast.LENGTH_SHORT).show();
}
else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
//Do something if disconnected
Toast.makeText(getApplicationContext(), "BT Disconnected", Toast.LENGTH_SHORT).show();
}
//else if...
}
};
This code is for the headset profiles, and probably it will work for other profiles too.
First you need to provide a profile listener (Kotlin code):
private val mProfileListener = object : BluetoothProfile.ServiceListener {
override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
if (profile == BluetoothProfile.HEADSET)
mBluetoothHeadset = proxy as BluetoothHeadset
}
override fun onServiceDisconnected(profile: Int) {
if (profile == BluetoothProfile.HEADSET) {
mBluetoothHeadset = null
}
}
}
Then while checking Bluetooth:
mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET)
if (!mBluetoothAdapter.isEnabled) {
return Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
}
It takes a bit of time until onSeviceConnected is called. After that you may get the list of the connected headset devices from:
mBluetoothHeadset!!.connectedDevices
BluetoothAdapter.getDefaultAdapter().isEnabled ->
returns true when Bluetooth is open.
val audioManager = this.getSystemService(Context.AUDIO_SERVICE) as AudioManager
audioManager.isBluetoothScoOn ->
returns true when a device connected
I was really looking for a way to fetch the connection status of a device, not listen to connection events. Here's what worked for me:
BluetoothManager bm = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
List<BluetoothDevice> devices = bm.getConnectedDevices(BluetoothProfile.GATT);
int status = -1;
for (BluetoothDevice device : devices) {
status = bm.getConnectionState(device, BLuetoothGatt.GATT);
// compare status to:
// BluetoothProfile.STATE_CONNECTED
// BluetoothProfile.STATE_CONNECTING
// BluetoothProfile.STATE_DISCONNECTED
// BluetoothProfile.STATE_DISCONNECTING
}