Est-ce que quelqu'un a réussi à faire fonctionner Android.hardware.usb.action.USB_DEVICE_ATTACHED "?
Ok, j'essaie donc d'utiliser les nouvelles fonctionnalités du mode hôte USB pour détecter la connexion d'un périphérique USB. Pour mes besoins, je souhaite être averti chaque fois qu'un périphérique est connecté. Je n'ai pas pu le voir arriver. J'utilise un récepteur de diffusion qui, je le sais, fonctionne (quand je le fais écouter pour autre chose, par exemple appuyer sur le bouton d'accueil. N'importe ce que j'essaie, je n'arrive pas à obtenir l'intention de tirer. Pour simplifier les choses, j'ai décidé d'oublier mon projet et d'essayer d'utiliser le propre exemple de code de Google pour voir si je pouvais au moins le faire fonctionner. Pour feu. Non. J'ai adapté le code pour qu'il fonctionne sur d'autres périphériques. J'ai d'abord essayé de régler le filtre de périphérique xml. J'ai ajouté mon périphérique (un clavier):
<usb-device vendor-id="1050" product-id="0010" />
J'ai eu le vendeur et le produit d'une commande lsusb. Lorsque le périphérique est connecté, le logcat indique que le périphérique est trouvé
D/EventHub( 144): No input device configuration file found for device 'Yubico Yubico Yubikey II'.
I/EventHub( 144): New device: id=43, fd=219, path='/dev/input/event8', name='Yubico Yubico Yubikey II', classes=0x80000003, configuration='', keyLayout='/system/usr/keylayout/Generic.kl', keyCharacterMap='/system/usr/keychars/Generic.kcm', builtinKeyboard=false
I/InputReader( 144): Device added: id=43, name='Yubico Yubico Yubikey II', sources=0x00000101
I/ActivityManager( 144): Config changed: { scale=1.0 imsi=0/0 loc=en_US touch=3 keys=2/1/1 nav=1/2 orien=L layout=0x10000014 uiMode=0x11 seq=47}
D/MissileLauncherActivity(16191): intent: Android.intent.action.MAIN
I/EventHub( 144): Removed device: path=/dev/input/event8 name=Yubico Yubico Yubikey II id=43 fd=219 classes=0x80000003
I/InputReader( 144): Device removed: id=43, name='Yubico Yubico Yubikey II', sources=0x00000101
I/ActivityManager( 144): Config changed: { scale=1.0 imsi=0/0 loc=en_US touch=3 keys=1/1/2 nav=1/2 orien=L layout=0x10000014 uiMode=0x11 seq=48}
D/dalvikvm( 144): GC_EXPLICIT freed 78K, 26% free 14717K/19719K, paused 3ms+3ms
D/MissileLauncherActivity(16191): intent: Android.intent.action.MAIN
Le xoom trouve le clavier et il est utilisable depuis le périphérique (je peux l'utiliser dans le navigateur pour taper des lettres). Et le type d'intention se déclenche (mais il ne déclenche que Android.intent.action.MAIN). Je ne reçois jamais l'intention de DEVICE_ATTACHED. L'entrée du journal provient de l'exemple de code:
Log.d(TAG, "intent: " + intent.getAction().toString());
Dans la fonction de reprise. Après avoir approfondi et supprimé toute référence à usb, j'ai constaté que chaque application que je crée recevait le résumé appelé lorsqu'un clavier était connecté/déconnecté (d'où l'intention: entrée de journal Android.intent.action.MAIN). Pour le moment, la seule chose que je peux comprendre, c'est qu'il s'agit d'un bug dans la source Android. En passant, j'utilise un xoom wifi avec l'os 3.1.
J'ai aussi eu le même problème. J'ai finalement compris que dans le filtre de périphérique xml, nous devrions ajouter la ligne suivante.
<usb-device vendor-id-"xxxxx" product-id="yyyyy">
xxxxx et yyyyy devraient être des nombres décimaux. PAS CODES HEX. Ensuite, tout fonctionne comme annoncé! Je sais qu'il est tard, mais j'espère que cela aidera.
J'ai donc trouvé une solution à mon problème et j'ai beaucoup appris, espérons-le, pour aider quelqu'un d'autre.
Alors tout d’abord Les périphériques HID ne lancent aucune intention . Ils ne figurent pas non plus dans la liste mUsbManager.getDeviceList()
. D'autres choses cependant le font. J'ai essayé une clé USB et que savez-vous si le périphérique est répertorié dans la liste des périphériques? J'ai aussi découvert que le périphérique retourné ne possède pas de classe, sous-classe ou protocole. Le débogage a révélé que l'interface parent avait cependant la classe/sous-classe/et le protocole appropriés. Aussi si vous devez avoir un filtre de périphérique. Je me suis retrouvé avec un class=0008 (USB STORAGE)
pour travailler à mes fins. Je devine que d'autres classes fonctionneraient aussi bien.
Passons maintenant à la détermination des intentions. Il s'avère que l'intention doit être attachée à une activité de lancement. Mes tentatives pour le joindre à un service ou à un récepteur ne porteront aucun fruit. Alors, maintenant que mes intentions de feu se déclenchent, des notifications s'affichent lorsque je connecte mon appareil (clé USB). Il me demande de définir mon application comme application par défaut pour cet appareil. Parfait maintenant, mon application est exécutée à chaque fois que j'attache ce périphérique. Notez que vous serez invité pour chaque périphérique unique. Mais une seule fois. Il semble être enregistré un peu comme les programmes par défaut.
Eh bien, je pense que cela résume ce que j'ai trouvé. Dommage que vous ne puissiez pas être averti quand un clavier/souris est connecté. Oh et encore une chose. Il n’existe aucun problème avec le noyau tiamat, son exécution immédiate et aucun problème.
J'ai récemment découvert une solution à un problème similaire.
Comme quelqu'un l'a déjà noté, HID devices
ne lance pas un intention , ce qui, je pense, était votre problème.
Cependant, un problème connexe est que, si votre programme est configuré pour s'exécuter lorsqu'un périphérique USB est connecté, alors même une fois l'application exécutée, vous ne pouvez pas capturer l'action USB_DEVICE_ATTACHED
. Au lieu de cela, le système voit cette intention et dit "oh, cela signifie que cette application veut être exécutée (comme indiqué dans votre manifeste), puis vous envoie l'action Android.intent.action.MAIN au lieu de l'action USB_DEVICE_ATTACHED
. Elle appelle onResume()
. Même si votre application est en cours d'exécution. Donc, autant que je sache, vous NE POUVEZ PAS capturer l'intention USB_DEVICE_ATTACHED
si votre manifeste déclare que votre application s'exécutera lorsque des périphériques USB seront connectés. Il vous suffit de mettre du code dans onResume()
pour vérifier pour vérifier si une connexion USB est connectée Même si votre programme est en cours d'exécution, onResume sera de nouveau appelé lorsqu'un périphérique USB est connecté.
Je note ma solution plus en détail ici: Android 3.1 USB-Host - BroadcastReceiver ne reçoit pas USB_DEVICE_ATTACHED
Une autre solution consiste à utiliser
new FileObserver("/dev/input") {
@Override public void onEvent(int event, String path) {
//gets called on input device insert / remove
}
};
qui fonctionnera pour certains périphériques USB (clavier, souris)
J'ai eu le même problème. Ma solution ultime était d'utiliser la technique de vote à l'ancienne. Voici une classe assez minimale qui résout le problème à ma satisfaction.
package com.YourCompancy.YourProduct;
import Android.app.*;
import Android.content.*;
import Android.hardware.usb.*;
import Java.util.*;
import Android.util.*;
import Android.os.*;
public class UsbDeviceWatcher extends BroadcastReceiver
{
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED))
{
UsbDevice d = (UsbDevice)
intent.getExtras().get(UsbManager.EXTRA_DEVICE);
DeviceConnect(d, false);
}
}
public void DeviceConnect(UsbDevice device, boolean Attached)
{
if (Attached)
{
// Some suggestions ...
// play sound effect
// notify consumer software
// determine if interested in device
// etc
Log.i("usb", "device attached");
} else
{
Log.i("usb", "device detached");
}
}
public UsbManager manager;
public Handler handler;
public UsbDeviceWatcher(Context context, Handler handle)
{
this.handler = handle;
manager = (UsbManager)
context.getSystemService(Context.USB_SERVICE);
IntentFilter dev = new IntentFilter();
dev.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
context.registerReceiver(this, dev);
final UsbDeviceWatcher _this = this;
Thread thread = new Thread(new Runnable()
{
public void run()
{
LinkedList<UsbDevice> seen = new LinkedList<UsbDevice>();
LinkedList<UsbDevice> attached = new LinkedList<UsbDevice>();
//there is a need for multithread support here
// so the thread can watch for an exit condition
while (true)
{
HashMap<String, UsbDevice>
D = manager.getDeviceList();
for (UsbDevice d : D.values())
{
if (!seen.contains(d))
{
if (!attached.contains(d))
{
final UsbDevice dev = d;
handler.post(new Runnable(){
public void run()
{
DeviceConnect(dev, true);
}
});
}
seen.add(d);
}
}
for (UsbDevice d : seen)
{
if (!D.values().contains(d)) seen.remove(d);
}
try
{
Thread.sleep(500);
} catch (InterruptedException exception)
{
return;
}
}
}
});
thread.start();
}
}
Énumérer des dispositifs
Si votre application souhaite inspecter tous les périphériques USB actuellement connectés pendant l'exécution de votre application, elle peut énumérer les périphériques sur le bus. Utilisez la méthode getDeviceList () pour obtenir une carte de hachage de tous les périphériques USB connectés. La carte de hachage est associée au nom du périphérique USB si vous souhaitez obtenir un périphérique à partir de la carte.
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
Si vous le souhaitez, vous pouvez simplement obtenir un itérateur à partir de la carte de hachage et traiter chaque périphérique un par un:
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
while(deviceIterator.hasNext()){
UsbDevice device = deviceIterator.next()
//your code
}
OK plus de travail, plus d'échec, mais des progrès.
J'ai trouvé plus d'informations dans la documentation de SDK. il semble que vous devez avoir le filtre de périphérique pour pouvoir utiliser les intentions. J'ai donc décidé d'essayer d'utiliser un filtre de classe au lieu des identifiants fournisseur/produit. Je suppose que ce serait plus général et j'espère attraper l'appareil caché. J'ai utilisé 03h comme identifiant de classe, j'ai essayé différents formats, j'ai essayé les sous-classes, j'ai même utilisé lsusb pour découvrir, la classe, la sous-classe et le protocole de mon appareil. ceux-ci n'ont pas semblé aider du tout. alors je suis allé plus loin dans la documentation de sdk et j'ai décidé d'essayer d'énumérer tous les périphériques pour voir ce que l'OS a vu les entiers classe/sous-classe/protocole. J'ai copié le code collé dans l'écouteur de clic et ajouté des instructions log.v. rien ne s'affiche dans le logcat.
il semble que le système américain ne voit aucun périphérique (même si le périphérique fonctionne réellement.) Cela indique maintenant très clairement que le périphérique USB connecté ne se déclenche pas. maintenant je dois dire que j'utilise un noyau personnalisé dans mon xoom (tiamat). Je pensais que cela pouvait avoir quelque chose à voir avec le problème il y a quelque temps, alors je suis revenu au stock 3.1. et progresse encore maintenant. C’était maintenant il ya quelque temps, avant que j’essaie d’énumérer, je vais maintenant revenir à Agaian et continuer à travailler avec les actions jusqu’à ce que je sois sûr que le noyau n’est pas le problème. Je vais vérifier dans quand je l'ai découvert plus. succès ou échec. Bien sûr, si quelqu'un d'autre le comprend mieux que moi, merci de préciser. une dernière note Je suis très inquiet à propos de tout le mode hôte otg lorsque j'ai vu cela dans la documentation .. remarquez que le coe est identique même pensé il fait référence à deux méthodes d'énumération. probablement juste une erreur de rédaction, mais inquiétez-vous quand même à la lumière de cet échec.
Mon application est définie sur launchMode="singleTop"
et, dans ce mode, il semble que la fonction getIntent().getAction()
soit toujours égale à l'action qui a démarré l'application pour la première fois.
Donc, si vous démarrez l'application manuellement et puis branchez un appareil (même après avoir quitté l'application), vous recevrez Android.intent.action.MAIN
.
Si vous supprimez l'application, puis que vous branchez l'appareil, vous obtiendrez toujours Android.hardware.usb.action.USB_DEVICE_ATTACHED
, même lorsque vous basculez vers votre application, ou même pour faire pivoter l'appareil .
En fait, je reçois des intentions étranges lorsque je débranche le périphérique USB, ce que je ne pense pas documenté - mais bien sûr, je reçois USB_DEVICE_ATTACHED
lorsque mon périphérique est déconnecté.
Sans singleTop
, cela fonctionne normalement, mais vous obtenez une activité supplémentaire stupide si votre application est déjà ouverte et que vous branchez l'appareil.
Une fois encore, l'API d'Android est boguée, trop compliquée et difficile à utiliser.
C’est ce que j’ai fait pour détecter USB/Media Connect.
Fichier manifeste
<receiver
Android:name=".UsbReceiver"
Android:enabled="true" >
<intent-filter>
<action Android:name="Android.intent.action.MEDIA_MOUNTED"/>
<action Android:name="Android.intent.action.MEDIA_UNMOUNTED"/>
<data Android:scheme="file"/>
</intent-filter>
</receiver>
Je n'ai rien fait dans l'activité ni mon récepteur.
on dirait que cette ligne fait le truc.
<data Android:scheme="file"/>
D'après mes tests, Android can déclenche une intention lorsqu'un périphérique HID est connecté. (L’exemple d’application MissileLauncher fait exactement cela. Consultez l’exemple de code source pour plus d’informations.)
Le sous-classe et le protocole du périphérique HID du dispositif de lancement de missiles (Dream Cheeky USB Missle Launcher) sont définis sur 0x00. Pour plus d'informations, voir: http://www.mattcutts.com/blog/playing-with-a-usb-missile-launcher/
La mise en garde est que Android ne jette pas une intention pour les dispositifs de souris et de clavier spécifiquement (peut-être plus). Je peux toutefois détecter les périphériques HID dont l'interfaceClass = 0x03, InterfaceSubClass = 0x00, InterfaceProtocol = 0x00. Pour mon application, mon périphérique HID est un contrôleur intégré, la configuration de la sous-classe et du protocole n’est donc pas un problème.
Connecter le clavier USBSANSfire USB_DEVICE_ATTACHED .
Au lieu de cela, le système déclenche Intent.ACTION_CONFIGURATION_CHANGED . Cependant, en cas de changement de configuration, le système relancera l'activité. Vous n'accepterez pas l'action avec l'activité redémarrée. Dans ce cas, vous devez ajouter Android: configChanges = "keyboard | keyboardHidden" dans votre manifeste Android afin que l'activité ne soit pas redémarrée une fois qu'un clavier externe est connecté.