现在,Android提供了USB Host,可以使安卓智能手机支持读取任何USB Host。
我正在尝试使用USB Host提供的这些类来访问智能卡中的数据。
我的代码用于检测任何USB Host:
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
PendingIntent mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbReceiver, filter);
IntentFilter attachedFilter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED);
registerReceiver(mUsbAttachedReceiver, attachedFilter);
private final BroadcastReceiver mUsbAttachedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Utils.writeStringToTextFile("\n1 .Get an action : " + action, FileName);
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
synchronized (this) {
device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device != null) {
showToast("Plugged In");
mUsbManager.requestPermission(device, mPermissionIntent);
}
}
} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device != null) {
showToast("Plugged Out");
// call your method that cleans up and closes communication with the device
}
}
}
};
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) {
device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
if (device != null) {
//call method to set up device communication
Utils.writeStringToTextFile("2 .Get an action : " + action + "\nDevice is : " + device, FileName);
showToast("Permission Granted for device");
Handler h = new Handler();
h.postDelayed(run, 1000);
}
} else {
showToast("Permission denied for device" + device);
}
}
}
}
};
当我获取到UsbDevice device
时,一切都按预期运行,它提供了设备的信息,例如:
Device is : UsbDevice[mName=/dev/bus/usb/001/002,mVendorId=1899,mProductId=12322,mClass=0,mSubclass=0,mProtocol=0,mManufacturerName=OMNIKEY AG,mProductName=Smart Card Reader USB,mVersion=2.0,mSerialNumber=null,mConfigurations=[
UsbConfiguration[mId=1,mName=CCID,mAttributes=160,mMaxPower=50,mInterfaces=[
UsbInterface[mId=0,mAlternateSetting=0,mName=null,mClass=11,mSubclass=0,mProtocol=0,mEndpoints=[
UsbEndpoint[mAddress=131,mAttributes=3,mMaxPacketSize=8,mInterval=24]
UsbEndpoint[mAddress=132,mAttributes=2,mMaxPacketSize=64,mInterval=0]
UsbEndpoint[mAddress=5,mAttributes=2,mMaxPacketSize=64,mInterval=0]]]]
现在我正在尝试使用
UsbDevice device
从卡中提取数据和详细信息,但我没有成功,并且我找不到任何有用的帖子。我知道我必须使用
UsbInterface
、UsbEndpoint
、UsbDeviceConnection
来获取我想要的东西,但我无法做到。另外,我也找不到任何示例或类似的东西。有人能指点我一下吗?
对不起,帖子太长了,先谢谢:)
编辑: 感谢Mr. Michael Roland,我能够阅读关于CCID的内容,因为读卡器设备通过USB接口使用CCID。
所以我使用了以下代码:
UsbDeviceConnection connection = mUsbManager.openDevice(device);
UsbEndpoint epOut = null, epIn = null;
for (int i = 0; i < device.getInterfaceCount(); i++) {
UsbInterface usbInterface = device.getInterface(i);
connection.claimInterface(usbInterface, true);
for (int j = 0; j < usbInterface.getEndpointCount(); j++) {
UsbEndpoint ep = usbInterface.getEndpoint(j);
showToast("Endpoint is : " + ep.toString() + " endpoint's type : " + ep.getType() + " endpoint's direction : " + ep.getDirection());
Log.d(" ", "EP " + i + ": " + ep.getType());
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
epOut = ep;
} else if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
epIn = ep;
}
}
}
int dataTransferred = 0;
byte[] PC_to_RDR_IccPowerOn = hexStringToByteArray("62" + "00000000" + "00" + "00" + "00" + "0000");
if (epOut != null) {
//Firstly send Power in on Bulk OUT endpoint
dataTransferred = connection.bulkTransfer(epOut, PC_to_RDR_IccPowerOn, PC_to_RDR_IccPowerOn.length, TIMEOUT);
}
StringBuilder result = new StringBuilder();
if (epIn != null) {
final byte[] RDR_to_PC_DataBlock = new byte[epIn.getMaxPacketSize()];
result = new StringBuilder();
//Secondly send Power out on Bulk OUT endpoint
dataTransferred = connection.bulkTransfer(epIn, RDR_to_PC_DataBlock, RDR_to_PC_DataBlock.length, TIMEOUT);
for (byte bb : RDR_to_PC_DataBlock) {
result.append(String.format(" %02X ", bb));
}
if (dataTransferred > 0) {
Utils.writeStringToTextFile("\n2nd buffer received was : " + result.toString(), "Card_communication_data.txt");
String s1 = Arrays.toString(RDR_to_PC_DataBlock);
String s2 = new String(RDR_to_PC_DataBlock);
showToast("received - " + s1 + " - " + s2);
} else {
showToast("received length at 2nd buffer transfer was " + dataTransferred);
}
}
}
我收到了
80 13 00 00 00 00 00 00 00 00 3B 9A 96 C0 10 31 FE 5D 00 64 05 7B 01 02 31 80 90 00 76 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
,但我仍然不确定如何处理数据字段:ATR,或者如何为PC_to_RDR_XfrBlock
命令组成Command APDU
。我认为我应该现在将命令APDU包装到
PC_to_RDR_XfrBlock
命令中发送; 有人能帮我吗?
编辑2:我弄清楚了ATR的含义和如何形成命令APDU。
但是现在我应该切换协议。
默认协议是T=0。为了设置T=1协议,设备必须向卡发送PTS(也称为PPS)。 由于卡需要同时支持T=0和T=1协议,因此协议切换的基本PTS对于卡是必需的。 PTS可以用于根据ISO/IEC 7816-3中的指示,在存在任何(TA(1)字节)的情况下,切换到比卡在ATR中提出的默认波特率更高的波特率。
我不确定这意味着什么,以及如何实现它!
write(connection, epOut, "62000000000000000000")
返回36 32 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30
。 - Abdulkarim Kanaan