In this article, we are going to see how to interact with USB in Android apps. What things are Required and Also 1 mini Project to Get a Clear Idea of How Things Work When We Need to Interact Android Apps With USB.
USB Endpoints and Interfaces
Endpoints:
Endpoints are the channels through which data is transferred between the USB device and the host (in this case our Android device is the host). They come in two types:
- In Endpoints: These are used by USB devices to send data to the host. For example, a camera might use an In Endpoint to send image data to a computer.
- Out Endpoints: These are used by USB devices to receive data from the host. For example, a printer might use an Out Endpoint to receive print jobs from a computer.
Interfaces:
The interface represents a set of endpoints that perform a specific function. A USB device can have multiple interfaces and each interface is identified by a unique number. For example, a printer might have one interface for printing and another for status information.
Required Components for USB Interaction and Implementing USB Communication in Android Apps
1. USB Host Mode Support:
For Android device to communicate with USB peripherals it must support USB Host Mode.Mostly modern Android devices have this capability.
2. USB Host API:
Android provides a set of APIs for interacting with USB devices. Primary classes for USB communication are UsbManager, UsbDevice, UsbDeviceConnection. These classes allow us to manage the USB devices connected to the host.
- UsbManager: This is the entry point for interacting with USB devices. It allows us to obtain a list of connected devices, request permission to communicate with a device, manage device connections.
- UsbDevice: Represents a connected USB device. It provides information about the device like its vendor and product IDs, interfaces,endpoints.
- UsbDeviceConnection: This class facilitates communication with a connected USB device. It allows us to send and receive data through the device’s endpoints.
3. USB Permissions:
Accessing USB devices is a sensitive operation we need to declare the necessary permissions in AndroidManifest.xml file. To ensure that only authorized apps can interact with connected USB devices.
XML
<uses-feature android:name="android.hardware.usb.host" /><uses-permission android:name="android.permission.USB_PERMISSION" /> |
4. USB Device Enumeration:
When a USB device is connected Android performs device enumeration to identify its capabilities and characteristics. We can use the UsbManager to obtain list of connected devices and iterate through them to find the one that matches our app requirements.
Java
UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);HashMap<String, UsbDevice> connectedDevices = usbManager.getDeviceList();Â Â for (UsbDevice device : connectedDevices.values()) {Â Â Â Â // You can check permissions and more here} |
Kotlin
val usbManager = getSystemService(Context.USB_SERVICE) as UsbManagerval connectedDevices: HashMap<String, UsbDevice> = usbManager.deviceList  for (device in connectedDevices.values) {  } |
5. Requesting Permission:
Before communicating with a USB device we need to request permission from the user using pending intent. It is a crucial security measure to ensure that only authorized apps can access the device and it is required.
Java
PendingIntent permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);usbManager.requestPermission(device, permissionIntent); |
Kotlin
val permissionIntent = PendingIntent.getBroadcast(this, 0, Intent(ACTION_USB_PERMISSION), 0)usbManager.requestPermission(device, permissionIntent) |
6. Managing Endpoints and Interfaces:
Once we have obtained permission to communicate with a device we can access its endpoints and interfaces. Using the UsbDevice and UsbDeviceConnection classes to send and receive data through the appropriate endpoints.
Example Project : Creating an App To Enumerate All the USB Devices List
In this project we are going to create an app to Get all the usb devices list that are connected to our android device with OTG.
What we are going to do:
Step By Step Implementation:
Step 1: Create a new Project and Select Kotlin/java As the programming language
Step 2: We have created a simple UI by adding one Button at Bottom
Step 3: Add Permissions To Interact With Usb that we have seen Earlier
XML
<uses-permission android:name="android.permission.USB_PERMISSION" /><uses-feature android:name="android.hardware.usb.host" /> |
Step 4: Working on Kotlin File and When the button is clicked it retrieves a list of connected USB devices and displays them in bottom sheet dialog that i have created showing information like device name, vendor ID, manufacturer name, product name,you can add more things. Each device item is clickable and clicking on it displays a toast message indicating the selected device with device name and Vendor Id.
Java
package com.ayush.gfgapp;  import android.content.Context;import android.hardware.usb.UsbDevice;import android.hardware.usb.UsbManager;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.widget.Button;import android.widget.LinearLayout;import android.widget.TextView;import android.widget.Toast;  import androidx.annotation.Nullable;import androidx.appcompat.app.AppCompatActivity;  import com.google.android.material.bottomsheet.BottomSheetDialog;  import java.util.HashMap;  public class MainActivity2 extends AppCompatActivity {      private Button getDevice;    private UsbManager usbManager;      @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main2);          // Initialize button and USB manager        getDevice = findViewById(R.id.getDevice);        usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);          // Set OnClickListener for the button        getDevice.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                // Retrieve the list of connected USB devices                HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();                showDevicesDialog(deviceList);            }        });    }      private void showDevicesDialog(HashMap<String, UsbDevice> deviceList) {        if (deviceList.isEmpty()) {            // Show a toast if no USB devices are found            Toast.makeText(this, "No USB devices found", Toast.LENGTH_SHORT).show();        } else {            // Inflate the bottom sheet layout to display the list of devices            View bottomSheetView = LayoutInflater.from(this).inflate(R.layout.bottom_sheet_device_list, null);            LinearLayout devicesLayout = bottomSheetView.findViewById(R.id.devicesLayout);              for (UsbDevice device : deviceList.values()) {                // Inflate the layout for each device item                View deviceItemLayout = LayoutInflater.from(this).inflate(R.layout.device_list_item, null);                TextView deviceNameTextView = deviceItemLayout.findViewById(R.id.deviceNameTextView);                TextView vendorIdTextView = deviceItemLayout.findViewById(R.id.vendorIdTextView);                TextView manufacturerTextView = deviceItemLayout.findViewById(R.id.manufacturerTextView);                TextView productNameTextView = deviceItemLayout.findViewById(R.id.ProductNameTextView);                TextView emptyTV = deviceItemLayout.findViewById(R.id.emptyTV);                  // Set information about the device in the corresponding TextViews                deviceNameTextView.setText("Device Name: " + device.getDeviceName());                vendorIdTextView.setText("Vendor ID: " + device.getVendorId());                manufacturerTextView.setText("Manufacturer Name: " + device.getManufacturerName());                productNameTextView.setText("Product Name: " + device.getProductName());                emptyTV.setText("Testing:- " + device.getProductId());                  // Add an OnClickListener to handle device selection                deviceItemLayout.setOnClickListener(new View.OnClickListener() {                    @Override                    public void onClick(View v) {                        Toast.makeText(MainActivity2.this, "Device Selected: " + device.getDeviceName() + " (Vendor ID: " + device.getVendorId() + ")", Toast.LENGTH_SHORT).show();                    }                });                    // Add the device item to the layout                devicesLayout.addView(deviceItemLayout);             }              // Create and display the bottom sheet dialog with the list of devices            BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(this);            bottomSheetDialog.setContentView(bottomSheetView);            bottomSheetDialog.show();        }    }} |
Kotlin
package com.ayush.gfgapp  import android.content.Contextimport android.content.Intentimport android.hardware.usb.UsbDeviceimport android.hardware.usb.UsbManagerimport android.os.Bundleimport android.view.LayoutInflaterimport android.widget.Buttonimport android.widget.LinearLayoutimport android.widget.TextViewimport android.widget.Toastimport androidx.appcompat.app.AppCompatActivityimport com.google.android.material.bottomsheet.BottomSheetDialog  class MainActivity2 : AppCompatActivity() {      private lateinit var getDevice: Button    private lateinit var usbManager: UsbManager      override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_main2)          getDevice = findViewById(R.id.getDevice)                  // Initialize the USB manager to access USB functionality        usbManager = getSystemService(Context.USB_SERVICE) as UsbManager            getDevice.setOnClickListener {            // Retrieve the list of connected USB devices            val deviceList = usbManager.deviceList                          // Call function to show the list of devices            showDevicesDialog(deviceList)         }    }      private fun showDevicesDialog(deviceList: HashMap<String, UsbDevice>) {        if (deviceList.isEmpty()) {            // Show a toast if no USB devices are found            Toast.makeText(this, "No USB devices found", Toast.LENGTH_SHORT).show()        } else {            // Inflate the bottom sheet layout to display the list of devices            val bottomSheetView = LayoutInflater.from(this).inflate(R.layout.bottom_sheet_device_list, null)            val devicesLayout = bottomSheetView.findViewById<LinearLayout>(R.id.devicesLayout)              for (device in deviceList.values) {                // Inflate the layout for each device item                val deviceItemLayout = LayoutInflater.from(this).inflate(R.layout.device_list_item, null) as LinearLayout                val deviceNameTextView = deviceItemLayout.findViewById<TextView>(R.id.deviceNameTextView)                val vendorIdTextView = deviceItemLayout.findViewById<TextView>(R.id.vendorIdTextView)                val manufacturerTextView = deviceItemLayout.findViewById<TextView>(R.id.manufacturerTextView)                val productNameTextView = deviceItemLayout.findViewById<TextView>(R.id.ProductNameTextView)                val emptyTV = deviceItemLayout.findViewById<TextView>(R.id.emptyTV)                  // Set information about the device in the corresponding TextViews                deviceNameTextView.text = "Device Name: ${device.deviceName}"                vendorIdTextView.text = "Vendor ID: ${device.vendorId}"                manufacturerTextView.text = "Manufacturer Name: ${device.manufacturerName}"                productNameTextView.text = "Product Name: ${device.productName}"                emptyTV.text = "Testing:- ${device.productId}"                  // Add an onClickListener to handle device selection                deviceItemLayout.setOnClickListener {                    Toast.makeText(this, "Device Selected: ${device.deviceName} (Vendor ID: ${device.vendorId})", Toast.LENGTH_SHORT).show()                }                                  // Add the device item to the layout                devicesLayout.addView(deviceItemLayout)             }              val bottomSheetDialog = BottomSheetDialog(this)            bottomSheetDialog.setContentView(bottomSheetView)            // Display the bottom sheet               // dialog with the list of devices            bottomSheetDialog.show()         }    }} |
Layout For Bottom Sheets:
bottom_sheet_device_list.xml:
XML
    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:background="@color/cardview_shadow_start_color"    android:orientation="vertical">      <LinearLayout        android:id="@+id/devicesLayout"        android:layout_width="match_parent"        android:background="@color/cardview_shadow_start_color"        android:layout_height="wrap_content"        android:orientation="vertical" />  </LinearLayout> |
device_list_item.xml:
XML
    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:orientation="vertical"    android:background="@color/cardview_shadow_start_color"    android:padding="16dp">      <TextView        android:id="@+id/deviceNameTextView"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:textColor="#E11919"        android:textAppearance="?android:textAppearanceMedium" />      <TextView        android:id="@+id/vendorIdTextView"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:textColor="#0EEF12"        android:layout_marginTop="4dp"        android:textAppearance="?android:textAppearanceSmall" />      <TextView        android:id="@+id/manufacturerTextView"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:textColor="#0EEF12"        android:layout_marginTop="4dp"        android:textAppearance="?android:textAppearanceSmall" />      <TextView        android:id="@+id/ProductNameTextView"        android:layout_width="wrap_content"        android:textColor="#0EEF12"        android:layout_height="wrap_content"        android:layout_marginTop="4dp"        android:textAppearance="?android:textAppearanceSmall" />      <TextView        android:id="@+id/emptyTV"        android:layout_width="wrap_content"        android:textColor="#3F51B5"        android:layout_height="wrap_content"        android:layout_marginTop="4dp"        android:textAppearance="?android:textAppearanceSmall" />  </LinearLayout> |
Output:
