Android usb device attached to the

Android usb device attached to the

Можно настроить и зарегистрировать BroadcastReceiver примерно так:

Нужно также определить обработчик для события BroadcastReceiver:

Здесь usbdev глобальная для класса Activity переменная типа UsbDevice.

[Ошибка приема события USB_DEVICE_ATTACHED]

На некоторых устройствах Android событие USB_DEVICE_ATTACHED не срабатывает [2], хотя USB_DEVICE_DETACHED отслеживается нормально. Но как тогда определить ситуацию, что устройство USB подключено к Android?

В документации [1] сказано, что можно определить intent-filter в файле AndroidManifest.xml для того, чтобы отследить событие подключения устройства USB к Android как хосту:

Здесь ресурс xml/all_usb_devices_filter задает файл xml/all_usb_devices_filter.xml такого содержания (здесь нет фильтрации по VID и PID устройства, поэтому фильтр будет срабатывать на все подключаемые устройства USB, подробнее см. [1]):

События подключения теперь будет отслеживать обработчик onResume экземпляра Activity программы:

События отключения будет отслеживать обработчик BroadcastReceiver, как уже было показано выше.

В таком способе определения событий подключения/отключения устройств USB кроется еще одна проблема. Если программа уже запущена, то подключение устройства приводит к запуску второго экземпляра программы (еще одного экземпляра activity), что нежелательно, и может запутать пользователя. Зачем при каждом подключении устройства USB запускать новые экземпляры программы и тратить на это ресурсы?. Чтобы этого избежать, можно определить атрибут android:launchMode для activity в значение singleTask, чтобы программа работала только в одном экземпляре.

Источник

Работа с устройствами USB в Android

В недавней статье на Geektimes в комментариях возник вопрос о поддержке в ОС Android периферии, подключенной к шине USB. Действительно, большинство вендорского ПО, к примеру, для работы с принтерами и МФУ, поддерживает только подключение по сети. Однако это не означает, что в самой ОС Android нет такой возможности — это означает лишь то, что большинство устройств не имеют полноценного USB хоста, и далеко не все имеют поддержку OTG. По сети же могут работать абсолютно все без исключения.

Большинство устройств на Android при наличии порта OTG поддерживают на уровне системы (ядра Linux или стандартных компонентов Android) следующие классы устройств:

  • Устройства ввода — клавиатуры, мыши, джойстики (HID)
  • Накопители (Mass Storage)

Несколько реже:

  • Сотовые модемы
  • Сетевые адаптеры
  • Вебкамеры

Хабы поддерживаются при наличии полноценных хост-портов, но не поддерживаются на портах OTG.

Подробнее список устройств, поддерживаемых на уровне ядра Linux, можно получить в sysfs:

$ ls /sys/bus/usb/drivers

Если же модуль в принципе доступен в исходниках ядра Linux, но не включен в Android — не стоит рассчитывать на то, что его получится собрать и расставить на все целевые системы.

Однако, начиная с Android 3.1 (API 12), в системе содержатся средства, достаточные для поддержки на уровне приложения любой USB периферии. Данные средства описаны в разделе USB Host руководства по Android API. Здесь же я хочу привести примеры реальной работы с некоторыми видами устройств.

Права доступа

Как и для прочих действий, Android требует, чтобы приложение получило разрешение на доступ к USB периферии. Существует 2 способа получить такое разрешение:

  • Задекларировать список устройств в AndroidManifest
  • Явно показать пользователю диалог “разрешить”

Поскольку для моих задач лишние вопросы к пользователю были нежелательны, я использовал первый способ.

Итак, нам необходимо добавить в манифест следующее:

А в res/xml/device_filter.xml вписать следующее:

Отмечу, что хотя общепринято указывать VID:PID в 16-ричной системе счисления, здесь они должны быть указаны в десятичной. В документации заявляется, что возможно указание только класса, без VID и PID, но у меня это не стало работать.

Принтеры

На примере принтера я покажу, как непосредственно использовать API android.hardware.usb. На уровне передачи данных все принтеры поддерживают стандартый класс USB устройств:

Класс предельно простой. В рамках этого класса устройство должно поддерживать:

  • Обязательный bulk out endpoind для отправки данных на принтер
  • Опциональный bulk in endpoind для получения статуса принтера
  • 3 управляющих запроса

Код, приведенный ниже, предоставляет функциональность, аналогичную устройству /dev/usb/lp в Linux. Далее нам нужен фильтр, преобразующий исходный документ в пакет данных, понятный конкретной модели принтера. Но это тема иной статьи. Как один из вариантов — можно собрать ghostscript с помощью NDK.

Для работы с устройством нам в первую очередь нужно:

1. Найти устройство. В примере для простоты я ищу первый попавшийся:

2. Получить endpoint’ы:

3. Непосредсвенно открыть устройство:

4. После этого мы можем читать и писать в устройство:

5. По завершении работы — закрыть устройство:

Преобразователи USB-Serial

В отличие от притеров, преобразователи USB-Serial гораздо менее стандартизированы. Существует несколько распространенных чипов, для которых существенно отличается установка параметров последовательного порта — битрейта, чётности и проч. К счастью, есть библиотека github.com/mik3y/usb-serial-for-android, поддерживающая практически все существующие чипы. Библиотека полностью скрывает USB API, сводя все необходимые действия к минимуму вызовов с минимумом параметров.

1. Найти и открыть устройство:

2. Установить параметры последовательного порта:

3. Читать и писать в порт:

4. По завершении работы — закрыть порт:

Резюме

Надеюсь, что мне удалось показать, что работа с USB периферией достаточно проста и логична. Безусловно, реализация протоколов некоторых конкретных устройств не блещет простотой — но это проявится в любой системе в одинаковой степени.

Все приведенные примеры я взял из реального проекта, лишь исключил очевидные проверки, оставив только ключевые строки.

Источник

Android Things — USB communications

Android Things now supports USB Host (since DP3), which allows a user space Android application to talk to a custom USB device.

To discover this feature, we will create a custom USB sensor, and forward all events to the Android Things board over USB.

You can see below a video of what we will achieve: the USB device will be an Arduino NFC reader. When scanning a tag (or an amiibo), the Arduino will forward NFC data to the Android Things board over USB.

Читайте также:  Пин код для запуска андроид zte

Attention, please

There are two different ways to communicate with a USB device via Android Things.

If the device is a USB-Serial and if it reports a /dev/tty* device handle through the kernel, then you won’t need to use any USB Host API. Instead, try to call PeripheralManager.getUartDeviceList() . If you can see a new UART endpoint, this means that you can directly use the UART API to communicate with the USB device. No need to use USB APIs at all (if you don’t need those).

If the device does not report a new /dev/tty* after being plugged in (e.g. the kernel doesn’t have the driver built-in), you are forced to use the USB layer. You will need to manipulate the USB Host API, which allows a regular user space application to communicate with USB devices without root privileges or support needed from the Linux kernel.

In a previous post, we already saw how to communicate with a serial device over UART.
This time, we will use the USB Host API, and the serial communication will be performed using a third party library. That way, the code we will write here will not be specific to Android Things, but will also work on any Android (3.1 and above) smartphone.

Flashing the Arduino

We will start with something simple: we first want the Arduino to continuously send the «Hello!» value to the serial port every second, at a 115 200 baud rate.

When we connect the Arduino to the Android Things board, we expect our app to receive the «Hello!» text every second. And for that, we’ll first have to edit the AndroidManifest.xml .

AndroidManifest.xml

We want to be notified when an external USB device is attached to the Android device.
This can be done adding a new intent-filter entry to the Activity that should be started by the system when a USB device is plugged in.
Also, we will add a meta-data element pointing to an external XML resource file (here in res/xml/device_filter.xml ) that declares identifying information about the device that we want to detect.

If the device_filter.xml file has the following content, we will be notified each time any USB device is plugged in:

This is not exactly what we want. We only want to be notified when the Arduino is plugged in, and ignore all other USB devices, so we will add a specific rule.

After connecting the Arduino to the Android Things board, we can consult the kernel logs using dmesg to get some device information:

We only want to be notified when the Arduino (idVendor=0x2341) is connected, so we will specify this vendor id into the usb-device tag:

Note here that the vendor-id expects a decimal value, not a hexadecimal one.

This filter will be enough for us. For a complete list of what we can do, please refer to the USB Host documentation

Starting a USB connection

Our Activity now receives an intent each time the Arduino is plugged in.

We will first list all the connected USB devices, and open a USB connection if the Arduino was found:

The startSerialConnection method will use felHR85’s USBSerial library to open a serial connection between the Arduino and the Android device:

The UsbSerialDevice.read() method takes an UsbReadCallback reference which will be called each time data is received. Here is a simple implementation:

We convert the byte[] data to a UTF-8 String, and log this data.

Now, each time data is sent from the Arduino over USB, the callback is triggered and data is logged. We can run adb logcat to confirm that we receive the “Hello!” message from the Arduino every second:

For a complete and optimized source code, take a look at github.com/Nilhcem/usbfun-androidthings.

Adding some more fun

Printing «Hello!» to the logs every second is quite boring.
A fast way to add some fun to this project is to connect an NFC module to the Arduino and send NFC tag data from this module to the Android Things board over USB.

I used Elechouse’s PN532 Module over SPI, using this sketch.

To simplify, I am only forwarding the tag ID to the Android Things board. And the Android app displays an appropriate image depending on the received ID.

Porting this project to an Android smartphone

As explained in the introduction, the project uses the USB Host API from the Android SDK, and is therefore fully compatible with any Android smartphones or tablets (minSdk=12). If you own a USB-OTG cable, you can plug an Arduino directly to your phone.

Below, a demonstration (with sound) of an Android phone, sending data to an Arduino over USB to play music on a piezo buzzer. (source code is available here)

There’s still one difference however: when a USB device is connected, a UI dialog is shown and the user needs to grant the USB permission to access the device. Checking whether the permission is granted was skipped on the Android Things source code project we wrote, as, similar to runtime permissions, you don’t have to check/request USB permission on Android Things since there may be no display attached, and therefore, no ways for users to grant those permissions. They are allowed by default.

Going further

A better example of what you can do with the USB Host API is the official USB enum sample.
This project iterates over all the USB devices discovered by the host and prints their interfaces and endpoints.

Reading the source code is interesting here as we can learn about USB descriptors.

For example, after a USB device has been detected, it is opened using the same API we used in this article (via UsbManager.openDevice() ), then, instead of opening a serial connection, the code immediately queries the USB device and configuration(s) descriptors:

When reading the USB specs, it is specified that all USB devices must support at least a default endpoint. Any transfer that targets this endpoint is called a control transfer, and is a way for the host to obtain device information.

  • 0x80 is the data direction. Here, it means “IN” (from the USB device to the host)
  • 0x06 is the request type to get a descriptor
  • 0x100 is for a device descriptor ( 0x200 for a configuration descriptor)
  • 0x00 is the descriptor index (default descriptor)
Читайте также:  Smart reading service андроид что это

Then, the code receives data from the buffer, as specified in the documentation.

And so on. Once we understand that, the sample code is much easier to read.

Conclusion

This post introduced an example of how to use the USB Host API with Android Things.
In a real-life scenario, you won’t need to use an Arduino to bring NFC support to Android Things, as you can develop the NFC driver directly, and even if you need to, you may be able to communicate with the Arduino using the UART API directly. You may not need to use the USB Host API + a third party dependency.

If you own a USB-Serial device and if this latter is recognized by the kernel, then using the UART API is the easiest and recommended way to communicate between both devices. But if you need to access any kind of USB device from an app, then you’ll be happy to have a user-space USB support on Android Things.

As Marcos Placona explained in a blog post, some components need super-fast drivers (sending signals that alternate from vcc to ground in a few microseconds). While this is not possible yet with Android Things, you could use a microcontroller that acts as a proxy and directs data to the Android Things board over USB, to use those components in your Android Things projects.

Источник

USB Host

In this document

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:

  1. 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.
  2. Ask the user for permission to connect to the USB device, if not already obtained.
  3. 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.

Источник

Читайте также:  Найди рингтоны для андроид
Оцените статью