繁体   English   中英

Android 3.1 USB主机 - BroadcastReceiver不接收USB_DEVICE_ATTACHED

[英]Android 3.1 USB-Host - BroadcastReceiver does not receive USB_DEVICE_ATTACHED

在developer.android.com上完成了USB主机的描述和示例,以检测连接和分离的USB设备。

如果我在清单文件中使用intent-filter在连接设备时启动我的应用程序,它可以正常工作:插入,检测到设备,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>

和接收器:

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
}

我不明白为什么相同的intent-filter工作,如果我在一个活动上使用它们,但如果它们应用于接收器则不行? 即使我在代码中设置了接收器和过滤器,也无法识别附件。

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

设备:Acer Iconia Tab A500

Android:3.1

提前致谢

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

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

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

即使您的应用程序正在运行并且在前台,当您插入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。 我想让设备进入睡眠状态,唤醒它会做同样的事情。

所以从我发现的,你无法直接得到意图,但看起来你可以依赖于插入USB设备时调用onResume(),因此解决方案是检查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里面有这个:

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

这包含在清单中的activity标记内:

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

无论如何,我希望这有助于某人! 我很惊讶我无法找到解决方案!

接下来来自@ Gusdor的深刻见解(+1):我在onNewIntent()中实现了一个检查,正如@Gusdor指出的那样,当你的activity launchMode被设置为singleTasksingleTop时会被调用。 然后,不是像接受的答案所暗示的那样检查布尔标志,而是使用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
}

您可以发送另一个系统广播而不是本地广播,但我不认为您将能够使用操作UsbManager.ACTION_USB_ACCESSORY_ATTACHED (系统会将其视为潜在的安全风险),因此您必须定义自己的行动。 没什么大不了的,但为什么要这么麻烦,特别是因为本地广播没有IPC开销。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM