Lorsque votre appareil Android est en mode hôte USB, il agit en tant qu'hôte USB, alimente le bus, et énumère les périphériques USB connectés. Le mode hôte USB est compatible avec Android 3.1 ou version ultérieure.
Présentation de l'API
Avant de commencer, il est important de comprendre les cours avec lesquels vous devez travailler. La
Le tableau suivant décrit les API hôtes USB du package android.hardware.usb
.
Classe | Description |
---|---|
UsbManager |
Permet d'énumérer les appareils USB connectés et de communiquer avec eux. |
UsbDevice |
Représente un périphérique USB connecté et contient des méthodes pour accéder à son identifiant d'informations, d'interfaces et de points de terminaison. |
UsbInterface |
Représente l'interface d'un périphérique USB, qui définit un ensemble de fonctionnalités pour appareil. Un appareil peut avoir une ou plusieurs interfaces sur lesquelles communiquer. |
UsbEndpoint |
Représente un point de terminaison d'interface, qui est un canal de communication pour cette interface. Une interface peut avoir un ou plusieurs points de terminaison, et a généralement des points de terminaison d'entrée et de sortie pour communication bidirectionnelle avec l’appareil. |
UsbDeviceConnection |
Représente une connexion à l'appareil, qui transfère des données sur les points de terminaison. Ce cours vous permet d'échanger des données de manière synchrone ou asynchrone. |
UsbRequest |
Représente une requête asynchrone pour communiquer avec un appareil via un UsbDeviceConnection . |
UsbConstants |
Définit les constantes USB correspondant aux définitions dans linux/usb/ch9.h du système Linux noyau. |
Dans la plupart des cas, vous devez utiliser toutes ces classes (UsbRequest
n'est requis que si vous effectuez une communication asynchrone).
lors de la communication
avec un périphérique USB. En général, vous obtenez un UsbManager
pour récupérer le UsbDevice
souhaité.
Une fois que vous avez l'appareil, vous devez trouver le UsbInterface
et le UsbEndpoint
appropriés.
d’interface sur laquelle
communiquer. Une fois que vous avez obtenu le bon point de terminaison, ouvrez un UsbDeviceConnection
pour communiquer avec le périphérique USB.
Exigences concernant les fichiers manifestes Android
La liste suivante décrit ce que vous devez ajouter au fichier manifeste de votre application avant travailler avec les API hôtes USB:
- Étant donné que les appareils Android n'acceptent pas tous les API hôtes USB,
incluent un élément
<uses-feature>
qui déclare que votre application utilise la fonctionnalitéandroid.hardware.usb.host
. - Définissez le SDK minimal de l'application sur le niveau d'API 12 ou supérieur. Les API hôtes USB ne sont pas présentes aux niveaux d'API précédents.
- Si vous souhaitez que votre application soit informée lorsqu'un périphérique USB est connecté, spécifiez un
Paire d'éléments
<intent-filter>
et<meta-data>
pour Intentandroid.hardware.usb.action.USB_DEVICE_ATTACHED
dans votre activité principale. La L'élément<meta-data>
pointe vers un fichier de ressources XML externe qui déclare des informations d'identification sur l'appareil que vous souhaitez détecter.Dans le fichier de ressources XML, déclarez les éléments
<usb-device>
pour l'USB appareils que vous souhaitez filtrer. La liste suivante décrit les attributs de<usb-device>
En général, utilisez le fournisseur et l'ID produit si vous souhaitez filtrer pour un appareil spécifique, et utilisez la classe, la sous-classe et le protocole si vous souhaitez filtrer les données en fonction d'un groupe. de périphériques USB, tels que les périphériques de stockage de masse ou les appareils photo numériques. Vous pouvez spécifier "aucun" ou tous ces attributs. Si aucun attribut ne correspond à chaque périphérique USB, si votre application l'exige:vendor-id
product-id
class
subclass
protocol
(appareil ou interface)
Enregistrez le fichier de ressources dans le répertoire
res/xml/
. Nom du fichier de ressources (sans l'extension .xml) doit être identique à celui spécifié dans le fichier Élément<meta-data>
. Le fichier de ressources XML est au format exemple ci-dessous.
Exemples de fichiers manifestes et de ressources
Voici un exemple de fichier manifeste et le fichier de ressources correspondant:
<manifest ...> <uses-feature android:name="android.hardware.usb.host" /> <uses-sdk android:minSdkVersion="12" /> ... <application> <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" /> </activity> </application> </manifest>
Dans ce cas, le fichier de ressources suivant doit être enregistré dans
res/xml/device_filter.xml
, et indique que tout périphérique USB doté du paramètre
attributs doivent être filtrés:
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" /> </resources>
Travailler avec des appareils
Lorsque les utilisateurs connectent un périphérique USB à un appareil Android, le système Android peut déterminer si votre application est intéressée par l'appareil connecté. Si c'est le cas, vous pouvez configurer la communication avec l’appareil si vous le souhaitez. Pour ce faire, votre application doit:
- Découvrez les appareils USB connectés à l'aide d'un filtre d'intent pour être averti lorsque l'utilisateur connecte un périphérique USB ou en énumérant les périphériques USB qui sont déjà connectés.
- Si ce n'est pas déjà fait, demandez à l'utilisateur l'autorisation de se connecter au périphérique USB.
- Communiquer avec le périphérique USB en lisant et en écrivant des données sur l'interface appropriée les points de terminaison.
Découvrir un appareil
Votre application peut détecter les périphériques USB en utilisant un filtre d'intent pour être averti lorsque l'utilisateur connecte un périphérique ou en énumérant les périphériques USB qui sont déjà connectés. À l'aide d'un Le filtre d'intent est utile si vous voulez que votre application détecte automatiquement l'appareil souhaité. L'énumération des périphériques USB connectés est utile si vous souhaitez obtenir une liste de tous les appareils connectés ou si votre application n'a filtré aucun intent.
Utiliser un filtre d'intent
Pour que votre application détecte un périphérique USB particulier, vous pouvez spécifier un filtre d'intent pour
filtre pour l'intent android.hardware.usb.action.USB_DEVICE_ATTACHED
. ainsi que
ce filtre d'intent, vous devez spécifier un fichier de ressources spécifiant les propriétés de la clé USB
(par exemple, l'ID du produit et l'ID du fournisseur). Lorsque les utilisateurs connectent un appareil qui correspond à votre appareil
le filtre affiche une boîte de dialogue qui leur demande s'ils souhaitent lancer votre application.
Si les utilisateurs acceptent, votre application est automatiquement autorisée à accéder à l'appareil jusqu'à ce que le
l'appareil est déconnecté.
L'exemple suivant montre comment déclarer le filtre d'intent:
<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" /> </activity>
L'exemple suivant montre comment déclarer le fichier de ressources correspondant qui spécifie le Appareils USB qui vous intéressent:
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-device vendor-id="1234" product-id="5678" /> </resources>
Dans votre activité, vous pouvez obtenir le UsbDevice
qui représente
l'appareil connecté à partir de l'intent, comme ceci:
Kotlin
val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
Java
UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
Énumérer les appareils
Si votre application souhaite inspecter tous les périphériques USB actuellement connectés
pendant son exécution, l'application peut énumérer les appareils présents dans le bus. Utilisez la méthode getDeviceList()
pour obtenir une carte de hachage de tous les
les périphériques USB qui sont connectés. La table de hachage est associée au nom du périphérique USB si vous souhaitez
obtenir un appareil sur la carte.
Kotlin
val manager = getSystemService(Context.USB_SERVICE) as UsbManager ... val deviceList = manager.getDeviceList() val device = deviceList.get("deviceName")
Java
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); ... HashMap<String, UsbDevice> deviceList = manager.getDeviceList(); UsbDevice device = deviceList.get("deviceName");
Si vous le souhaitez, vous pouvez également obtenir un itérateur à partir de la table de hachage et traiter chaque appareil par un:
Kotlin
val manager = getSystemService(Context.USB_SERVICE) as UsbManager .. val deviceList: HashMap<String, UsbDevice> = manager.deviceList deviceList.values.forEach { device -> // your code }
Java
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 }
Obtenir l'autorisation de communiquer avec un appareil
Pour pouvoir communiquer avec le périphérique USB, votre application doit avoir l'autorisation de votre utilisateurs.
Remarque:Si votre application utilise un d'intent pour détecter les périphériques USB lorsqu'ils sont connectés, il reçoit automatiquement si l'utilisateur autorise votre application à gérer l'intent. Sinon, vous devez demander explicitement dans votre application avant de vous connecter à l'appareil.
Il peut être nécessaire de demander explicitement l'autorisation dans certaines situations, par exemple lorsque votre énumère les périphériques USB qui sont déjà connectés et qui souhaitent communiquer avec 1. Vous devez vérifier si vous êtes autorisé à accéder à un appareil avant d'essayer de communiquer avec lui. Si non, vous recevrez une erreur d'exécution si l'utilisateur a refusé l'autorisation d'accéder à l'appareil.
Pour obtenir explicitement l'autorisation, commencez par créer un broadcast receiver. Ce récepteur écoute
L'intent qui est diffusé lorsque vous appelez requestPermission()
. L'appel de requestPermission()
affiche une boîte de dialogue pour
utilisateur demandant l'autorisation
de se connecter à l'appareil. L'exemple de code suivant montre comment
créez le broadcast receiver:
Kotlin
private const val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION" private val usbReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (ACTION_USB_PERMISSION == intent.action) { synchronized(this) { val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { device?.apply { // call method to set up device communication } } else { Log.d(TAG, "permission denied for device $device") } } } } }
Java
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"; private final BroadcastReceiver usbReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (ACTION_USB_PERMISSION.equals(action)) { synchronized (this) { UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { if(device != null){ // call method to set up device communication } } else { Log.d(TAG, "permission denied for device " + device); } } } } };
Pour enregistrer le broadcast receiver, ajoutez ceci à la méthode onCreate()
de votre
activité:
Kotlin
private const val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION" ... val manager = getSystemService(Context.USB_SERVICE) as UsbManager ... permissionIntent = PendingIntent.getBroadcast(this, 0, Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE) val filter = IntentFilter(ACTION_USB_PERMISSION) registerReceiver(usbReceiver, filter)
Java
UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"; ... permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE); IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); registerReceiver(usbReceiver, filter);
Pour afficher la boîte de dialogue qui demande aux utilisateurs l'autorisation de se connecter à l'appareil, appelez la méthode requestPermission()
:
Kotlin
lateinit var device: UsbDevice ... usbManager.requestPermission(device, permissionIntent)
Java
UsbDevice device; ... usbManager.requestPermission(device, permissionIntent);
Lorsque les utilisateurs répondent à la boîte de dialogue, votre broadcast receiver reçoit l'intent qui contient le
EXTRA_PERMISSION_GRANTED
supplémentaire, qui est une valeur booléenne
représentant la réponse. Vérifiez dans cet extra la valeur "true" avant de vous connecter
appareil.
Communiquer avec un appareil
La communication avec un périphérique USB peut être synchrone ou asynchrone. Dans les deux cas, vous
doit créer un nouveau thread sur lequel effectuer toutes les transmissions de données, afin de ne pas bloquer le
thread UI. Pour configurer correctement la communication avec un appareil, vous devez obtenir les
UsbInterface
et UsbEndpoint
appareil avec lequel vous souhaitez communiquer et envoyer des requêtes sur ce point de terminaison avec un UsbDeviceConnection
. En règle générale, votre code doit:
- Vérifiez les attributs d'un objet
UsbDevice
, tels que l'ID produit, l'ID du fournisseur ou la classe d'appareil pour déterminer si vous souhaitez ou non communiquer appareil. - Lorsque vous êtes certain de vouloir communiquer avec l'appareil, recherchez les
UsbInterface
que vous souhaitez utiliser pour communiquer avec le lesUsbEndpoint
appropriées de cette interface. Les interfaces peuvent avoir un ou plus, et possède généralement un point de terminaison d'entrée et de sortie pour une liaison bidirectionnelle de la communication. - Une fois que vous avez trouvé le point de terminaison approprié, ouvrez un
UsbDeviceConnection
sur ce point de terminaison. - Fournissez les données que vous souhaitez transmettre sur le point de terminaison à l'aide de la méthode
bulkTransfer()
oucontrolTransfer()
. Vous devez effectuez cette étape dans un autre thread pour éviter de bloquer le thread UI principal. Pour plus sur l'utilisation des threads dans Android, consultez la section Processus et Threads :
L'extrait de code suivant constitue un moyen simple d'effectuer un transfert de données synchrone. Votre code devrait avoir plus de logique pour trouver correctement l'interface et les points de terminaison appropriés pour communiquer Vous devez également transférer les données dans un autre thread que le thread UI principal:
Kotlin
private lateinit var bytes: ByteArray private val TIMEOUT = 0 private val forceClaim = true ... device?.getInterface(0)?.also { intf -> intf.getEndpoint(0)?.also { endpoint -> usbManager.openDevice(device)?.apply { claimInterface(intf, forceClaim) bulkTransfer(endpoint, bytes, bytes.size, TIMEOUT) //do in another thread } } }
Java
private Byte[] bytes; private static int TIMEOUT = 0; private boolean forceClaim = true; ... UsbInterface intf = device.getInterface(0); UsbEndpoint endpoint = intf.getEndpoint(0); UsbDeviceConnection connection = usbManager.openDevice(device); connection.claimInterface(intf, forceClaim); connection.bulkTransfer(endpoint, bytes, bytes.length, TIMEOUT); //do in another thread
Pour envoyer des données de manière asynchrone, utilisez la classe UsbRequest
pour initialize
et queue
une requête asynchrone, puis attendez le résultat.
avec requestWait()
.
Interruption de la communication avec un appareil
Lorsque vous avez terminé de communiquer avec un appareil ou si celui-ci a été déconnecté, fermez UsbInterface
et UsbDeviceConnection
en
appeler releaseInterface()
et
close()
Pour écouter les événements détachés,
créez un broadcast receiver comme ci-dessous:
Kotlin
var usbReceiver: BroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (UsbManager.ACTION_USB_DEVICE_DETACHED == intent.action) { val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) device?.apply { // call your method that cleans up and closes communication with the device } } } }
Java
BroadcastReceiver usbReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (device != null) { // call your method that cleans up and closes communication with the device } } } };
La création du broadcast receiver dans l'application, et non du fichier manifeste, permet à une application pour ne gérer que les événements détachés pendant son exécution. De cette façon, les événements détachés envoyé uniquement à l'application en cours d'exécution et non diffusé à toutes les applications.