最近在做有关Android TV端使用USB外设进行用户交互方面的开发。总结一下开发过程中的困惑、解决方案以及开发的整个过程:

一、做USB Host开发前的准备工作:
1. “工欲善其事必先利其器”,先简单了解一下USB Host:
1> USB Device:从硬件角度看就是一个带有USB Client控制器的设备;从软件角度看,就是一个挂在USB总线上的一个普通意义上的设备,只不过它们的驱动是基于Host驱动之上的。
2> USB Host:USB主设备,可以从另外一个USB Device中取得数据,包括USB Host控制器和USB Host协议。与USB Client设备和USB Slave协议相对应。
3> USB Client:从硬件角度看就是指USB Device,从软件角度看,就是指USB Client协议。
4> USB OTG:On The Go,正在进行中的意思,也就是可以直接传输,就是可以从一个机器直接传到另一个机器中。
5> USB HUB:USB扩展/集线器,一种可以将一个USB接口扩展为多个(通常为4个),并可以使这些接口同时使用的装置。

我总结一下:Android TV上提供USB插口,Android TV是USB Host(包含协议,是主设备),插在插口上的USB Device为USB Client。如果一个插口上插了个USB分线器,这个是USB HUB。USB Client与USB Host之间进行数据交换叫做OTG。
2. Check your device surpport USB Host or not.
怎么检查呢?
1> 使用ES或RE文件浏览器,进入 /system/etc/permissions 目录下,查看是否有 android.hardware.usb.host.xml 文件。
2> 若有那么OK。没有的话自己创建一个同名的文件,在文件中写入:

<permissions>
            <feature name="android.hardware.usb.host />
     </permissions>

3> 最好检查一下: /system/etc/permissions 目录下
手机:handheld_core_hardware.xml
平板/TV:tablelet_core_hardware.xml
文件中的< permissions >< /permissions >节点下是否第2>点中的那句话,没有的话可以考虑加一下。(Google官方说不加且有第1>点中的文件是没问题的。)

二、USB Host 的Android工程Demo编写

  1. 新建一个Android 工程,在清单配置文件中设置应用的USB Host权限(注意:此处是应用的权限,之前第一点是设备的硬件支持)
<uses-feature
        android:name="android.hardware.usb.host"
        android:required="true" />

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

另外,需要在< application>的某个< activity>节点中添加意图过滤(Intent-Fliter)、中继数据(meta-data),具体如下:

<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" />

注意:此处是重点:
1) 意图过滤表示的是 硬件USB设备依附的动作意图;
2) 中继数据表示的是 关联res/xml文件夹下的device_filter.xml文件,因此需要在对应的目录下创建这个文件,并且在此文件中编写代码(表示的是你的应用要获取的指定的USB设备的数据),我的是这样的:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <usb-device vendor-id="11021" product-id="257" />
    <usb-device vendor-id="11020" product-id="513" />
</resources>

这里的vendor_id也好、 product_id也好,一定要写你自己需要获取数据的设备的id。

2.Java代码部分。
1) 需要知道的几个类:UsbManager、UsbDevice、UsbInterface、UsbDeviceConnection、UsbEndPoint这几个类。

大概介绍一下(想详细了解可以参考AndroidDevelopers官方网站):
UsbManager:USB管理器,是获得USB设备,进行数据交换的最基本的类。
UsbDevice:表示USB设备的一个类。
UsbDeviceConnection:表示USB设备连接的类
UsbInterface:连接的USB设备的接口(类似Channel),表示数据是从哪个通道传递过来的。下面是一些通用的基本操作:

// 创建USB管理器对象
UsbManager mUsbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
// 获得被USB管理器管理的所有设备
HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
// 查看管理器是否对某个USB设备有管理权限
mUsbManager.hasPermission(mUsbDevice)
// 获得USB数据传输的通道
UsbInterface intf = mUsbDevice.getInterface(index);

2) 数据接收类(根据业务需求封装的类) —— HidUsb.java
重磅干货来袭!!!

public class HidUsb {
    private static final String TAG = HidUsb.class.getSimpleName();
    private Context mContext;
    private UsbManager mUsbManager;
    private UsbDevice mUsbDevice;
    private UsbInterface mInterface;
    private UsbDeviceConnection mDeviceConnection;
    private UsbEndpoint mEpOut;
    private UsbEndpoint mEpIn;
    //主线程消息处理器
    private Handler mHandler;
    //工作线程消息处理器
    private HandlerThread mHandlerThread;
    private HidListener mListener;
    private Handler mHidHandler;

    public HidUsb(Context context) { 
        Log.i(TAG, "The construction method of HidUsb had been executed!");
        mContext = context;
        mUsbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
        start();
    }

    public void release() {
        stop();
    }

    /**
     * 此方法用来设置监听器
     *
     * @param listener
     */
    public void setListener(HidListener listener) {
        mListener = listener;
    }

    /**
     * 此方法用来开启HID
     */
    public void openHID() {
        // 关闭HID
        closeHID();
        // 判断是否是要求的设备
        enumerateDevice();
        // 判断是否有使用USB HOST的权限。
        if (hasPermission()) {
            // 有权限则连接HID设备
            // TODO 此处仍有提升空间connectHID() 和 openDevice() 方法都返回布尔值,返回false需要进行什么处理
            connectHID();
        } else {
            // 没有权限则获得权限
            obtainPermission();
        }
    }

    /**
     * 此方法用来连接HID设备
     */
    private boolean connectHID() {
        // 找到接口,将找到的指定接口的代号赋给成员变量mInterface
        findInterface();
        // 分配端节点,给端节点赋值
        assignEndpoint();
        // 返回打开HID设备
        return openDevice();
    }

    public void closeHID() {
        if (mDeviceConnection != null) {
            mDeviceConnection.releaseInterface(mInterface);
            mDeviceConnection.close();
        }
        mDeviceConnection = null;
        mUsbDevice = null;
        mInterface = null;
    }


    /**
     * 查找device,找到指定的HidUsb设备
     */
    private void enumerateDevice() {
        Log.v(TAG, "enumerateDevice.");
        if (mUsbManager != null) {
            Log.d(TAG, "enumerateDevice2");
            HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();

            if (!deviceList.isEmpty()) {
                Iterator deviceIterator = deviceList.values().iterator();

                while (deviceIterator.hasNext()) {
                    UsbDevice device = (UsbDevice) deviceIterator.next();
                    Log.v(TAG, "device = " + device);
                    // 获得USB设备列表,判断是否是要求的USB设备
                    if (isYourRequiredDevice(device)) {
                        // 是要求的USB 设备的情况下,将此设备赋值给成员变量 mUsbDevice
                        mUsbDevice = device;
                        Log.d(TAG, "enumerateDevice: Get Device OK.");
                        break;
                    }
                }
            } else {
                Log.e(TAG, "enumerateDevice: Device list is null !!!");
            }
        } else {
            Log.e(TAG, "enumerateDevice: USB manager is null !!!");
        }
        // 否则报出错误是设备是空、或者设备管理器是空等
    }

    /**
     * 是否有权限
     *
     * @return true if caller has permission
     */
    private boolean hasPermission() {
        if (mUsbDevice != null) {
            return mUsbManager.hasPermission(mUsbDevice);
        }
        return false;
    }

    /**
     * 获取权限
     */
    private void obtainPermission() {
        if (mUsbDevice != null) {
            PendingIntent mPermissionIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(Constants.ACTION_USB_PERMISSION), 0);
            mUsbManager.requestPermission(mUsbDevice, mPermissionIntent);
        }
    }

    private void findInterface() {
        // 如果成员变量mUsbDevice不是空(参考enumerateDevice方法)时,
        // 获得Usb设备的接口(通道)的数目,在所有接口中找到
        if (mUsbDevice != null) {
            int intfCount = mUsbDevice.getInterfaceCount();
            for (int i = 0; i < intfCount; ++i) {
                UsbInterface intf = mUsbDevice.getInterface(i);
                int intfClass = intf.getInterfaceClass();
                int intfSubClass = intf.getInterfaceSubclass();
                int intfProtocol = intf.getInterfaceProtocol();
                if (是你要的通道) {
                   // TODO
                }
            }
        }
    }

    private void assignEndpoint() {
        // 如果指定的端口代号不是空,获得EndPoint的数目
        // 找出指定的端节点,设置成员变量EndPointOut/EndPointIn
        if (mInterface != null) {
            int epCount = mInterface.getEndpointCount();
            for (int i = 0; i < epCount; ++i) {
                UsbEndpoint ep = mInterface.getEndpoint(i);
                int epType = ep.getType();
                int epDir = ep.getDirection();
                if (epType == 指定的端节点) {
                    // TODO 
                }
            }
        }
    }

    /**
     * 打开device
     *
     * if(接口代号不为空){
     *     if(USB设备管理器有制定设备的管理权限){
     *         初始化USB设备连接;
     *     }
     *
     *     // 表示有权限或者没权限初始化了连接
     *     if(USB设备连接仍然为空){
     *         说明无法连接指定的USB设备;
     *         return false;
     *     }
     *
     *     // 表示连接不是空
     *     if(申明接口){
     *         重新发送消息,执行任务;
     *         return true;
     *     }
     *
     * }else{
     *     // 表示接口代号为空
     *     if(连接不为空){
     *         // 表示连接了设备,这个设备却没有接收数据的接口
     *         关闭连接;
     *         return false;
     *     }
     *
     *     return false;
     * }
     */
    private boolean openDevice() {
        if (mInterface != null) {
            UsbDeviceConnection conn = null;
            if (mUsbManager.hasPermission(mUsbDevice)) {
                conn = mUsbManager.openDevice(mUsbDevice);
            }
            Log.d(TAG, "conn = " + conn);
            if (conn == null) {
                Log.e(TAG, "open device null!!!");
                return false;
            }
            if (conn.claimInterface(mInterface, true)) {
                mDeviceConnection = conn;
                Log.d(TAG, "open device OK.");
                mHandler.removeCallbacks(mRunnable);
                mHandler.post(mRunnable);
                return true;
            } else {
                if (conn != null) {
                    conn.close();
                }
                Log.e(TAG, "open device Error!!!");
            }
        }
        return false;
    }

    private void start() { 
        Log.i(TAG, "start method running!");
        // 1.创建了一个关联当前线程(主线程)的Handler
        mHandler = new Handler();
        // 2.创建了一个自带Handler的工作线程,并启动线程
        mHandlerThread = new HandlerThread("Hid_Thread");
        mHandlerThread.start();
        // 3.获得了工作线程的Handler对象
        mHidHandler = new Handler(mHandlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    // 收到GET_DATA_MSG消息时执行
                    case GET_DATA_MSG:
                        try {
                            // 调用getData方法
                            final long gd = getData();
                            // 判断获得的数据不为0,监听器不为空,主线程的Handler不为空时执行
                            // 向主线程发送消息,调用监听器的onCodeReceive方法
                            if (gd != 0 && mListener != null && mHandler != null) {
                                mHandler.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        mListener.onCodeReceive(gd);
                                    }
                                });
                            }
                        } catch (NullPointerException e) {
                            // 抓去空指针异常
                            e.printStackTrace();
                            // 休眠50毫秒
                            Thread.sleep(50);
                        } catch (InterruptedException e2) {
                                e2.printStackTrace();
                        }

                        // 4.移除主线程任务队列中的可执行任务
                        if(mHandler!=null) {
                            mHandler.removeCallbacks(mRunnable);
                            // 5.向主消息队列中放置任务
                            mHandler.post(mRunnable);
                        }
                        break;
                    default:
                        break;
                }
            }
        };
    }

    private Runnable mRunnable = new Runnable() {
        @Override
        public void run() {
            // 当主线程Handler不为空时执行清空消息队列中的消息,并发送GET_DATA_MSG消息。
            if (mHidHandler != null) {
                mHidHandler.removeMessages(GET_DATA_MSG);
                mHidHandler.sendEmptyMessage(GET_DATA_MSG);
            }
        }
    };


    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
    private void stop() {
        mHandler.removeCallbacks(mRunnable);
        mHandler = null;
        if (mHandlerThread != null) {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
                mHandlerThread.quit();
            } else {
                mHandlerThread.quitSafely();
            }
            mHandlerThread = null;
            mHidHandler = null;
        }
    }

    private long getData() {
       return 你从底层获得的数据
    }

    private boolean isYourRequiredDevice(UsbDevice device) {
        return 根据vendorid productid判断是否是你要的USB设备
    }

    /**
     * 这是一个监听器接收数据的接口
     */
    public interface HidListener {
        void onCodeReceive(long code);
    }
}

3.在页面中获得数据 MainActivity.java

public class  MainActivity extends Activity implements HidUsb.HidListener {
    private static final String TAG = MainActivity.class.getSimpleName();

    private HidUsb mHidUsb;

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

    private void onInitUsb() {
        mHidUsb = new HidUsb(this);
        mHidUsb.setListener(this);
        mHidUsb.openHID();
    }

    @Override
    public void onCodeReceive(long code) {
        // TODO
    }
}

我觉得注释写的还算清楚就不解释了~~~
————————————————————————