Android 3.1 USB主机 – BroadcastReceiver不会收到USB_DEVICE_ATTACHED

我通过在developer.android.com上的USB主机的描述和示例来检测连接和分离的USB设备。

如果我在清单文件中使用意图filter来启动我的应用程序,当一个设备连接时,它工作得很好:插入,检测到设备,android要求启动应用程序的权限,设备信息显示在表中。

我正在开发的应用程序只有在设备连接/分离(例如数据pipe理目的)的情况下才能启动/完成。 另外,如果应用程序已经运行,我不希望打开对话框popup。 所以我决定不要直接开始活动,如果一个设备连接,而是注册一个BroadcastReceiver,这是(稍后)应该通知活动,如果一个设备处于/分离。 这个接收器可以很好的识别分离动作,但不能识别附加动作。

我是否缺less权限或数据属性或类似的东西? 本教程和示例没有提到其他必要的属性。

这是清单文件:

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="de.visira.smartfdr" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="12" /> <uses-feature android:name="android.hardware.usb.host" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <receiver android:name=".usb.Detector"> <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" /> </receiver> </application> 

和接收器:

 public class FDRDetector extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Toast.makeText(context, "Action: " + action, 3).show(); // pops up only if action == DETACHED } 

我不明白为什么同样的意图filter工作,如果我使用他们的活动,但不是如果他们被应用到接收器? 即使我设置了代码接收器和filter,连接也不被识别。

我的工作环境:IDE:带有Android插件的Eclipse 3.7

设备:macros碁Iconia标签A500

Android:3.1

提前致谢

Solutions Collecting From Web of "Android 3.1 USB主机 – BroadcastReceiver不会收到USB_DEVICE_ATTACHED"

啊哈! 我想到了。 我有完全相同的问题。

它的要点是 – 如果您的应用程序在插入设备(使用清单文件)时自动启动,那么看起来Android 系统获得了ACTION_USB_DEVICE_ATTACHED意图,然后它知道您的应用程序想要在这种情况下运行,它实际上发送你的应用程序的android.intent.action.MAIN意图。 它永远不会将ACTION_USB_DEVICE_ATTACHED动作发送给你的应用程序,因为它认为它已经知道你的应用程序在这种情况下想要做什么。

我刚刚发现了这个问题,我想我有一个解决scheme,但我可以告诉你我发现了什么:

即使您的应用程序正在运行,并在前台,当您插入USB设备,Android系统获取ACTION_USB_DEVICE_ATTACHED意图时,它将在您的活动中调用onResume()。

不幸的是,你不能这样做:

 @Override public void onResume() { super.onResume(); Intent intent = getIntent(); Log.d(TAG, "intent: " + intent); String action = intent.getAction(); if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) { //do something } } 

因为意图会回来作为android.intent.action.MAIN,而不是ACTION_USB_DEVICE_ATTACHED。

令人讨厌的是,如果你只是离开了应用程序,你也可以得到android.intent.action.MAIN,但是不要拔掉USB。 我想,把设备睡觉,唤醒它会做同样的事情。

所以从我发现的东西,你不能直接得到意图,但它似乎确实可以依靠onresume()被称为USB设备插入时,所以解决scheme是检查是否是USB每次你得到一个onResume连接。 当USB断开连接时,您也可以设置一个标志,因为USB断开连接意图当然会触发。

所以总的来说,你的广播接收机可能是这样的:

 // BroadcastReceiver when remove the device USB plug from a USB port BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { usbConnected=false; } } }; 

你可以在onCreate里面find这个:

  // listen for new devices IntentFilter filter = new IntentFilter(); filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); registerReceiver(mUsbReceiver, filter); 

这在清单中的活动标签内:

  <intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" /> 

您的/ res / xml /文件夹中将有一个device_filter.xml文件,如下所示:

 <?xml version="1.0" encoding="utf-8"?> <resources> <usb-device vendor-id="1027" product-id="24577" /> <usb-device vendor-id="1118" product-id="688" /> </resources> 

(当然,无论你需要什么厂商ID和产品ID)

然后你的onCreate看起来像这样:

 @Override public void onResume() { super.onResume(); Intent intent = getIntent(); Log.d(TAG, "intent: " + intent); String action = intent.getAction(); if (usbConnected==false ) { //check to see if USB is now connected } } 

我没有检查USB连接的具体代码,因为我还没有深究。 我正在使用一个库,只要可以连接,所以对于我的应用程序,我可以开始这个循环,我很好。

将清单中的活动的启动模式设置为“singleTask”以防止它在已经运行时再次运行,或者插入USB设备将启动应用程序的第二个实例也很重要。

所以我的整个活动标签在我的清单看起来像这样:

  <activity android:label="@string/app_name" android:name="com.awitness.common.TorqueTablet" android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen" android:screenOrientation="landscape" android:configChanges="orientation|keyboardHidden" android:launchMode="singleTask" > <intent-filter > <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.HOME"/> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" /> </activity> 

无论如何,我希望这可以帮助别人! 我很惊讶,我无法find一个解决scheme已经!

(@ +1):我在onNewIntent()中实现了一个检查,就像@Gusdor指出的那样,当你的activity launchMode被设置为singleTask或者singleTop时候,会被调用。 然后,不要像接受的答案那样检查布尔标志,只需使用LocalBroadcastManager将意图传递给USB广播接收器LocalBroadcastManager 。 例如,

 @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(intent.getAction())) { LocalBroadcastManager.getInstance(this).sendBroadcast(intent); } } 

然后,无论您在哪里注册现有的(系统)USB广播接收机,只需向本地广播pipe理器实例注册相同的接收机,

 @Override protected void onResume() { super.onResume(); myContext.registerReceiver(myUsbBroadcastReceiver, myIntent); // system receiver LocalBroadcastManager.getInstance(myContext).registerReceiver(myUsbBroadcastReceiver, intent); // local receiver } @Override protected void onPause() { super.onResume(); myContext.unregisterReceiver(myUsbBroadcastReceiver); // system receiver LocalBroadcastManager.getInstance(myContext).unregisterReceiver(myUsbBroadcastReceiver); // local receiver } 

你可以发送另一个系统广播,而不是本地广播,但我不认为你可以使用动作UsbManager.ACTION_USB_ACCESSORY_ATTACHED (系统会看到潜在的安全风险),所以你必须定义自己的行动。 没什么大不了的,但是为什么呢,特别是因为没有IPC本地广播的开销。

在应用程序中创build广播接收器,而不是清单,允许您的应用程序只处理正在运行的分离事件。 这样,分离的事件只被发送到当前正在运行的应用程序,而不是广播给所有的应用程序。