- USB Host
- In this document
- Related Samples
- API Overview
- Android Manifest Requirements
- Manifest and resource file examples
- Working with Devices
- Discovering a device
- Using an intent filter
- Enumerating devices
- Obtaining permission to communicate with a device
- Communicating with a device
- Terminating communication with a device
- Usb host для андроида
USB Host
In this document
Related Samples
When your Android-powered device is in USB host mode, it acts as the USB host, powers the bus, and enumerates connected USB devices. USB host mode is supported in Android 3.1 and higher.
API Overview
Before you begin, it is important to understand the classes that you need to work with. The following table describes the USB host APIs in the android.hardware.usb package.
Table 1. USB Host APIs
Class | Description |
---|---|
UsbManager | Allows you to enumerate and communicate with connected USB devices. |
UsbDevice | Represents a connected USB device and contains methods to access its identifying information, interfaces, and endpoints. |
UsbInterface | Represents an interface of a USB device, which defines a set of functionality for the device. A device can have one or more interfaces on which to communicate on. |
UsbEndpoint | Represents an interface endpoint, which is a communication channel for this interface. An interface can have one or more endpoints, and usually has input and output endpoints for two-way communication with the device. |
UsbDeviceConnection | Represents a connection to the device, which transfers data on endpoints. This class allows you to send data back and forth sychronously or asynchronously. |
UsbRequest | Represents an asynchronous request to communicate with a device through a UsbDeviceConnection . |
UsbConstants | Defines USB constants that correspond to definitions in linux/usb/ch9.h of the Linux kernel. |
In most situations, you need to use all of these classes ( UsbRequest is only required if you are doing asynchronous communication) when communicating with a USB device. In general, you obtain a UsbManager to retrieve the desired UsbDevice . When you have the device, you need to find the appropriate UsbInterface and the UsbEndpoint of that interface to communicate on. Once you obtain the correct endpoint, open a UsbDeviceConnection to communicate with the USB device.
Android Manifest Requirements
The following list describes what you need to add to your application’s manifest file before working with the USB host APIs:
- Because not all Android-powered devices are guaranteed to support the USB host APIs, include a element that declares that your application uses the android.hardware.usb.host feature.
- Set the minimum SDK of the application to API Level 12 or higher. The USB host APIs are not present on earlier API levels.
- If you want your application to be notified of an attached USB device, specify an and element pair for the android.hardware.usb.action.USB_DEVICE_ATTACHED intent in your main activity. The element points to an external XML resource file that declares identifying information about the device that you want to detect.
In the XML resource file, declare elements for the USB devices that you want to filter. The following list describes the attributes of . In general, use vendor and product ID if you want to filter for a specific device and use class, subclass, and protocol if you want to filter for a group of USB devices, such as mass storage devices or digital cameras. You can specify none or all of these attributes. Specifying no attributes matches every USB device, so only do this if your application requires it:
- vendor-id
- product-id
- class
- subclass
- protocol (device or interface)
Save the resource file in the res/xml/ directory. The resource file name (without the .xml extension) must be the same as the one you specified in the element. The format for the XML resource file is in the example below.
Manifest and resource file examples
The following example shows a sample manifest and its corresponding resource file:
In this case, the following resource file should be saved in res/xml/device_filter.xml and specifies that any USB device with the specified attributes should be filtered:
Working with Devices
When users connect USB devices to an Android-powered device, the Android system can determine whether your application is interested in the connected device. If so, you can set up communication with the device if desired. To do this, your application has to:
- Discover connected USB devices by using an intent filter to be notified when the user connects a USB device or by enumerating USB devices that are already connected.
- Ask the user for permission to connect to the USB device, if not already obtained.
- Communicate with the USB device by reading and writing data on the appropriate interface endpoints.
Discovering a device
Your application can discover USB devices by either using an intent filter to be notified when the user connects a device or by enumerating USB devices that are already connected. Using an intent filter is useful if you want to be able to have your application automatically detect a desired device. Enumerating connected USB devices is useful if you want to get a list of all connected devices or if your application did not filter for an intent.
Using an intent filter
To have your application discover a particular USB device, you can specify an intent filter to filter for the android.hardware.usb.action.USB_DEVICE_ATTACHED intent. Along with this intent filter, you need to specify a resource file that specifies properties of the USB device, such as product and vendor ID. When users connect a device that matches your device filter, the system presents them with a dialog that asks if they want to start your application. If users accept, your application automatically has permission to access the device until the device is disconnected.
The following example shows how to declare the intent filter:
The following example shows how to declare the corresponding resource file that specifies the USB devices that you’re interested in:
In your activity, you can obtain the UsbDevice that represents the attached device from the intent like this:
Enumerating devices
If your application is interested in inspecting all of the USB devices currently connected while your application is running, it can enumerate devices on the bus. Use the getDeviceList() method to get a hash map of all the USB devices that are connected. The hash map is keyed by the USB device’s name if you want to obtain a device from the map.
If desired, you can also just obtain an iterator from the hash map and process each device one by one:
Obtaining permission to communicate with a device
Before communicating with the USB device, your application must have permission from your users.
Note: If your application uses an intent filter to discover USB devices as they’re connected, it automatically receives permission if the user allows your application to handle the intent. If not, you must request permission explicitly in your application before connecting to the device.
Explicitly asking for permission might be neccessary in some situations such as when your application enumerates USB devices that are already connected and then wants to communicate with one. You must check for permission to access a device before trying to communicate with it. If not, you will receive a runtime error if the user denied permission to access the device.
To explicitly obtain permission, first create a broadcast receiver. This receiver listens for the intent that gets broadcast when you call requestPermission() . The call to requestPermission() displays a dialog to the user asking for permission to connect to the device. The following sample code shows how to create the broadcast receiver:
To register the broadcast receiver, add this in your onCreate() method in your activity:
To display the dialog that asks users for permission to connect to the device, call the requestPermission() method:
When users reply to the dialog, your broadcast receiver receives the intent that contains the EXTRA_PERMISSION_GRANTED extra, which is a boolean representing the answer. Check this extra for a value of true before connecting to the device.
Communicating with a device
Communication with a USB device can be either synchronous or asynchronous. In either case, you should create a new thread on which to carry out all data transmissions, so you don’t block the UI thread. To properly set up communication with a device, you need to obtain the appropriate UsbInterface and UsbEndpoint of the device that you want to communicate on and send requests on this endpoint with a UsbDeviceConnection . In general, your code should:
- Check a UsbDevice object’s attributes, such as product ID, vendor ID, or device class to figure out whether or not you want to communicate with the device.
- When you are certain that you want to communicate with the device, find the appropriate UsbInterface that you want to use to communicate along with the appropriate UsbEndpoint of that interface. Interfaces can have one or more endpoints, and commonly will have an input and output endpoint for two-way communication.
- When you find the correct endpoint, open a UsbDeviceConnection on that endpoint.
- Supply the data that you want to transmit on the endpoint with the bulkTransfer() or controlTransfer() method. You should carry out this step in another thread to prevent blocking the main UI thread. For more information about using threads in Android, see Processes and Threads.
The following code snippet is a trivial way to do a synchronous data transfer. Your code should have more logic to correctly find the correct interface and endpoints to communicate on and also should do any transferring of data in a different thread than the main UI thread:
To send data asynchronously, use the UsbRequest class to initialize and queue an asynchronous request, then wait for the result with requestWait() .
For more information, see the AdbTest sample, which shows how to do asynchronous bulk transfers, and the MissileLauncher sample, which shows how to listen on an interrupt endpoint asynchronously.
Terminating communication with a device
When you are done communicating with a device or if the device was detached, close the UsbInterface and UsbDeviceConnection by calling releaseInterface() and close() . To listen for detached events, create a broadcast receiver like below:
Creating the broadcast receiver within the application, and not the manifest, allows your application to only handle detached events while it is running. This way, detached events are only sent to the application that is currently running and not broadcast to all applications.
Источник
Usb host для андроида
Когда устройство на базе Android работает в режиме USB host, оно становится главным устройством на шине USB, подает питание на шину, и производит энумерацию для подключенных к шине устройств USB. Режим хоста USB поддерживается в Android 3.1 и более новых версиях. Непонятные термины касательно шины USB см. в USB in a NutShell [2] (на русском языке), а непонятные термины и сокращения, касающиеся Androd, в Словарике [5].
[Обзор API]
Чтобы разобраться в режиме USB host для Android, важно понимать, с какими классами устройств USB Вам предстоит работать. В следующей таблице описаны классы USB host API в пакете android.hardware.usb.
Таблица 1. USB Host API.
Класс | Описание |
---|---|
UsbManager | Позволяет Вам производить энумерацию подключенных устройств USB и организовать обмен с ними. |
UsbDevice | Представляет подключенное устройство USB, и содержит методы для доступа к идентификационной информации, интерфейсам и конечным точкам. |
UsbInterface | Представляет интерфейс устройства USB определяющий набор функционала устройства. Устройство может иметь один или большее количество интерфейсов, с которыми можно взаимодействовать. |
UsbEndpoint | Представляет конечную точку интерфейса (interface endpoint), которая дает канал связи для этого интерфейса. Интерфейс может иметь 1 или большее количество конечных точек, и обычно имеет отдельно конечную точку для ввода и отдельно конечную точку для вывода, чтобы можно было вести обмен данными в двух направлениях. |
UsbDeviceConnection | Представляет соединение с устройством, которое переносит данные между Android и конечными точками. Этот класс позволяет Вам отправить блок данных туда и обратно, синхронно или асинхронно. |
UsbRequest | Представляет асинхронный запрос для обмена с устройством через UsbDeviceConnection . |
UsbConstants | Определяет константы USB, соответствующие определениям в linux/usb/ch9.h ядра Linux. |
В большинстве ситуаций Вам нужно использовать все эти классы (UsbRequest требуется только если Вы осуществляете асинхронную связь), когда происходит взаимодействие с устройством USB device. Обычно Вы задействуете UsbManager для получения доступа к нужному UsbDevice. Когда Вы получили устройство USB, то для обмена данными нужно найти подходящий интерфейс UsbInterface и конечную точку UsbEndpoint на этом интерфейсе. Как только Вы получили правильную конечную точку, откройте соединение UsbDeviceConnection для обмена данными с устройством USB.
[Требования к Android Manifest]
Следующий список описывает, что Вам нужно добавить в манифест приложения перед тем, как начать работать с USB host API:
• Поскольку не все устройства на базе Android гарантированно поддерживают USB host API, включите элемент , который декларирует, что Ваше приложение использует фичу android.hardware.usb.host .
• Установите минимальный уровень SDK приложение на API Level 12 или более высокий, потому что USB host API не представлены в более старых уровнях API.
• Если Вы хотите, чтобы Ваше приложение получало оповещение о подключенных к шине USB устройствах, укажите пару элементов и для intent android.hardware.usb.action.USB_DEVICE_ATTACHED в главной активности приложения. Элемент указывает на внешний XML-файл ресурса, в котором указана идентификационная информация об устройстве, подключение которого нужно детектировать.
В XML-файле ресурсов продекларируйте элементы для устройств USB, которые хотите отфильтровать. Следующий список описывает атрибуты элемента . Обычно указываются идентификаторы вендора (vendor ID, VID) и продукта (product ID, PID), если хотите фильтровать специфическое устройство, и используется class, subclass и protocol, если хотите фильтровать группы (классы) устройств USB, такие как устройства хранения (mass storage devices, MSD) или цифровые камеры. Вы можете не указывать ни одного из этих атрибутов, в этом случае фильтрация подойдет под любое устройство USB, не только то, что Вам нужно. Вот имена атрибутов для устройств USB:
vendor-id
product-id
class
subclass
protocol (device или interface)
Сохраните XML-файл ресурсов в директории res/xml/ . Имя файла ресурса (без расширения .xml) должно быть то же самое, как указано в элементе . Формат файла ресурса XML показан в примере ниже (пример манифеста и соответствующего ему файла ресурсов):
В этом случае следующий файл ресурсов будет сохранен в файл res/xml/device_filter.xml (здесь указано, что должно фильтроваться любое устройство USB с указанными параметрами):
Примечание: указанные здесь в текстовом виде значения VID (vendor-id) и PID (product-id) должны быть не в шестнадцатеричном виде, а в десятичном. Таким образом, если например у Вас VID=0x16C0, PID=0x05DF, то вы должны преобразовать эти шестнадцатеричные значения в десятичные, и их в текстовом виде указать в XML:
VID 0x16C0 -> 5824
PID 0x05DF -> 1503
Если необходимо, чтобы под фильтр попадали все без исключения подключаемые устройства USB, то просто удалите из элемента usb-device его атрибуты:
[Как работать с устройствами USB, подключенными к Android]
Когда пользователи подключают устройства USB к Android, то система Android может определить интересно ли подключенное устройство USB для Вашего приложения. Если это так, то Вы можете установить обмен с устройством, если это нужно. Для этого приложение должно выполнить:
1. Определение подключенных устройств USB, используя intent фильтр для оповещения о ситуациях, когда пользователь подключает устройство USB, или путем энумерации устройств USB, которые уже подключены.
2. Запросить у пользователя разрешение на подключение к устройству USB, если оно еще не получено.
3. Далее можно осуществлять взаимодействие с устройством USB путем чтения и записи данных через соответствующие конечные точки интерфейса (interface endpoints).
[Определение наличия подключенного устройства USB]
Ваше приложение может распознать устройства USB либо с помощью использования intent-фильтра, который будет оповещать подключение пользователем устройств, либо путем энумерации устройств USB, которые уже подключены. Использование фильтра intent полезно, если Вы хотите иметь в приложении возможность автоматического детектирования (подключения) нужного устройства. Энумерация подключенных устройств USB полезна, если Вы хотите получить список всех подключенных устройств, или если Ваше приложение не делает фильтр для intent.
Использование intent filter
Чтобы приложение могло обнаружить какое-то отдельное устройство USB, Вы можете указать intent filter, чтобы фильтровать android.hardware.usb.action.USB_DEVICE_ATTACHED intent. Вместе с этим intent filter Вам нужно указать файл ресурса, который задает свойства устройства USB, такие как VID и/или PID. Когда пользователь подключает устройство, которое подходит под условие фильтра устройства, система представляет диалог, запрашивающий у пользователя, хочет ли он запустить Вашу программу. Если пользователь подтвердит запуск, то Ваше приложение автоматически будет иметь право на доступ (permission access) к устройству, пока устройство не будет отключено.
В следующем примере показано, как декларировать intent filter:
Следующий пример показывает, как декларировать соответствующий файл ресурса, который указывает интересующие Вас устройства USB:
В activity приложения Вы можете получить объект UsbDevice, который представляет подключенное устройство USB из intent примерно так:
Энумерация устройств
Если Ваше приложение нуждается в инспекции всех устройств USB, уже подключенных во время работы приложения, то оно может произвести энумерацию устройств на шине USB. Используйте метод getDeviceList() для получения карты всех устройств USB (hash map), которые сейчас подключены. В списке hash map есть имена устройств USB, которые Вы можете использовать для получения доступа к устройству.
Если необходимо, Вы также можете просто получить итератор из hash map и обработать каждое устройство друг за другом:
[Получение права на взаимодействие с устройством USB]
Перед тем, как начать обмен с устройством USB, Ваше приложение должно запросить на это разрешение от пользователя.
Примечание: если Ваше приложение использует intent filter, чтобы распознать подключенные устройства USB, то оно автоматически принимает разрешение, если пользователь разрешает разрешает Вашему приложению обработать intent. Если нет, то Вы должны в приложении явным образом запросить разрешение перед подключением к устройству.
Явный запрос на разрешение может быть необходим в некоторых ситуациях, таких как если Ваше приложение делает энумерацию уже подключенных устройств USB, и затем хочет обмениваться данными с ними. Вы должны проверить право на доступ к устройству, перед тем как сделать попытку взаимодействовать с ним. Если этого не сделать, то Вы получите runtime error (ошибка во время выполнения), когда пользователь не дал разрешения на доступ к устройству.
Чтобы явно получить разрешение, создайте сначала broadcast receiver (широковещательный приемник). Этот receiver прослушивает intent, которое получает broadcast, когда Вы вызываете requestPermission(). Вызов requestPermission() отображает диалог для пользователя с запросом разрешения на подключение к устройству USB. В следующем примере кода показано, как создать broadcast receiver:
Для того, чтобы зарегистрировать broadcast receiver, добавьте в метод onCreate() Вашей activity следующий код:
Чтобы отобразить диалог, запрашивающий у пользователей разрешение на подключение к устройству, вызовите метод requestPermission():
Когда пользователь ответит на этот диалог, Ваш broadcast receiver получит intent, который содержит расширение EXTRA_PERMISSION_GRANTED, представляющее суть ответа в двоичном виде. Проверьте его на значение true перед тем, как подключиться к устройству.
[Обмен с устройством USB]
Обмен с устройством USB может быть либо синхронным, либо асинхронным. В любом случае Вы должны создать новый поток, который будет обрабатывать все перемещения данных, чтобы не блокировать на ожидании поток интерфейса (UI thread). Чтобы правильно установить обмен с устройством, Вам нужно получить соответствующие объекты UsbInterface и UsbEndpoint устройства, с которым Вы хотите наладить обмен, и отправлять запросы в эти конечные точки с помощью UsbDeviceConnection . В общем случае Ваш код должен делать следующее:
• Нужно проверить атрибуты объекта UsbDevice , такие как product ID (идентификатор продукта, PID), vendor ID (идентификатор производителя, VID), или класс устройства — чтобы определить, хотите ли Вы соединиться именно с этим устройством USB.
• Когда принято положительное решение на обмен с этим устройством USB, найдите подходящий UsbInterface (), который Вы хотите использовать для обмена с подходящей UsbEndpoint интерфейса (конечные точки и их привязка к интерфейсу также задана в дескрипторах USB).
Прим. переводчика: интерфейс — это некая логическая сущность, описывающая метод взаимодействия с устройством USB. И интерфейсу привязаны конечные точки — другая логическая сущность, олицетворяющая какой-то буфер данных в устройстве USB. Наличие конкретного интерфейса (он обычно в устройстве USB один, но интерфейсом может быть и несколько), его тип, привязка к интерфейсу конечных точек, тип конечных точек — все это зависит от дескрипторов устройства USB (подробнее см. [2]). Дескрипторы устройств USB автоматически считываются системой Android при энумерации и подключении устройств USB.
Интерфейсу может принадлежать одна или большее количество конечных точек (endpoint). Обычно для осуществления двунаправленного обмена имеются 2 конечные точки — одна конечная точка работает на ввод от устройства (IN endpoint), а другая на вывод в устройство (OUT endpoint).
• Когда Вы нашли корректную конечную точку, откройте UsbDeviceConnection к этой конечной точке.
• Предоставьте данные, которые Вы хотите передать в конечную точку методами bulkTransfer() или controlTransfer() . Вы должны провести эту операцию передачи данных в другом потоке, чтобы не блокировать главный поток интерфейса пользователя (main UI thread). Для дополнительной информации по использованию потоков в Android см. [3].
Следующий кусок кода показывает тривиальный способ осуществить синхронную передачу данных. Ваш реальный рабочий код должен содержать больше логики, чтобы корректно найти нужный интерфейс и конечные точки для обмена, и также должен передавать данные в отдельном потоке (чтобы не блокировать main UI thread, и чтобы приложение визуально не тормозило [4]):
Чтобы отправить данные асинхронно (без ожидания), используйте класс UsbRequest для инициализации очереди на асинхронном запросе, и затем ждите результата с помощью вызова requestWait() .
Для дополнительной информации см. пример AdbTest, который показывает как делать асинхронные bulk передачи, и пример MissleLauncher, который показывает как асинхронно слушать interrupt endpoint.
[Прекращение обмена с устройством USB]
Когда Вы завершили обмен с устройством USB, или устройство USB было отключено, закройте UsbInterface и UsbDeviceConnection вызовом releaseInterface() и close() . Чтобы прослушивать события отключения, создайте broadcast receiver примерно так:
Создание broadcast receiver в приложении, не в манифесте, позволит Вашему приложению во время выполнения обрабатывать только события отключения. С таким методом события отключения будут отправлены только приложению, которое сейчас работает, и не всем приложениям.
Источник