USB开发------android AOA开发
android AOA开发
Android从3.1版本可开始引进了对AOA的支持,这是一种允许外部USB硬件与Android设备进行交互的特殊Accessory模式。当一个Android设备处于Accessory模式的时候,已连接的配件则扮演Host的角色(负责给总线供电并且枚举设备),而Android设备则扮演USB device的角色。Android USB配件是一个专门设计的附加到Android 设备上,并实现了一个简单的协议(AOA),使他们能够检测支持Accessory模式的Android设备。配件还必须提供500ma的5V供电电源。许多以前发布的Android设备只能充当USB设备,不能用来与外部USB设备的连接通讯。AOA的支持克服了这个限制。accessory模式最终依赖于硬件设备,并且不是所有的设备都支持Accessory模式。如果设备支持Accessory模式的话,可以在应用的AndroidManifest中使用 uses-feature 元素来标记。
- AOA的检测与连接流程
- 代码实现
AOA的检测与连接流程
一个USB配件必须遵循AOA协议,这个协议定义了一个配件如何发现并且与设备建立通讯,通常情况下,一个配件应该按照以下步骤:
- 等待发现连接的设备
- 确定设备是否支持Accessory模式
- 尝试让配件切换到Accessory模式
- 建立通讯,如果设备支持AOA协议
连接流程如下:
当设备连接时,他们应该在以下三种状态中的一种:
1.已Attached的设备支持Accessory模式,并且已经处于此模式
2.已Attached的设备支持Accessory模式,但不处于此模式
3.设备不支持Accessory模式
当建立连接之后,配件应该检查连接的设备的VID和PID。google固定了AOA设备的VID与PID,如果PID跟VID匹配的话,那么就可以使用USB的块传输的endpoints建立配件与设备之间的通讯。
AOA 设备VID = 0x18D1, PID有多种,其中包括AOA 2.0中新增的,分别对应的关系如下:
PID | 模式 |
---|---|
0x2D00 | accessory |
0x2D01 | accessory + adb |
0x2D02 | audio |
0x2D03 | audio + adb |
0x2D04 | accessory + audio |
0x2D05 | accessory + audio + adb |
如果VID跟PID不匹配,那么我们就需要请求设备切换为Accessory模式,这时候需要发送51号命令控制请求来确定设备是否支持Android附件协议。如果支持协议,则返回非零数,表示设备支持的协议版本。此请求是端点0上的控制请求,其特征如下:
参数 | 值 |
---|---|
requestType | USB_DIR_IN 或者 USB_TYPE_VENDOR |
request | 51 |
value | 0 |
index | 0 |
data | 协议版本号 |
如果设备返回支持的协议版本号,则向设备发送标识字符串信息。该信息允许设备为该附件找出合适的应用程序,并且如果不存在适当的应用程序,则向用户指示下载的URL地址。这些请求是端点0(对于每个字符串ID)的52号命令控制请求,具有以下特征:
参数 | 值 |
---|---|
requestType | USB_DIR_OUT 或者 USB_TYPE_VENDOR |
request | 52 |
value | 0 |
index | stringID |
data | UTF-8字符 |
stringID定义如下(每个字符串最大长度为256,以/0结尾):
参数 | 描述 | 值 |
---|---|---|
manufacturer name | 制造商 | 0 |
model name | 型号 | 1 |
description | 描述 | 2 |
version | 版本 | 3 |
URI | 下载路径 | 4 |
serial number | 序列号 | 5 |
发送string ID后,使用53号控制命令请求设备在accessory模式下启动,使用如下命令:
参数 | 值 |
---|---|
requestType | USB_DIR_OUT 或者 USB_TYPE_VENDOR |
request | 53 |
value | 0 |
index | 0 |
data | none |
在AOA 2.0协议中,增加了对Audio的支持,将设备设置为音频模式(此命令必须在发送53号命令之前发送),控制请求描述如下:
参数 | 值 |
---|---|
requestType | USB_DIR_OUT 或者 USB_TYPE_VENDOR |
request | 58 |
value | 0 for no audio (default), 1 for 2 channel, 16-bit PCM at 44100 KHz |
index | 0 |
data | none |
代码实现
package com.zdragon.videoio;import android.app.PendingIntent;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.hardware.usb.UsbConstants;import android.hardware.usb.UsbDevice;import android.hardware.usb.UsbDeviceConnection;import android.hardware.usb.UsbManager;import android.os.Handler;import android.os.HandlerThread;import android.os.Looper;import android.os.Message;import android.util.Log;import java.io.UnsupportedEncodingException;/** * Created by GaddiZou on 2018/8/5 0005. */public class UsbTest { private final static String MANUFACTURER_NAME = "AoA Test MA"; private final static String MODEL_NAME = "AOA Test Model"; private final static String DESCRIPTION = "Description"; private final static String VERSION = "ver1.0"; private final static String URI = "http://www.downloadapk.com"; private final static String SERIAL = "111111111111111111"; private final static String REQUEST_PERMISSION_ACTION = "com.test.usb"; private UsbManager mUsbManager; private PendingIntent mPendingIntent; private HandlerThread mHandlerThread = new HandlerThread("usb-handler"); private UsbHandler mUsbHandler; private class UsbHandler extends Handler { public final static int MSG_REQUEST_PERMISSION = 0; public final static int MSG_USB_ATTACHED = 1; public final static int MSG_USB_DETACHED = 2; public UsbHandler(Looper looper){ super(looper); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); int what = msg.what; UsbDevice device = (UsbDevice) msg.obj; switch(what){ case MSG_REQUEST_PERMISSION: if (mUsbManager.hasPermission(device)) { switchToAoAMode(device); } else { //No permission } break; case MSG_USB_ATTACHED: //TODO break; case MSG_USB_DETACHED: //TODO break; } } } private BroadcastReceiver mUsbDeviceEventReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); Message msg = mUsbHandler.obtainMessage(); msg.obj = device; if(action.equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)){ msg.what = UsbHandler.MSG_USB_ATTACHED; } else if(action.equals(UsbManager.ACTION_USB_ACCESSORY_DETACHED)){ msg.what = UsbHandler.MSG_USB_DETACHED; } else if(action.equals(REQUEST_PERMISSION_ACTION)){ msg.what = UsbHandler.MSG_REQUEST_PERMISSION; } mUsbHandler.sendMessage(msg); } }; public UsbTest(Context context){ mHandlerThread.start(); mUsbHandler = new UsbHandler(mHandlerThread.getLooper()); mUsbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); intentFilter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED); intentFilter.addAction(REQUEST_PERMISSION_ACTION); context.registerReceiver(mUsbDeviceEventReceiver, intentFilter); mPendingIntent = PendingIntent.getBroadcast(context,0, new Intent(REQUEST_PERMISSION_ACTION), 0); } public void usbRequestPermission(UsbDevice usbDevice){ if(usbDevice == null){ return; } mUsbManager.requestPermission(usbDevice, mPendingIntent); } public void switchToAoAMode(UsbDevice usbDevice){ if(usbDevice.getVendorId() == 0x18D1 && (usbDevice.getProductId() == 0x2D00 || usbDevice.getProductId() == 0x2D01 || usbDevice.getProductId() == 0x2D02 || usbDevice.getProductId() == 0x2D03 || usbDevice.getProductId() == 0x2D04 || usbDevice.getProductId() == 0x2D05 )){ //UsbDevice in AOA mode. sendAccessoryInfo(usbDevice); }else{ UsbDeviceConnection udc = mUsbManager.openDevice(usbDevice); byte [] datas = new byte[2]; int ret = udc.controlTransfer(UsbConstants.USB_DIR_IN, 51, 0,0, datas, 1, 0); if(ret > 0 && datas[0] == 1){ //device has been switch to support AOA sendAccessoryInfo(usbDevice); }else{ //device not support AOA } } } public void sendAccessoryInfo(UsbDevice usbDevice){ UsbDeviceConnection udc = mUsbManager.openDevice(usbDevice); int ret = -1; try { byte [] datas = MANUFACTURER_NAME.getBytes("utf-8"); ret = udc.controlTransfer(UsbConstants.USB_DIR_OUT, 52, 0,0, datas, datas.length, 0); if(ret < 0){ return; } datas = MODEL_NAME.getBytes("utf-8"); ret = udc.controlTransfer(UsbConstants.USB_DIR_OUT, 52, 0,1, datas, datas.length, 0); if(ret < 0){ return; } datas = DESCRIPTION.getBytes("utf-8"); ret = udc.controlTransfer(UsbConstants.USB_DIR_OUT, 52, 0,2, datas, datas.length, 0); if(ret < 0){ return; } datas = VERSION.getBytes("utf-8"); ret = udc.controlTransfer(UsbConstants.USB_DIR_OUT, 52, 0,3, datas, datas.length, 0); if(ret < 0){ return; } datas = URI.getBytes("utf-8"); ret = udc.controlTransfer(UsbConstants.USB_DIR_OUT, 52, 0,4, datas, datas.length, 0); if(ret < 0){ return; } datas = SERIAL.getBytes("utf-8"); ret = udc.controlTransfer(UsbConstants.USB_DIR_OUT, 52, 0,5, datas, datas.length, 0); if(ret < 0){ return; } //After send info ok, we start up accessory. udc.controlTransfer(UsbConstants.USB_DIR_OUT, 53, 0,0, null, 0, 0); } catch (UnsupportedEncodingException e) { Log.e("ERROR", Log.getStackTraceString(e)); } }}
更多相关文章
- Linux与Android的关系
- Android技术架构演进与未来
- Android当中的MVP模式(三)基于分页列表的封装
- 图解IntelliJ IDEA 13版本对Android(安卓)SQLite数据库的支持
- 手机和平板之外——带你理解跨设备的Android(安卓)技术体系
- 移动设备操作系统知识点简摘又名我的期末考试复习第二弹
- Android(安卓)KitKat 4.4平台开发-添加USB ADB和MTP功能支持
- Android开发的前景分析――之你为何看好Android?
- 如何在Android和iOS设备上录制游戏?