USB interface in android

假如想象 提交于 2021-02-17 20:47:34

问题


I rooted my device and working in host mode. I can able to detect the usb device connected to my tab but Am having two questions.

1) i try to display my device name using device.getDeviceName(); but its showing something like/dev/usb/002/002 I need to get the manufacturer name of the usb device name. I thing its available in accessory mode but i need to get the manufacturer name in host mode.

2)I need to transfer some data from my app to the usb port in android. i can able to detect the device but please help in transfering some data or file from my android app to mass storage connected to usb port.


回答1:


Probably you will actually need to read the Raw USB Descriptors to get at the data you want. Here's a basic USB device discovery program I wrote for my own purposes. Mind you that I'm looking for a specific device (a Dajac Easy I/O 1000 data acquisition system) but you can apply the same principles. I do show you how to get the data you're looking for.

Here's the code first. My package is usbtest3, and the file is MainActivity.java:

package com.hotspotoffice.usbtest3;

// David Schofield, Hotspot Office, LLC., Pittsburgh, PA.
// Donations via PayPal always welcome! schofield (dot) david (at) verizon.net

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import android.os.Bundle;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.view.View;
import android.view.Menu;
import android.widget.Button;
import android.widget.TextView;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbInterface;


public class MainActivity extends Activity {

    protected static final int STD_USB_REQUEST_GET_DESCRIPTOR = 0x06;
    // http://libusb.sourceforge.net/api-1.0/group__desc.html
    protected static final int LIBUSB_DT_STRING = 0x03;
    private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";

    private Button btnDiscover;
    private TextView txtInfo;
    private PendingIntent mPermissionIntent; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnDiscover=(Button)findViewById(R.id.btnDiscover);
        txtInfo=(TextView)findViewById(R.id.txtInfo);

        mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
        registerReceiver(mUsbReceiver, filter);

        btnDiscover.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // txtInfo.setText("Button has been Pressed for "+(++i)+" Times.");

                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();

                    manager.requestPermission(device, mPermissionIntent);

                    txtInfo.append("Model:" + device.getDeviceName() + "\n");  
                    txtInfo.append("DeviceID:" + device.getDeviceId() + "\n");
                    txtInfo.append("Vendor:" + device.getVendorId() + "\n");
                    txtInfo.append("Product:" + device.getProductId() + "\n");
                    txtInfo.append("Class:" + device.getDeviceClass() + "\n");
                    txtInfo.append("Subclass:" + device.getDeviceSubclass() + "\n");
                    txtInfo.append("Protocol:" + device.getDeviceProtocol() + "\n");

                    UsbInterface intf = device.getInterface(0);
                    int epc = 0;
                    epc = intf.getEndpointCount();
                    txtInfo.append("Endpoints:" + epc + "\n");

                    txtInfo.append("Permission:" + Boolean.toString(manager.hasPermission(device))  + "\n");

                    UsbDeviceConnection connection = manager.openDevice(device);
                    if(null==connection){
                        txtInfo.append("(unable to establish connection)\n");
                    } else {

                        // Claims exclusive access to a UsbInterface. 
                        // This must be done before sending or receiving data on 
                        // any UsbEndpoints belonging to the interface.
                        connection.claimInterface(intf, true);

                        // getRawDescriptors can be used to access descriptors 
                        // not supported directly via the higher level APIs, 
                        // like getting the manufacturer and product names.
                        // because it returns bytes, you can get a variety of
                        // different data types.
                        byte[] rawDescs = connection.getRawDescriptors();
                        String manufacturer = "", product = "";

                        try
                        {
                            byte[] buffer = new byte[255];
                            int idxMan = rawDescs[14];
                            int idxPrd = rawDescs[15];

                            int rdo = connection.controlTransfer(UsbConstants.USB_DIR_IN
                                    | UsbConstants.USB_TYPE_STANDARD, STD_USB_REQUEST_GET_DESCRIPTOR,
                                    (LIBUSB_DT_STRING << 8) | idxMan, 0, buffer, 0xFF, 0);
                            manufacturer = new String(buffer, 2, rdo - 2, "UTF-16LE");

                            rdo = connection.controlTransfer(UsbConstants.USB_DIR_IN
                                            | UsbConstants.USB_TYPE_STANDARD, STD_USB_REQUEST_GET_DESCRIPTOR,
                                    (LIBUSB_DT_STRING << 8) | idxPrd, 0, buffer, 0xFF, 0);
                            product = new String(buffer, 2, rdo - 2, "UTF-16LE");

                        } catch (UnsupportedEncodingException e)
                        {
                        e.printStackTrace();
                        }

                        txtInfo.append("Manufacturer:" + manufacturer + "\n");                      
                        txtInfo.append("Product:" + product + "\n");                        
                        txtInfo.append("Serial#:" + connection.getSerial() + "\n");                     
                    }

                    txtInfo.append("------------------------------------\n");                   
                }               

            }
        });

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {

        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (ACTION_USB_PERMISSION.equals(action)) {
                synchronized (this) {
                    UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        if(device != null){
                          //call method to set up device communication
                       }
                    } 
                    else {
                        txtInfo.append("permission denied for device " + device);
                    }
                }
            }
        }
    };

}

My manifest file containing the intents and requirements for the USB Host device support:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.hotspotoffice.usbtest3"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-feature android:name="android.hardware.usb.host" />

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="15" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <activity
            android:name="com.hotspotoffice.usbtest3.MainActivity"
            android:label="@string/app_name" >

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <intent-filter>
                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
            </intent-filter>

            <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
                android:resource="@xml/device_filter" />

        </activity>
    </application>

</manifest>

Finally, you will need a device filter. This is located under \res\xml\device_filter.xml Note that I had to create the xml folder myself, under \res.

<?xml version="1.0" encoding="utf-8"?>

<resources>
    <usb-device vendor-id="7635" product-id="1" class="255" subclass="255" protocol="0" />
</resources>

Note that all the fields need to be in decimal, not hex. You'll need to substitute your own vendor, product, class and subclass values from your own device. You can use a program like "USB Host View" or "USB Device Info" to discover these values. (download them free from the Play Store.)

Finally, here's how I defined the user interface in Activity_Main.xml
You'll need at least the Discover button, and the TextMultiline for output. (Ignore the Init and On/Off buttons.)

BTW, I'm using a 10" Toshiba Thrive tablet, so YMMV.

<RelativeLayout 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"
    tools:context=".MainActivity" >

    <EditText
        android:id="@+id/txtInfo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/btnDiscover"
        android:layout_alignRight="@+id/textView1"
        android:layout_centerVertical="true"
        android:ems="10"
        android:inputType="textMultiLine"
        android:maxLines="50"
        android:minLines="20"
        android:minWidth="400dp" >

        <requestFocus />
    </EditText>

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/btnToggleDIO"
        android:layout_marginLeft="192dp"
        android:layout_toRightOf="@+id/btnDiscover"
        android:text="@string/lblDIO"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <Button
        android:id="@+id/btnDiscover"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/btnInit"
        android:layout_alignBottom="@+id/btnInit"
        android:layout_alignParentLeft="true"
        android:layout_marginLeft="73dp"
        android:text="@string/strDiscover" />

    <ToggleButton
        android:id="@+id/btnToggleDIO"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/btnInit"
        android:layout_alignBottom="@+id/btnInit"
        android:layout_alignLeft="@+id/textView1"
        android:text="@string/strIOState" />

    <Button
        android:id="@+id/btnInit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/txtInfo"
        android:layout_marginBottom="29dp"
        android:layout_marginLeft="48dp"
        android:layout_toRightOf="@+id/btnDiscover"
        android:text="@string/strInit" />

</RelativeLayout>

When I run my program and plug in my device, it asks for my permission to connect and I say "Ok". then I click Discover, and it tells me among other things that the manufacturer is "Dajac Inc." the product is "EIO1000" and the serial# is "0000004B".

I wish you good providence; you can give me credit but it's only by standing on the shoulders of others (with a lot of my own sweat) I've been able to see this far. Pass it forward! -David




回答2:


Code above works fine for most of the devices except Samsung mobile devices. For making them supply Language ID else you will get stall.

int rdo = connection.controlTransfer(UsbConstants.USB_DIR_IN
| UsbConstants.USB_TYPE_STANDARD, STD_USB_REQUEST_GET_DESCRIPTOR,
(LIBUSB_DT_STRING << 8) | idxMan, 0x0409, buffer, 0xFF, 0);



回答3:


device name

This looks like the internal device name from the Linux Kernel.

manufacturer name

You only get this indirectly via the USB VID (Vendor ID). They are assigned and maintained by the USB-IF.

A device may provide a name for the manufacturer in its string descriptor, but AFAIK this is optional - and not exposed in the high level android java interface.

You can try your luck with UsbDeviceConnection.getRawDescriptors, but that would require rather ugly fiddeling with bytes.

to mass storage

USB Mass storage is a rather complex protocol, so talking directly via USB Host API would be rather difficult to implement. Some Android firmware images can mount USB flash drives, that would be much simpler.




回答4:


Just a minor note on the above code, which in principle works just fine. Requesting the user permission to access the USB device is an asynchronous call. So the code should not proceed for that particular device if it does not (yet) have permissions.

Please allow me to make a small update to the onClick and onReceive methods:

    Button btnDiscover = (Button) findViewById(R.id.buttonDiscover);
    btnDiscover.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            txtInfo.setText("");
            HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
            for (UsbDevice device : deviceList.values()) {
                Log.i("discover", "Model    :" + device.getDeviceName());
                if (!manager.hasPermission(device)) {
                    Log.i("discover", "No permission to access, so requesting it now from user (async)");
                    manager.requestPermission(device, mPermissionIntent);
                } else {
                    showUsbDetails(device);
                }
            }
        }
    });

private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (MainActivity.ACTION_USB_PERMISSION.equals(action)) {
            Log.i("BroadcastReceiver", "onReceive: ACTION_USB_PERMISSION");
            synchronized (this) {
                UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                    if(device != null){
                        showUsbDetails(device);
                    }
                }
                else {
                    txtInfo.append("permission denied for device " + device);
                }
            }

Needless to say that showUsbDetails now contains the part from the original code that does the communication with the USB device to query for the manufacturer and other strings.




回答5:


  1. getVendorId() should give you manufacturer's name. Other calls include getDeviceName(), getDeviceId(), getDeviceClass(), getDeviceSubclass(), getDeviceProtocol(), getProductId(). refer this link: Android USB Host

  2. For Data Transfers, refer this link: BulkTransfer. Read from the file in a buffer and pass the buffer to bulkTransfer call along with specific output Endpoint of your device and data length.



来源:https://stackoverflow.com/questions/13217755/usb-interface-in-android

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!