Java Android 3.1 USB主机-BroadcastReceiver未接收连接的USB_设备

Java Android 3.1 USB主机-BroadcastReceiver未接收连接的USB_设备,java,android,usb,Java,Android,Usb,我努力检测连接和分离的USB设备 如果我在附加设备时在清单文件中使用意图过滤器来启动我的应用程序,它工作得非常好:插件,检测到设备,android请求启动应用程序的权限,设备信息显示在表中 我正在开发的应用程序不应仅在连接/分离设备时启动/完成(例如,出于数据管理目的)。此外,如果应用程序已经在运行,我不希望弹出“打开”对话框。因此,我决定如果设备已连接,则不直接启动该活动,而是注册一个BroadcastReceiver,该接收器(稍后)应在设备处于-/分离状态时通知该活动。此接收器可以识别分离

我努力检测连接和分离的USB设备

如果我在附加设备时在清单文件中使用意图过滤器来启动我的应用程序,它工作得非常好:插件,检测到设备,android请求启动应用程序的权限,设备信息显示在表中

我正在开发的应用程序不应仅在连接/分离设备时启动/完成(例如,出于数据管理目的)。此外,如果应用程序已经在运行,我不希望弹出“打开”对话框。因此,我决定如果设备已连接,则不直接启动该活动,而是注册一个BroadcastReceiver,该接收器(稍后)应在设备处于-/分离状态时通知该活动。此接收器可以识别分离操作,但不能识别附加操作

我是否缺少权限或数据属性或类似的内容?本教程和示例没有说明任何其他必要属性

以下是清单文件:

<?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>
我不明白,如果我在活动中使用相同的意图过滤器,但如果它们应用于接收者,为什么它们不起作用?即使我在代码中设置接收器和过滤器,也无法识别附件

我的工作环境: IDE:Eclipse3.7和Android插件

设备:Acer Iconia Tab A500

安卓:3.1


提前感谢

在应用程序中创建广播接收器,而不是清单,使应用程序在运行时只能处理分离的事件。这样,分离的事件只发送到当前正在运行的应用程序,而不会广播到所有应用程序。

Aha!我想出来了。我也有同样的问题

要点是——如果你让你的应用程序在设备插入时自动启动(使用清单文件),那么Android系统似乎获得了动作\u USB\u设备\u附加的意图,然后因为它知道你的应用程序想要在这种情况下运行,它实际上向您的应用程序发送android.intent.action.MAIN intent。它从不将动作\u USB\u设备\u附加动作发送到您的应用程序,因为它认为它已经知道您的应用程序在这种情况下想要做什么

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

即使您的应用程序正在运行且处于前台,当您插入USB设备并且Android系统获得操作\u USB\u设备\u附加意图时,它也会在您的活动中调用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
    } 
}
因为intent将作为android.intent.action.MAIN返回,而不是action\u USB\u DEVICE\u ATTACHED

令人烦恼的是,如果你只是离开应用程序,但不拔下USB,你也会得到android.intent.action.MAIN。我想,让设备进入睡眠状态,然后将其唤醒也会有同样的效果

因此,从我发现的情况来看,您无法直接了解目的,但似乎您可以依赖于在插入USB设备时调用onResume(),因此解决方案是每次收到onResume时检查USB是否已连接。您还可以在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;             
        }
    }
};
<?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>
@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
    } 
}
    <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>
您将在onCreate中看到以下内容:

  // 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" />
我没有具体的代码来检查USB是否连接,因为我实际上还没有深入研究。我正在使用一个库,如果可以的话,它会连接,所以对于我的应用程序,我可以启动这个循环,我很好

将清单中活动的launchmode设置为“singleTask”可能也很重要,以防止它在已经运行时再次运行,否则插入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;             
        }
    }
};
<?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>
@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
    } 
}
    <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>


不管怎样,我希望这对别人有帮助!我很惊讶,我已经找不到解决这个问题的办法了

继续@Gusdor的深刻评论(+1):我实现了一个签入
onNewIntent()
,正如@Gusdor指出的,当您的活动
launchMode
设置为
singleTask
singleTop
时,将调用该签入。然后,不必像接受的答案所建议的那样检查布尔标志,只需使用
LocalBroadcastManager
将意图传递给USB广播接收器即可。比如说,

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(intent.getAction())) {
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }
}
然后,无论您在何处注册现有(系统)USB广播接收器,只需向本地广播管理器实例注册同一接收器,即

@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
}

您可以发送另一个系统广播,而不是本地广播,但我认为您无法使用action
UsbManager.action\u USB\u附件(系统会将其视为潜在的安全风险),因此您必须定义自己的操作。没什么大不了的,但为什么要麻烦呢,尤其是本地广播没有IPC开销。

尝试覆盖onNewIntent()-当您使用android:launchMode=“singleTop”时会调用它,可能会很好地解决您的问题。onResume()总是在之后调用。你能解释一下你的第一段“它的要点是什么”吗?我看起来很困惑。谢谢,我一直在想同样的事情。很高兴知道这件事根本不管用。闻起来像是Android bug。在你的活动的onCreate和onResume中,如果你注册了附加的
USB_设备_
intent,你可以检查它的意图,看看它是否将该设备作为可配置的额外设备:
UsbDevice DEVICE=(UsbDevice)intent.getParcelableExtra(UsbManager.extra_DEVICE);如果(设备!=null){Log.d(T