Detect when a USB OTG device disconnects - android

I have an app which interacts with a USB OTG device:
When a USB device connects, a helper activity is started to display the Android confirmation dialog. This is done via an IntentFilter in the manifest.
The helper activity starts a service is started by sending it an app-specific intent.
The service’s onCreate() method populates an IntentFilter, adding the actions to which the service should react when running, including UsbManager.ACTION_USB_DEVICE_DETACHED. Adding extra debug output tells me the method runs when I expect it to, i.e. the IntentFilter is populated when I register the receiver.
The service’s onStartCommand() method calls an internal method which registers the BroadcastReceiver for the intent filter (if the service was started with the start intent, and has the necessary permissions—else the service terminates).
When the receiver receives UsbManager.ACTION_USB_DEVICE_DETACHED and the device reported is the one that is currently connected, it stops the service.
There is also a main activity, which is not involved in handling the USB device.
The service also gets called for other reasons, notably when a charger is connected. In this case the service looks for a Bluetooth device (if a USB device is already connected, indicated by a member of the service instance being non-null, this is skipped and the service exits).
Now, if I plug in the USB device, I get the confirmation and the service starts, and when I unplug the device, the service stops again. So far, so good.
However, in some cases the service keeps running even after the device is unplugged. I have noticed this always happens when the main activity was open when I connected the device. Logs show me that the service never receives the UsbManager.ACTION_USB_DEVICE_DETACHED broadcast.
While doing further tests (open main activity and navigate away from it before connecting the device), I found evidence that there may be two instances of the service running for some reason.
What is happening here, and how can I reliably detect that the USB device was disconnected?

This behavior appears to be caused by two factors:
As described above, the service gets started not only when a USB device connects, but also on other events, such as the device being connected to an AC adapter or the main activity being opened. In these cases it will look for a Bluetooth device (“autoconnect”) and exit if none is found, or if a USB device is already connected.
As a result, when autoconnect is enabled, opening the main activity will always start the first service instance. If a USB device connects after that, we may apparently have two service instances running. I suspect the disconnect broadcast may get picked up by the wrong instance.
If I disable autoconnect, the service does receive the disconnection event but ignores it, as the devices are not considered equal. Yet log output shows that the device path for both devices is the same. Further analysis revealed that I had simply used != to compare the two UsbDevice instances, which fails to catch two different class instances referring to the same device.
So we need to do two things:
Use UsbDevice#equals() rather than the equality operator for comparison.
Prevent multiple instances of the service from running. Ensure the service exits when no device is found, and Intents are delivered to the existing instance rather than starting a new one.

Related

Android receive callback when bluetooth device is paired/connected by the system automatically?

Is there any way to receive a callback when Android automatically pairs/connects to a bluetooth device, for instance my car, and not having the app already started/open (some kind of broadcast)? I have had thoughts about a service that periodically scans for devices and sees if they are already bonded, but that feels ineffective as Android already does this: it will automatically connect to for instance my car when I am in range. The idea is to start a specific job when I am in range of my car, and stop the job when I am out of range of my car, without having to start the app or have it open.
My initial thought was that there should be some kind of broadcast one could register to, to know when the device is "connected", and in that listener just start the job for some time or until the device is "disconnected". Note that having your phone in your pocket and not taking it up is a necessity. I have only seen examples that does this if the app is already open, by listening on state changes. Is this possible to not have the app open and only be "event driven" and listen on broadcasts?
Try the following code:
IntentFilter actionChangeFilter = new IntentFilter(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
mContext.registerReceiver(btDeviceConnectChangedReceiver, actionChangeFilter);
You can listen for the ACTION_STATE_CHANGED broadcast of the BluetoothAdapter.
See here for details
Edit:
The above is for changes of state of adapter. To listen to new connections etc use those listed here: BluetoothDevice

Automatically have an Android device connect & receive advertised data from BLE device

I have created an android application using android studio API 21 to scan & connect to a BLE device and subscribe to receive advertised data. This works great, but now I would like to do this automatically without having the user to manually run the android application. Is there a way for my android device to know when it is in range of the BLE device and to automatically connect and receive data if available? I'm just a little confused as to what code is needed in the Broadcast receiver class and does the Broadcast receiver class need to be in a service?
AFAIK, there is no such system broadcast for notifying BLE device found.
I think you will have to do it by yourself with a service
To scan BLE devices in background, you will have to run the scanning in a service.
Few requirements you may want.
Start the service on app start
This is the starting point of your service first run.
Just call startService in your activity onCreate.
Keep service running
See, how to keep service running
Stop BLE scanning on bluetooth disabled
It is meaningless to keep scanning while bluetooth disabled by user.
So, you may want this check. See, detecting bluetooth change
Start the service on device boot
See, start service at boot
Implement BLE scan in service
Move all the code from your scanning activity (or fragment) to the service. Something like,
BLEScanningService extends Service {
#Override
public int onStartCommand (Intent intent, int flags, int startId) {
if (/*Bluetooth is available*/) {
/*
Do BLE scan
*/
} else {
// Stop BLE scanning and stop this service
}
}
}
Then, your will have BLE scanning service always running in background :)
Maybe you may also want to broadcast some event from the service so that app UI and notification can update correspondingly.

Android: NSD service still available after closing app

i have a problem with Androids NSD.
I registered a service using NsdManager on device A. With an other device B in the same WiFi i started the app "bonjour browser" which was able to discover the service. Fine.
But when i closed the app which registered my service on device A, the service is still available on the other device B using "bonjour browser". I killed the app and still the service is available. When i disable the wifi connection of device A the service disappears on device B. But when i reconnect to the wifi WITHOUT starting the service registration app, the services pops up again. Strange.
Is this normal? Do i need to explicit un-register the service? I thought that the service should disappear as soon as my app (and the NsdManager) is not working anymore.
Thanks for help.
I had a similar problem when using NSD on Android.
Your app should explicitly un-register the service before exiting.

NfcAdapter.getDefaultAdapter returns null, when android application starts on BOOT_COMPLETED intent

NFC based Android application, which starts after boot complete (when BOOT_COMPLETED event received by BroadcastReceiver).
The Problem
Some times NfcAdapter.getDefaultAdapter(this) retunrs null; this is random/inconsistent, for some boot cycles it works fine and returns NfcAdapter, and for other boot cycles this method returns null.
I am suspecting, when it returns null, NFC Service not yet started, or NFC Service not fully running by the time BOOT_COMPLETED event is Broadcasted.
The question
Is there a way to make sure NFC Service is running and stable before BOOT_COMPLETED event is Broadcasted?
Assuming the device is rooted, would it help if init.rc modified? If yes, What is the tweak if any one has come across such a problem?

Android service that was running when the phone was shut down starts automatically when the phone is booted

I am currently developing an Android telephony application that includes a service to handle all the SIP signaling for making and receiving calls.
I want this service to start exclusively when the user has correctly logged into the application. However, I am observing an undesired behavior: if the device is shut down while the app is running, the service is automatically started after the phone boots. This does not happen if the application is closed at the moment of shutting down the phone.
I have been reading about it but no answer comes up. Could anybody explain why this happens and how to prevent it?
Thank you in advance.
Thanks to CommonsWare comment I have quickly found the answer:
[...] The only way a service starts up is if somebody starts it, and the OS will not do that on its own.
I was so blinded thinking the OS was responsible for it that I didn't notice it was being done on purpose, as an undocumented feature inherited from a former version of the app.
There was a BroadcastReceiver listening to the android.intent.action.BOOT_COMPLETED action. This receiver was, among other things, restarting the service on start up when the app had not been properly shut down.
Thank you CommonsWare for your help.
Update
After preventing the BroadcastReceiver from listening to the BOOT_COMPLETE action, I still experience the same behavior.
The reason is that this BroadcastReceiver is also listening to connectivity changes to restart the SIP service when the WIFI or a data connection becomes active, only when the app is running. Wether the application was closed or not is stored in the app preferences, but this value was not properly set when the phone was shut down while the app was running.
That is why the service was still unwantedly starting on boot: because the BroadcastReceiver detected an android.net.conn.CONNECTIVITY_CHANGE at start up and the preference telling wether the app was still running or had been quit was not properly updated.

Categories

Resources