Tuesday, February 18, 2014

Search UsbInterface and UsbEndpoint, of USB_ENDPOINT_XFER_BULK type, with both USB_DIR_OUT and USB_DIR_IN

This example scan USB devices in USB Host mode, search for any UsbInterface and UsbEndpoint, of USB_ENDPOINT_XFER_BULK type, with both USB_DIR_OUT and USB_DIR_IN.

Search UsbInterface and UsbEndpoint automatically
Search UsbInterface and UsbEndpoint
Modify MainActivity.java in "Use intent filter to detect a specified USB device and auto start application", implement searchEndPoint() and remove un-necessary function.
package com.example.androidusbhost;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;

import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;

public class MainActivity extends Activity {

 TextView textInfo;
 TextView textSearchedEndpoint;
 
 TextView textDeviceName;
 TextView textStatus;
 
 private static final int targetVendorID= 9025;
 private static final int targetProductID = 32828;
 UsbDevice deviceFound = null;
 UsbInterface usbInterfaceFound = null;
 UsbEndpoint endpointIn = null;
 UsbEndpoint endpointOut = null;

 private static final String ACTION_USB_PERMISSION = 
   "com.android.example.USB_PERMISSION";
 PendingIntent mPermissionIntent;
 
 UsbInterface usbInterface;
 UsbDeviceConnection usbDeviceConnection;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  textStatus = (TextView)findViewById(R.id.textstatus);
  
  textDeviceName = (TextView)findViewById(R.id.textdevicename);
  textInfo = (TextView) findViewById(R.id.info);
  textSearchedEndpoint = (TextView)findViewById(R.id.searchedendpoint);
  
  //register the broadcast receiver
  mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
  IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
  registerReceiver(mUsbReceiver, filter);
  
  registerReceiver(mUsbDeviceReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED));
  registerReceiver(mUsbDeviceReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED));
  
  connectUsb();
 }

 @Override
 protected void onDestroy() {
  releaseUsb();
  unregisterReceiver(mUsbReceiver);
  unregisterReceiver(mUsbDeviceReceiver);
  super.onDestroy();
 }
 
 private void connectUsb(){
  
  Toast.makeText(MainActivity.this, 
    "connectUsb()", 
    Toast.LENGTH_LONG).show();
  textStatus.setText("connectUsb()");

  searchEndPoint();
  if(deviceFound != null){
   doRawDescriptors(); 
  }
 }

 private void releaseUsb(){
  
  Toast.makeText(MainActivity.this, 
    "releaseUsb()", 
    Toast.LENGTH_LONG).show();
  textStatus.setText("releaseUsb()");
  
  if(usbDeviceConnection != null){
   if(usbInterface != null){
    usbDeviceConnection.releaseInterface(usbInterface);
    usbInterface = null;
   }
   usbDeviceConnection.close();
   usbDeviceConnection = null;
  }
  
  deviceFound = null;
  usbInterfaceFound = null;
  endpointIn = null;
  endpointOut = null;
 }
 
 private void searchEndPoint(){
  
  textInfo.setText("");
  textSearchedEndpoint.setText("");
  
  usbInterfaceFound = null;
  endpointOut = null;
  endpointIn = null;
  
  //Search device for targetVendorID and targetProductID
  if(deviceFound == null){
   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();

    if(device.getVendorId()==targetVendorID){
     if(device.getProductId()==targetProductID){
      deviceFound = device;
     }
    }
   }
  }

  if(deviceFound==null){
   Toast.makeText(MainActivity.this, 
     "device not found", 
     Toast.LENGTH_LONG).show();
   textStatus.setText("device not found");
  }else{
   String s = deviceFound.toString() + "\n" + 
     "DeviceID: " + deviceFound.getDeviceId() + "\n" +
     "DeviceName: " + deviceFound.getDeviceName() + "\n" +
     "DeviceClass: " + deviceFound.getDeviceClass() + " - " 
     + translateDeviceClass(deviceFound.getDeviceClass()) + "\n" +
     "DeviceSubClass: " + deviceFound.getDeviceSubclass() + "\n" +
     "VendorID: " + deviceFound.getVendorId() + "\n" +
     "ProductID: " + deviceFound.getProductId() + "\n" +
     "InterfaceCount: " + deviceFound.getInterfaceCount();
   textInfo.setText(s);
      
   //Search for UsbInterface with Endpoint of USB_ENDPOINT_XFER_BULK,
   //and direction USB_DIR_OUT and USB_DIR_IN
   
   for(int i=0; i<deviceFound.getInterfaceCount(); i++){
    UsbInterface usbif = deviceFound.getInterface(i);
    
    UsbEndpoint tOut = null;
    UsbEndpoint tIn = null;
    
    int tEndpointCnt = usbif.getEndpointCount();
    if(tEndpointCnt>=2){
     for(int j=0; j<tEndpointCnt; j++){
      if(usbif.getEndpoint(j).getType() ==
        UsbConstants.USB_ENDPOINT_XFER_BULK){
       if(usbif.getEndpoint(j).getDirection() ==
         UsbConstants.USB_DIR_OUT){
        tOut = usbif.getEndpoint(j);
       }else if(usbif.getEndpoint(j).getDirection() ==
         UsbConstants.USB_DIR_IN){
        tIn = usbif.getEndpoint(j);
       }
      }
     }
     
     if(tOut!=null && tIn!=null){
      //This interface have both USB_DIR_OUT
      //and USB_DIR_IN of USB_ENDPOINT_XFER_BULK
      usbInterfaceFound = usbif;
      endpointOut = tOut;
      endpointIn = tIn;
     }
    }

   }
   
   if(usbInterfaceFound==null){
    textSearchedEndpoint.setText("No suitable interface found!");
   }else{
    textSearchedEndpoint.setText(
     "UsbInterface found: " + usbInterfaceFound.toString() + "\n\n" +
     "Endpoint OUT: " + endpointOut.toString() + "\n\n" +
     "Endpoint IN: " + endpointIn.toString());
   }
  }
 }

 private final BroadcastReceiver mUsbReceiver = 
   new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
     String action = intent.getAction();
     if (ACTION_USB_PERMISSION.equals(action)) {
      
      Toast.makeText(MainActivity.this, 
        "ACTION_USB_PERMISSION", 
        Toast.LENGTH_LONG).show();
      textStatus.setText("ACTION_USB_PERMISSION");
      
                  synchronized (this) {
                      UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

                      if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                          if(device != null){
                           doReadRawDescriptors(device);
                         }
                      } 
                      else {
                          Toast.makeText(MainActivity.this, 
                            "permission denied for device " + device, 
                            Toast.LENGTH_LONG).show();
                          textStatus.setText("permission denied for device " + device);
                      }
                  }
              }
    }
 };
 
 private final BroadcastReceiver mUsbDeviceReceiver = 
   new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
     String action = intent.getAction();
     if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
      
      deviceFound = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
      Toast.makeText(MainActivity.this, 
        "ACTION_USB_DEVICE_ATTACHED: \n" +
        deviceFound.toString(), 
        Toast.LENGTH_LONG).show();
      textStatus.setText("ACTION_USB_DEVICE_ATTACHED: \n" +
        deviceFound.toString());
      
      connectUsb();

     }else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
      
      UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
      
      Toast.makeText(MainActivity.this, 
        "ACTION_USB_DEVICE_DETACHED: \n" +
        device.toString(), 
        Toast.LENGTH_LONG).show();
      textStatus.setText("ACTION_USB_DEVICE_DETACHED: \n" +
        device.toString());
      
      if(device!=null){
       if(device == deviceFound){
        releaseUsb();
       }
      }
      
      textInfo.setText("");
     }
    }
  
 };
 
 private void doRawDescriptors(){
  UsbDevice deviceToRead = deviceFound;
  UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
  
  Boolean permitToRead = manager.hasPermission(deviceToRead);
  
  if(permitToRead){
   doReadRawDescriptors(deviceToRead);
  }else{
   manager.requestPermission(deviceToRead, mPermissionIntent);
   Toast.makeText(MainActivity.this, 
     "Permission: " + permitToRead, 
     Toast.LENGTH_LONG).show();
   textStatus.setText("Permission: " + permitToRead);
  }
 }
 
 private void doReadRawDescriptors(UsbDevice device){
  final int STD_USB_REQUEST_GET_DESCRIPTOR = 0x06;
  final int LIBUSB_DT_STRING = 0x03;
  
  boolean forceClaim = true;
  
  byte[] buffer = new byte[255];
        int indexManufacturer = 14;
        int indexProduct = 15;
        String stringManufacturer = "";
        String stringProduct = "";
  
  UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
  usbDeviceConnection = manager.openDevice(device);
  if(usbDeviceConnection != null){
   usbInterface = device.getInterface(0);
   usbDeviceConnection.claimInterface(usbInterface, forceClaim);
   
   byte[] rawDescriptors = usbDeviceConnection.getRawDescriptors();
   
   int lengthManufacturer = usbDeviceConnection.controlTransfer(
     UsbConstants.USB_DIR_IN|UsbConstants.USB_TYPE_STANDARD,
     STD_USB_REQUEST_GET_DESCRIPTOR,
     (LIBUSB_DT_STRING << 8) | rawDescriptors[indexManufacturer],
     0,
     buffer,
     0xFF,
     0);
   try {
    stringManufacturer = new String(buffer, 2, lengthManufacturer-2, "UTF-16LE");
   } catch (UnsupportedEncodingException e) {
    Toast.makeText(MainActivity.this, e.toString(), Toast.LENGTH_LONG).show();
    textStatus.setText(e.toString());
   }
   
   int lengthProduct = usbDeviceConnection.controlTransfer(
     UsbConstants.USB_DIR_IN|UsbConstants.USB_TYPE_STANDARD,
     STD_USB_REQUEST_GET_DESCRIPTOR,
     (LIBUSB_DT_STRING << 8) | rawDescriptors[indexProduct],
     0,
     buffer,
     0xFF,
     0);
   try {
    stringProduct = new String(buffer, 2, lengthProduct-2, "UTF-16LE");
   } catch (UnsupportedEncodingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   
   Toast.makeText(MainActivity.this, 
     "Manufacturer: " + stringManufacturer + "\n" +
     "Product: " + stringProduct, 
     Toast.LENGTH_LONG).show();
   textStatus.setText("Manufacturer: " + stringManufacturer + "\n" +
     "Product: " + stringProduct);
  }else{
   Toast.makeText(MainActivity.this, 
     "open failed", 
     Toast.LENGTH_LONG).show();
   textStatus.setText("open failed");
  }
 }

 private String translateDeviceClass(int deviceClass){
  switch(deviceClass){
  case UsbConstants.USB_CLASS_APP_SPEC: 
   return "Application specific USB class";
  case UsbConstants.USB_CLASS_AUDIO: 
   return "USB class for audio devices";
  case UsbConstants.USB_CLASS_CDC_DATA: 
   return "USB class for CDC devices (communications device class)";
  case UsbConstants.USB_CLASS_COMM: 
   return "USB class for communication devices";
  case UsbConstants.USB_CLASS_CONTENT_SEC: 
   return "USB class for content security devices";
  case UsbConstants.USB_CLASS_CSCID: 
   return "USB class for content smart card devices";
  case UsbConstants.USB_CLASS_HID: 
   return "USB class for human interface devices (for example, mice and keyboards)";
  case UsbConstants.USB_CLASS_HUB: 
   return "USB class for USB hubs";
  case UsbConstants.USB_CLASS_MASS_STORAGE: 
   return "USB class for mass storage devices";
  case UsbConstants.USB_CLASS_MISC: 
   return "USB class for wireless miscellaneous devices";
  case UsbConstants.USB_CLASS_PER_INTERFACE: 
   return "USB class indicating that the class is determined on a per-interface basis";
  case UsbConstants.USB_CLASS_PHYSICA: 
   return "USB class for physical devices";
  case UsbConstants.USB_CLASS_PRINTER: 
   return "USB class for printers";
  case UsbConstants.USB_CLASS_STILL_IMAGE: 
   return "USB class for still image devices (digital cameras)";
  case UsbConstants.USB_CLASS_VENDOR_SPEC: 
   return "Vendor specific USB class";
  case UsbConstants.USB_CLASS_VIDEO: 
   return "USB class for video devices";
  case UsbConstants.USB_CLASS_WIRELESS_CONTROLLER: 
   return "USB class for wireless controller devices";
  default: return "Unknown USB class!";
  
  }
 }

}

activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <TextView
        android:id="@+id/textstatus"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/textdevicename"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold|italic" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/info"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
            
            <TextView
                android:id="@+id/searchedendpoint"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textStyle="bold" />
            
        </LinearLayout>
    </ScrollView>

</LinearLayout>




download filesDownload the files.



Step-by-step: Android USB Host Mode programming

No comments: