Android 3.1 USB-Host – BroadcastReceiver no recibe USB_DEVICE_ATTACHED

He trabajado a través de la descripción y las muestras de host USB en developer.android.com para detectar dispositivos USB conectados y separados.

Si utilizo un filtro de intenciones en el archivo de manifiesto para iniciar mi aplicación cuando se conecta un dispositivo, funciona perfectamente: se conecta, se detecta el dispositivo, android pide permiso para iniciar la aplicación, la información del dispositivo se muestra en una tabla.

La aplicación que estoy desarrollando no debe ser iniciada / finalizada sólo si un dispositivo está conectado / separado (por ejemplo, para la administración de datos). También no quiero que el diálogo abierto aparezca si la aplicación ya se está ejecutando. Así que decidí no iniciar la actividad directamente si un dispositivo está conectado, pero para registrar un BroadcastReceiver, que se supone (más tarde) para notificar la actividad si un dispositivo está en / desvinculado. Este receptor reconoce la acción de separación muy bien, pero no la acción de acoplamiento.

¿Me falta un permiso o atributo de datos o algo así? El tutorial y las muestras no dicen nada acerca de los atributos adicionales necesarios.

Aquí está el archivo de manifiesto:

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

Y el receptor:

 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 } 

No entiendo por qué funciona el mismo filtro de intención, si los uso en una actividad, pero no si se aplican a un receptor? Incluso si configuro el receptor y el filtro en código, no se reconocen los conectores.

Mi entorno de trabajo: IDE: Eclipse 3.7 con complemento de Android

Dispositivo: Acer Iconia Tab A500

Android: 3.1

Gracias por adelantado

¡Ah! Me lo imaginé. Yo estaba teniendo el mismo problema.

La esencia de ello es: si su aplicación se inicia automáticamente cuando se conecta un dispositivo (utilizando el archivo de manifiesto), entonces parece que el sistema Android obtiene la intención ACTION_USB_DEVICE_ATTACHED y, a continuación, ya que sabe que su aplicación desea ejecutarse en esa situación , En realidad envía a su aplicación la intención de android.intent.action.MAIN. Nunca envía la acción ACTION_USB_DEVICE_ATTACHED a su aplicación porque piensa que ya sabe lo que su aplicación quiere hacer en esa situación.

Acabo de identificar el problema, y ​​creo que tengo una solución, pero puedo decirte lo que he encontrado:

Incluso si su aplicación se está ejecutando y en primer plano, al conectar el dispositivo USB y el sistema Android recibe la intención ACTION_USB_DEVICE_ATTACHED, llamará aResume () en su actividad.

Desafortunadamente, no puedes hacer esto:

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

Porque la intención volverá como android.intent.action.MAIN, NOT ACTION_USB_DEVICE_ATTACHED.

Un molesto, también obtiene android.intent.action.MAIN si acaba de salir de la aplicación, pero no desenchufe USB. Me imagino poner el dispositivo para dormir y despertarlo de nuevo hará lo mismo.

Así que por lo que he encontrado, no se puede obtener la intención directamente, pero parece que se puede confiar en onResume () se llama cuando un dispositivo USB está conectado, por lo que la solución es sólo para comprobar si USB es Conectado cada vez que obtiene un onResume. También puede establecer una bandera cuando USB se desconecta, porque por supuesto la intención de desconexión USB dispara muy bien.

Por lo tanto, en total, su receptor de difusión podría verse así:

 // 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; } } }; 

Usted tendría esto dentro de onCreate:

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

Esto va dentro de la etiqueta de actividad en su manifiesto:

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

Tendrás un archivo device_filter.xml en la carpeta / res / xml / que tiene este aspecto:

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

(Por supuesto, con cualquier ID de proveedor e ID de producto que necesite)

Y entonces su onCreate se parece a esto:

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

No tengo un código específico para comprobar si el USB está conectado ya que en realidad no he investigado en eso todavía. Estoy usando una biblioteca que sólo se conectará si puede, por lo que para mi aplicación sólo puedo iniciar ese ciclo y estoy bien.

Su también probablemente importante para establecer el launchmode de su actividad en el manifiesto a "singleTask" para evitar que se ejecute de nuevo cuando su ya está ejecutando, o bien conectar un dispositivo USB acaba de lanzar una segunda instancia de su aplicación!

Así que mi etiqueta de actividad completa en mi manifiesto se ve así:

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

De todos modos, espero que esto ayude a alguien! Me sorprendió que no era capaz de encontrar una solución para esto ya!

Sólo para seguir el comentario perspicaz de @ Gusdor (+1): implementé un check in onNewIntent() que, como @Gusdor señala, se llama cuando el launchMode su actividad se establece como singleTask o singleTop . Entonces, en lugar de buscar banderas booleanas como sugiere la respuesta aceptada, simplemente pase la intención a su receptor de difusión USB usando un LocalBroadcastManager . Por ejemplo,

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

Entonces, dondequiera que esté registrando su receptor de radiodifusión USB (sistema) existente, sólo registre el mismo receptor con una instancia de administrador de difusión local, es decir,

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

Usted podría enviar otro sistema de difusión en lugar de una emisión local, pero no creo que usted será capaz de utilizar la acción UsbManager.ACTION_USB_ACCESSORY_ATTACHED (sistema vería que como riesgo potencial de seguridad), por lo que tendría que definir su propia acción. No es gran cosa, pero ¿por qué molestarse, sobre todo porque no hay IPC overhead con emisiones locales.

La creación del receptor de difusión en la aplicación, y no en el manifiesto, permite que su aplicación solo administre eventos separados mientras se está ejecutando. De esta forma, los eventos separados solo se envían a la aplicación que se está ejecutando actualmente y no se emite a todas las aplicaciones.

  • Android adb inalámbrica depuración con accesorio USB
  • Aparato de almacenamiento masivo USB Android
  • Uso de la API de host USB de Android para leer mi controlador de juego USB u otros datos de dispositivo USB
  • NullPointerException de UsbManager
  • Mi Macbook Pro no detectará mi samsung galaxy s6
  • ¿Cómo comunicarse con un dispositivo USB?
  • Anfitrión USB Android y dispositivos ocultos
  • Modo de Android Host Depuración USB
  • USB Host Mode - Permiso de acceso al dispositivo concedido pero no recordado
  • Problema de conexión USB AOA
  • Opción de depuración USB en gris
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.