下面的流程在非Android O系统版本的手机中运行正常,在Android O连接USB2.0时也运行正常,仅在Android O连接USB3.0/3.1时,第一个指令的发送接收也正常, 然而第二个指令发送就失败了, 返回-1, 尝试过把发送时的bulkTransfer方法的第三个参数(即数据长度)修改为EndPoint的MaXPacketSize, 接收时的bulkTransfer方法的第三个参数修改为接收到数据的大小, 在我的使用中为0x0c, 这样第二个指令就可以正常发送接收, 但是第三个指令还是会发送失败, 可能跟这个有关, 但是最多就发送成功了两个指令
寻找USB设备
val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager
//this method just filter the vendorId of device
val dev = lookupCompatibleDevice(usbManager) ?: return
申请权限
if (usbManager.hasPermission(dev)){
//if has permission already
connect(context, dev)
}else {
//request permission and connect device in receiver
registerPermissionReceiver(context)
val mPermissionIntent = PendingIntent.getBroadcast(context, 0, Intent(
ACTION_USB_PERMISSION), 0)
usbManager.requestPermission(dev, mPermissionIntent)
}
获取EndPoint
fun connect(context: Context, device: UsbDevice){
val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager
var intf : UsbInterface? = null
(0 until (device.interfaceCount)).forEach {
val i = device.getInterface(it)
if (i.interfaceClass == UsbConstants.USB_CLASS_STILL_IMAGE){
intf = i
}
}
if (intf == null){
//PTP interface not found
connectListener.onConnectStateChange(ConnectState.NO_PTP_INTERFACE)
return
}
if (device.interfaceCount > 1){
connectListener.onConnectStateChange(ConnectState.MULTI_INTERFACE)
return
}
val conn = usbManager.openDevice(device) ?: return
if (conn.claimInterface(intf, true)){
Log.i(TAG, "claim interface successful")
}else {
Log.i(TAG, "claim interface failure")
}
var bulkIn: UsbEndpoint? = null
var bulkOut: UsbEndpoint? = null
(0 until (intf!!.endpointCount)).forEach {
val endpoint = intf!!.getEndpoint(it)
Log.d(TAG, "connect: endpoint type: " + endpoint.type + "direction: " + endpoint.direction)
if (endpoint.type == UsbConstants.USB_ENDPOINT_XFER_BULK) {
if (endpoint.direction == UsbConstants.USB_DIR_IN) {
bulkIn = endpoint
} else if (endpoint.direction == UsbConstants.USB_DIR_OUT) {
bulkOut = endpoint
}
}
}
if (bulkIn == null || bulkOut == null) {
//
connectListener.onConnectStateChange(ConnectState.BULK_NOT_ENOUGH)
return
}
if (AppConfig.LOG) {
Log.i(TAG, "Found compatible USB interface")
Log.i(TAG, "Interface class " + intf?.interfaceClass)
Log.i(TAG, "Interface subclass " + intf?.interfaceSubclass)
Log.i(TAG, "Interface protocol " + intf?.interfaceProtocol)
Log.i(TAG, "Bulk out max size " + bulkOut?.maxPacketSize)
Log.i(TAG, "Bulk in max size " + bulkIn?.maxPacketSize)
}
val connection = UsbConnection(context.applicationContext, device.vendorId, conn, bulkOut!!, bulkIn!!, object : Connection.ConnectStateListener {
override fun onConnectStateChange(state: ConnectState) {
connectListener.onConnectStateChange(state)
if (state.state < ConnectState.WIFI_ACKNOWLEDGED.state){
CameraHolder.disconnectCamera(context)
}
}
})
when(device.vendorId){
CanonVendorId -> { camera = CanonCamera(context, connection, cameraListener) }
NikonVendorId -> { camera = NikonCamera(context, connection, cameraListener) }
SonyVendorId -> { camera = SonyCamera(context, connection, cameraListener) }
else -> { camera = Camera(context, connection, cameraListener) }
}
connectListener.onConnectStateChange(ConnectState.USB_CONNECTED)
}
the UsbConnection class just pack the EndPoints
发送指令
fun send(): Int {
if (AppConfig.LOG_PACKETS){
PacketUtil.logHexdump(TAG, byteBuffer.array(), byteBuffer.position(), byteBuffer.limit())
}
val res = connection.bulkTransfer(bulkOut, byteBuffer.array(), byteBuffer.limit(), timeout)
return res
}
the bytebuffer contains the data that needs to be send
接收指令
res = connection.bulkTransfer(bulkIn, `in`.array(), maxPacketSize, AppConfig.USB_TRANSFER_TIMEOUT)
Any help will be appreciated..