O modo de acessório USB permite que os usuários se conectem Hardware de host USB projetado especificamente para dispositivos com tecnologia Android. Os acessórios devem aderir ao protocolo de acessório Android descrito na documentação do Kit de desenvolvimento de acessórios Android. Isso permite que dispositivos com tecnologia Android que não podem atuar como host USB ainda interajam com USB ao hardware. Quando um dispositivo com tecnologia Android está no modo de acessório USB, o dispositivo USB Android conectado atua como host, fornece energia para o barramento USB e enumera os dispositivos conectados. O Android 3.1 (API de nível 12) é compatível com o modo de acessório USB, e o recurso também tem backport para Android 2.3.4 (nível 10 da API) para oferecer suporte a uma variedade maior de dispositivos.
Escolha as APIs de acessório USB certas
Embora as APIs de acessório USB tenham sido introduzidas na plataforma no Android 3.1, elas também são disponíveis no Android 2.3.4 usando a biblioteca de complementos das APIs do Google. Como essas APIs foram usando uma biblioteca externa, há dois pacotes que podem ser importados para oferecer suporte a USB modo acessório. Dependendo para quais dispositivos Android você quer oferecer suporte, talvez seja necessário use uma em vez da outra:
com.android.future.usb
: para oferecer suporte ao modo de acessório USB no Android 2.3.4, a Complemento das APIs do Google inclui as APIs de acessórios USB com backport e elas estão contidas neste . O Android 3.1 também oferece suporte à importação e chamada de classes dentro desse namespace para oferecem suporte a aplicativos criados com a biblioteca de complementos. Esta biblioteca de complementos é um wrapper fino nas APIs de acessórioandroid.hardware.usb
e não oferece suporte ao modo host USB. Se Se quiser oferecer suporte à maior variedade de dispositivos com suporte ao modo de acessório USB, use o complemento e importar esse pacote. É importante observar que nem todos os dispositivos com Android 2.3.4 são necessário para oferecer suporte ao recurso de acessório USB. Cada fabricante de dispositivo decide oferecer ou não suporte para essa capacidade. É por isso que você precisa declará-la no manifesto. .android.hardware.usb
: esse namespace contém as classes com suporte a USB. modo acessório no Android 3.1. Esse pacote está incluído como parte das APIs do framework, portanto, O Android 3.1 é compatível com o modo de acessório USB sem o uso de uma biblioteca de complementos. Usar este pacote Se você só se preocupar com dispositivos Android 3.1 ou mais recentes que tenham suporte de hardware para USB modo acessório, que pode ser declarado no arquivo de manifesto.
Instalar a biblioteca de complementos das APIs do Google
Se você quiser instalar o complemento, instale as APIs do Google para Android API 10 com o SDK Manager. Consulte Como instalar as APIs do Google Complemento para mais informações sobre como instalar a biblioteca de complementos.
Visão geral da API
Como a biblioteca de complementos é um wrapper para as APIs de estrutura, as classes compatíveis com a
O recurso de acessório USB é semelhante. Você pode usar a documentação de referência do android.hardware.usb
mesmo se estiver usando a biblioteca de complementos.
Observação:no entanto, há um pequeno uso diferença entre a biblioteca de complementos e as APIs de framework que você precisa conhecer.
A tabela a seguir descreve as classes compatíveis com as APIs de acessório USB:
Classe | Descrição |
---|---|
UsbManager |
Permite que você enumere e se comunique com acessórios USB conectados. |
UsbAccessory |
Representa um acessório USB e contém métodos para acessar o elemento de identificação informações imprecisas ou inadequadas. |
Diferenças de uso entre a biblioteca de complementos e as APIs de plataforma
Há duas diferenças de uso entre a biblioteca de complementos das APIs do Google e a plataforma APIs de terceiros.
Se você estiver usando a biblioteca de complementos, precisará recuperar o objeto UsbManager
da seguinte maneira:
Kotlin
val manager = UsbManager.getInstance(this)
Java
UsbManager manager = UsbManager.getInstance(this);
Se você não estiver usando a biblioteca de complementos, precisará recuperar o objeto UsbManager
da seguinte maneira:
Kotlin
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
Java
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
Quando você filtra um acessório conectado com um filtro de intent, o objeto UsbAccessory
fica dentro da intent transmitida ao seu
para o aplicativo. Se você estiver usando a biblioteca de complementos, precisará recuperar o objeto UsbAccessory
da seguinte maneira:
Kotlin
val accessory = UsbManager.getAccessory(intent)
Java
UsbAccessory accessory = UsbManager.getAccessory(intent);
Se você não estiver usando a biblioteca de complementos, precisará recuperar o objeto UsbAccessory
da seguinte maneira:
Kotlin
val accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY) as UsbAccessory
Java
UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
Requisitos de manifesto do Android
A lista a seguir descreve o que você precisa adicionar ao arquivo de manifesto do aplicativo antes trabalhando com as APIs de acessórios USB. O arquivo de manifesto e recursos exemplos mostram como declarar esses itens:
- Como nem todos os dispositivos com tecnologia Android são compatíveis com as APIs de acessórios USB,
incluir um elemento
<uses-feature>
que declare que seu aplicativo usa o recursoandroid.hardware.usb.accessory
. - Se você estiver usando o
biblioteca de complementos,
adicione o elemento
<uses-library>
especificandocom.android.future.usb.accessory
para a biblioteca. - Defina o SDK mínimo do aplicativo como o nível 10 da API se você estiver usando a biblioteca de complementos
ou 12 se você estiver usando o pacote
android.hardware.usb
. -
Se quiser que seu aplicativo seja notificado sobre um acessório USB conectado, especifique um Par de elementos
<intent-filter>
e<meta-data>
para oandroid.hardware.usb.action.USB_ACCESSORY_ATTACHED
na sua atividade principal. O elemento<meta-data>
aponta para um arquivo de recurso XML externo que declara informações de identificação sobre o acessório que você quer detectar.No arquivo de recurso XML, declare elementos
<usb-accessory>
para o acessórios que você quer filtrar. Cada<usb-accessory>
pode ter seguintes atributos:manufacturer
model
version
A filtragem em
version
não é recomendada. Um acessório ou device nem sempre especifica uma string de versão (de maneira intencional ou não). Quando o app declara um atributo de versão para filtrar e o acessório ou dispositivo não especifica uma string de versão, isso faz com que umaNullPointerException
seja exibida com as versões anteriores do Android. Esse problema foi corrigido no Android 12.Salve o arquivo de recurso no diretório
res/xml/
. O nome do arquivo de recurso (sem a extensão .xml) deve ser igual ao especificado na<meta-data>
. O formato do arquivo de recurso XML também é mostrado em o exemplo abaixo.
Exemplos de arquivo de manifesto e recurso
O exemplo a seguir mostra um manifesto e o arquivo de recurso correspondente:
<manifest ...> <uses-feature android:name="android.hardware.usb.accessory" /> <uses-sdk android:minSdkVersion="<version>" /> ... <application> <uses-library android:name="com.android.future.usb.accessory" /> <activity ...> ... <intent-filter> <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" android:resource="@xml/accessory_filter" /> </activity> </application> </manifest>
Nesse caso, o arquivo de recurso a seguir deve ser salvo
res/xml/accessory_filter.xml
e especifica que qualquer acessório que tenha o
modelo, fabricante e versão correspondentes devem ser filtrados. O acessório envia essas
atribui o dispositivo com tecnologia Android:
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-accessory model="DemoKit" manufacturer="Google" version="1.0"/> </resources>
Trabalhar com acessórios
Quando os usuários conectam acessórios USB a um dispositivo com tecnologia Android, o sistema Android pode determine se o aplicativo está interessado no acessório conectado. Nesse caso, é possível definir a comunicação com o acessório, se desejado. Para fazer isso, seu app precisa:
- Descubra acessórios conectados usando um filtro de intent que filtra por acessórios eventos anexados ou enumerando acessórios conectados e encontrando o apropriado.
- Pedir permissão ao usuário para se comunicar com o acessório, caso ainda não tenha feito isso. obtidos.
- Comunicar-se com o acessório lendo e gravando dados na interface adequada endpoints.
Descobrir um acessório
Seu aplicativo pode descobrir acessórios usando um filtro de intent para ser notificado quando o usuário conecta um acessório ou enumera acessórios que já estão conectados. Usar um o filtro de intent é útil quando você quer que seu aplicativo detecte automaticamente o acessório desejado. Enumerar acessórios conectados é útil se você quer receber uma lista de todos os acessórios conectados ou se o aplicativo não foi filtrado por uma intent.
Usar um filtro de intent
Para que seu aplicativo descubra um acessório USB específico, é possível especificar um filtro de intent.
para filtrar a intent android.hardware.usb.action.USB_ACCESSORY_ATTACHED
. Junto
com esse filtro de intents, é preciso especificar um arquivo de recurso que especifique as propriedades do USB
acessório, como fabricante, modelo e versão.
O exemplo a seguir mostra como declarar o filtro de intent:
<activity ...> ... <intent-filter> <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" android:resource="@xml/accessory_filter" /> </activity>
O exemplo a seguir mostra como declarar o arquivo de recurso correspondente que especifica os Acessórios USB do seu interesse:
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-accessory manufacturer="Google, Inc." model="DemoKit" version="1.0" /> </resources>
Na sua atividade, você pode acessar o UsbAccessory
que representa
ao acessório anexado da intent como esta (com a biblioteca de complementos):
Kotlin
val accessory = UsbManager.getAccessory(intent)
Java
UsbAccessory accessory = UsbManager.getAccessory(intent);
ou assim (com as APIs de plataforma):
Kotlin
val accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY) as UsbAccessory
Java
UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
Enumerar acessórios
Você pode fazer com que o aplicativo enumere acessórios que se identificaram enquanto seu aplicativo está em execução.
Usar o método getAccessoryList()
para gerar uma matriz com todos os acessórios USB conectados:
Kotlin
val manager = getSystemService(Context.USB_SERVICE) as UsbManager val accessoryList: Array<out UsbAccessory> = manager.accessoryList
Java
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); UsbAccessory[] accessoryList = manager.getAccessoryList();
Observação : somente um acessório conectado é compatível com por vez.
Receber permissão para se comunicar com um acessório
Antes de se comunicar com o acessório USB, o aplicativo precisa ter permissão do usuários.
Observação: caso seu aplicativo use uma filtro de intent para descobrir acessórios conforme eles estão conectados, ele recebe automaticamente permissão se o usuário permitir que seu aplicativo manipule a intent. Caso contrário, solicite explicitamente no aplicativo antes de se conectar ao acessório.
Pedir permissão explicitamente pode ser necessário em algumas situações, como quando seu o aplicativo enumera os acessórios que já estão conectados e depois querem se comunicar com um. Você precisa verificar a permissão para acessar um acessório antes de tentar se comunicar com ele. Caso contrário, você receberá um erro de tempo de execução se o usuário negar a permissão para acessar o acessório.
Para receber permissão explicitamente, primeiro crie um broadcast receiver. Este receptor detecta
a intent que é transmitida quando você chama requestPermission()
. A chamada para requestPermission()
mostra uma caixa de diálogo para o
o usuário solicita permissão para se conectar ao acessório. O código de exemplo a seguir mostra como
crie o 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 accessory: UsbAccessory? = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY) if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { accessory?.apply { // call method to set up accessory communication } } else { Log.d(TAG, "permission denied for accessory $accessory") } } } } }
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) { UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { if(accessory != null){ // call method to set up accessory communication } } else { Log.d(TAG, "permission denied for accessory " + accessory); } } } } };
Para registrar o broadcast receiver, coloque-o no método onCreate()
no seu
atividade:
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), 0) 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), 0); IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); registerReceiver(usbReceiver, filter);
Para exibir a caixa de diálogo que solicita permissão aos usuários para se conectar ao acessório, chame o método
Método requestPermission()
:
Kotlin
lateinit var accessory: UsbAccessory ... usbManager.requestPermission(accessory, permissionIntent)
Java
UsbAccessory accessory; ... usbManager.requestPermission(accessory, permissionIntent);
Quando os usuários respondem à caixa de diálogo, seu broadcast receiver recebe a intent que contém o
EXTRA_PERMISSION_GRANTED
extra, que é um booleano
que representam a resposta. Verifique se esse extra tem um valor "true" antes de se conectar ao
acessório.
Comunicar-se com um acessório
É possível se comunicar com o acessório usando o UsbManager
para
conseguir um descritor de arquivo em que possa configurar streams de entrada e saída para ler e gravar dados
descritor. Os streams representam os endpoints em massa de entrada e saída do acessório. Você deve definir
a comunicação entre o dispositivo e o acessório em outra linha de execução, para não bloquear o
linha de execução de interface principal. O exemplo a seguir mostra como abrir um acessório para comunicação:
Kotlin
private lateinit var accessory: UsbAccessory private var fileDescriptor: ParcelFileDescriptor? = null private var inputStream: FileInputStream? = null private var outputStream: FileOutputStream? = null ... private fun openAccessory() { Log.d(TAG, "openAccessory: $mAccessory") fileDescriptor = usbManager.openAccessory(accessory) fileDescriptor?.fileDescriptor?.also { fd -> inputStream = FileInputStream(fd) outputStream = FileOutputStream(fd) val thread = Thread(null, this, "AccessoryThread") thread.start() } }
Java
UsbAccessory accessory; ParcelFileDescriptor fileDescriptor; FileInputStream inputStream; FileOutputStream outputStream; ... private void openAccessory() { Log.d(TAG, "openAccessory: " + accessory); fileDescriptor = usbManager.openAccessory(accessory); if (fileDescriptor != null) { FileDescriptor fd = fileDescriptor.getFileDescriptor(); inputStream = new FileInputStream(fd); outputStream = new FileOutputStream(fd); Thread thread = new Thread(null, this, "AccessoryThread"); thread.start(); } }
No método run()
da linha de execução, é possível ler e gravar no acessório usando
os objetos FileInputStream
ou FileOutputStream
. Durante a leitura
dados de um acessório com um objeto FileInputStream
, garanta que o buffer que
que você usa é grande o suficiente para armazenar os dados do pacote USB. O protocolo de acessório Android oferece suporte
buffers de pacote de até 16.384 bytes, ou seja, você pode optar por sempre declarar esse buffer
de tamanho para simplificar.
Observação:em um nível inferior, os pacotes são de 64 bytes para USB. acessórios de alta velocidade e 512 bytes para acessórios USB de alta velocidade. O acessório do Android agrupa os pacotes das duas velocidades em um pacote lógico para simplificar.
Para mais informações sobre o uso de linhas de execução no Android, consulte Processos e Linhas de execução.
Encerrar a comunicação com um acessório
Quando terminar de se comunicar com um acessório ou se ele tiver sido desconectado, feche o
descritor de arquivo que você abriu chamando close()
.
Para ouvir eventos independentes, crie um broadcast receiver como abaixo:
Kotlin
var usbReceiver: BroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (UsbManager.ACTION_USB_ACCESSORY_DETACHED == intent.action) { val accessory: UsbAccessory? = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY) accessory?.apply { // call your method that cleans up and closes communication with the accessory } } } }
Java
BroadcastReceiver usbReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) { UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); if (accessory != null) { // call your method that cleans up and closes communication with the accessory } } } };
Criar o broadcast receiver dentro do aplicativo, e não o manifesto, permite que seu para processar apenas eventos desconectados enquanto estiver em execução. Dessa forma, os eventos independentes são enviados somente para o aplicativo em execução no momento e não transmitidos para todos os aplicativos.