Reputation: 910
I've got an Android app that needs to detect when a USB peripheral is attached or detached. It works fine when the peripheral is first attached, but I don't receive any notification (i.e., I don't receive an Intent
whose action is ACTION_USB_DEVICE_DETACHED
) when it is subsequently detached.
Here's the relevant part of my AndroidManifest.xml
:
<activity android:name=".LauncherActivity">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" />
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" android:resource="@xml/device_filter" />
</activity>
It may also be worth noting that LauncherActivity
only exists to start a Service
when the device is attached, and to stop the service when it is detached. In either case, LauncherActivity
always finish
es itself immediately. All of this occurs in LauncherActivity.onCreate
.
Any ideas?
Upvotes: 16
Views: 30155
Reputation: 11
The fix that worked for me was to unregister in onPause()
and register again in onResume()
:
@Override
public void onPause()
{
super.onPause();
stopIOManager();
if(m_UsbReceiver!=null) unregisterReceiver(m_UsbReceiver);
}
@Override
public void onResume()
{
super.onResume();
startIOManager();
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(m_UsbReceiver, filter);
}
However, although the app seems to always receive the DETACH event, once in a while it doesn't get the ATTACHED event. I then need to plug and and unplug the USB connector, and it usually works after one or two attempts. I've put the blame of this strange behaviour on the OS, without certainty.
Upvotes: 1
Reputation: 11
For what it's worth, I had this same issue because the activity is paused then resumed when the device is disconnected.
Since the receiver is unregistered in the OnPause()
method just prior to receiving the ACTION_USB_DEVICE_DETACHED
, your app never gets notified.
Upvotes: 0
Reputation: 259
Try with USB_STATE as below.
It will fire both attached and detatched to same receiver and in receiver you can identify whether is was attached or detatched event.
IntentFilter filter = new IntentFilter();
filter.addAction("android.hardware.usb.action.USB_STATE");
Receiver:
public class USBReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if (intent.getExtras().getBoolean("connected")) {
//do your stuff
}
}
}
Upvotes: 11
Reputation: 247
USB_DEVICE_DETACHED is a broadcast intent, thus you may want to declare the BroadcastReceiver in manifest with the appropriate intent-filter for detached action, also with meta-data attached. Same goes for USB_ACCESSORY_DETACHED, for who is interested.
Summary:
USB_XXX_ATTACHED is an activity intent
USB_XXX_DETACHED is a broadcast intent
(where XXX = DEVICE | ACCESSORY)
See: http://developer.android.com/guide/components/intents-filters.html
"There is no overlap within these messaging systems: Broadcast intents are delivered only to broadcast receivers, never to activities or services"
Upvotes: 19
Reputation: 910
So, I never got the ACTION_USB_DEVICE_DETACHED
Intent
to go to LauncherActivity
; I don't know what the deal is there, probably something I don't properly understand about intent filters or the Activity
lifecycle callbacks.
The solution I ended up using comes from the post linked by Pratik. I basically took everything about USB_DEVICE_DETACHED
out of AndroidManifest.xml
. Then, in the onCreate
method of the Service
, I registered a BroadcastReceiver
like this:
@Override
public void onCreate() {
detachReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED))
stopSelf();
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(detachReceiver, filter);
}
A little clunky, and I'm still curious why just adding USB_DEVICE_DETACHED
to the <intent-filter>
of LauncherActivity
wasn't working, but it does what I need.
Upvotes: 9