IDTech Unimag Card Swiper on Android
android, android-2.3-gingerbread, credit-card
Solution
Here's what I used with the UniMag. Using a handler to output the swiped data, and a 'Swipe' button to start the swiping. To improve, one should wait until the card reader reports it is connected / ready to swipe, then enable the button, disable while waiting for swipe, and re-enable after receiving data.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import IDTech.MSR.XMLManager.StructConfigParameters;
import IDTech.MSR.uniMag.uniMagReader;
import IDTech.MSR.uniMag.uniMagReaderMsg;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity implements uniMagReaderMsg {
private uniMagReader myUniMagReader = null;
private Button btnSwipe;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(myUniMagReader == null) {
myUniMagReader = new uniMagReader(this,this);
myUniMagReader.setSaveLogEnable(false);
myUniMagReader.setXMLFileNameWithPath(null);
myUniMagReader.loadingConfigurationXMLFile(true);
//myUniMagReader.setVerboseLoggingEnable(true);
myUniMagReader.registerListen();
}
btnSwipe = (Button) findViewById(R.id.button1);
btnSwipe.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
myUniMagReader.startSwipeCard();
}
});
}
@Override
public void onDestroy() {
myUniMagReader.stopSwipeCard();
myUniMagReader.unregisterListen();
myUniMagReader.release();
super.onDestroy();
}
@Override
public boolean getUserGrant(int arg0, String arg1) {
Log.d("UniMag", "getUserGrant -- " + arg1);
return true;
}
@Override
public void onReceiveMsgAutoConfigProgress(int arg0) {
// TODO Auto-generated method stub
Log.d("UniMag", "onReceiveMsgAutoConfigProgress");
}
@Override
public void onReceiveMsgCardData(byte arg0, byte[] arg1) {
Log.d("UniMag", "onReceiveMsgCardData");
Log.d("UniMag", "Successful swipe!");
String strData = new String(arg1);
Log.d("UniMag", "SWIPE - " + strData);
if(myUniMagReader.isSwipeCardRunning()) {
myUniMagReader.stopSwipeCard();
}
// Match the data we want.
String pattern = "%B(\\d+)\\^([^\\^]+)\\^(\\d{4})";
Log.d("UniMag", pattern);
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(strData);
String card = "";
String name = "";
String exp = "";
String data = "";
if(m.find()) {
for(int a = 0; a < m.groupCount(); ++a) {
Log.d("UniMag", a + " - "+m.group(a));
}
card = m.group(1);
name = m.group(2);
exp = m.group(3);
data = "Data: " + name + " -- " + card + " -- " + exp;
Log.d("UniMag", data);
Message msg = new Message();
msg.obj = data;
swipeHandler.sendMessage(msg);
}
}
final Handler swipeHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
String text = (String)msg.obj;
TextView dataView = (TextView) findViewById(R.id.text_view);
dataView.setText(text);
}
};
@Override
public void onReceiveMsgCommandResult(int arg0, byte[] arg1) {
Log.d("UniMag", "onReceiveMsgCommandResult");
}
@Override
public void onReceiveMsgConnected() {
Log.d("UniMag", "onReceiveMsgConnected");
Log.d("UniMag", "Card reader is connected.");
}
@Override
public void onReceiveMsgDisconnected() {
Log.d("UniMag", "onReceiveMsgDisconnected");
if(myUniMagReader.isSwipeCardRunning()) {
myUniMagReader.stopSwipeCard();
}
myUniMagReader.release();
}
@Override
public void onReceiveMsgFailureInfo(int arg0, String arg1) {
Log.d("UniMag","onReceiveMsgFailureInfo -- " + arg1);
}
@Override
public void onReceiveMsgSDCardDFailed(String arg0) {
Log.d("UniMag", "onReceiveMsgSDCardDFailed -- " + arg0);
}
@Override
public void onReceiveMsgTimeout(String arg0) {
Log.d("UniMag", "onReceiveMsgTimeout -- " + arg0);
Log.d("UniMag","Timed out!");
}
@Override
public void onReceiveMsgToConnect() {
Log.d("UniMag","Swiper Powered Up");
}
@Override
public void onReceiveMsgToSwipeCard() {
Log.d("UniMag","onReceiveMsgToSwipeCard");
}
@Override
public void onReceiveMsgAutoConfigCompleted(StructConfigParameters arg0) {
Log.d("UniMag", "onReceiveMsgAutoConfigCompleted");
}
}
Problem
I've been working on Android (v2.3) for a couple of weeks now, and I've stumbled upon some problems with the Unimag Card Swiper from IDTECH. The unit comes with a scarce documentation and the demo app from the SDK implements the firmware update and a few classes for dialogs and such which really offuscate how to achieve basic functionality (added to the few and not so good comments in the code). I have implemented the interface in a basic activity and tried to detect when the unit is connected or disconnected but it seems the listener catches both events (connection/disconnection) as "disconnect", let alone trying to read a card. Has anyone worked with this unit on Android and has some clear examples? By the way, here is my class: ``` package com.card.swipe; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import IDTech.MSR.uniMag.uniMagReader; import IDTech.MSR.uniMag.uniMagReaderMsg; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.TextView; import android.widget.Toast; public class CardSwipeTestActivity extends Activity implements uniMagReaderMsg { private uniMagReader myUniMagReader = null; private TextView etCardData; private String _strMSRData = null; private byte[]_MSRData = null; private String _strStatus = null; private int _nGetChallengeResult = 0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // InitializeUI(); InitializeReader(); String strManufacture = myUniMagReader.getInfoManufacture(); String strModel = myUniMagReader.getInfoModel(); String strSDKVerInfo = myUniMagReader.getSDKVersionInfo(); String strOSVerInfo = android.os.Build.VERSION.RELEASE; etCardData = (TextView)findViewById(R.id.text_view); etCardData.setText("Phone: "+strManufacture+"\n"+"Model: "+strModel+"\n"+"SDK Ver: "+strSDKVerInfo+"\nOS Version: "+strOSVerInfo); } @Override protected void onPause() { // TODO Auto-generated method stub if(myUniMagReader!=null) { //you should stop swipe card and unregister when the application go to background myUniMagReader.stopSwipeCard(); // myUniMagReader.unregisterListen(); // myUniMagReader.release(); } super.onPause(); } @Override protected void onResume() { // TODO Auto-generated method stub // you should register to listen the headset event when the application resumed. // if(myUniMagReader!=null) // { //// myUniMagReader.registerListen(); // if(_bCheckedSaveLogItem==true) // myUniMagReader.setSaveLogEnable(true); // else // myUniMagReader.setSaveLogEnable(false); // } // if(itemStartSC!=null) // itemStartSC.setEnabled(true); // waitingCommandResult=false; super.onResume(); } @Override protected void onDestroy() { myUniMagReader.release(); super.onDestroy(); android.os.Process.killProcess(android.os.Process.myPid()); } //********************************************************************************// @Override public boolean getUserGrant(int arg0, String arg1) { // TODO Auto-generated method stub return false; } @Override public void onReceiveMsgAutoConfigProgress(int arg0) { // TODO Auto-generated method stub } @Override public void onReceiveMsgCardData(byte arg0, byte[] arg1) { // TODO Auto-generated method stub Log.d("SWIPE", "Card swiped!"); Toast.makeText(getApplicationContext(), "Card swiped!", Toast.LENGTH_SHORT).show(); } @Override public void onReceiveMsgCommandResult(int arg0, byte[] arg1) { // TODO Auto-generated method stub } @Override public void onReceiveMsgConnected() { Log.d("CONNECTION","Swiper Connected"); Toast.makeText(getApplicationContext(), "Swiper Connected!", Toast.LENGTH_SHORT).show(); } @Override public void onReceiveMsgDisconnected() { Log.d("CONNECTION","Swiper Disconnected"); Toast.makeText(getApplicationContext(), "Swiper Disconnected!", Toast.LENGTH_SHORT).show(); } @Override public void onReceiveMsgFailureInfo(int arg0, String arg1) { // TODO Auto-generated method stub Log.d("CONNECTION","Swiper Failure"); } @Override public void onReceiveMsgSDCardDFailed(String arg0) { // TODO Auto-generated method stub } @Override public void onReceiveMsgTimeout(String arg0) { Log.d("TIMEOUT","Timed out!"); Toast.makeText(getApplicationContext(), "Timed out!", Toast.LENGTH_SHORT).show(); } @Override public void onReceiveMsgToConnect() { Log.d("CONNECTION","Swiper Powered Up"); Toast.makeText(getApplicationContext(), "Swiper Powered Up", Toast.LENGTH_SHORT).show(); } @Override public void onReceiveMsgToSwipeCard() { Log.d("SWIPE","Ready to swipe!"); Toast.makeText(getApplicationContext(), "Ready to swipe!", Toast.LENGTH_SHORT).show(); } //********************************************************************************// private void InitializeReader() { if(myUniMagReader==null) myUniMagReader = new uniMagReader(this,this); myUniMagReader.setVerboseLoggingEnable(true); myUniMagReader.registerListen(); //load the XML configuratin file String fileNameWithPath = getXMLFileFromRaw(); if(!isFileExist(fileNameWithPath)) { fileNameWithPath = null; } myUniMagReader.setXMLFileNameWithPath(fileNameWithPath); myUniMagReader.loadingConfigurationXMLFile(true); myUniMagReader.setTimeoutOfSwipeCard(5); } private boolean isFileExist(String path) { if(path==null) return false; File file = new File(path); if (!file.exists()) { return false ; } return true; } private String getXMLFileFromRaw( ){ //the target filename in the application path String fileNameWithPath = null; fileNameWithPath = "idt_unimagcfg_default.xml"; try{ InputStream in = getResources().openRawResource(R.raw.idt_unimagcfg_default); int length = in.available(); byte [] buffer = new byte[length]; in.read(buffer); in.close(); deleteFile(fileNameWithPath); FileOutputStream fout = openFileOutput(fileNameWithPath, MODE_PRIVATE); fout.write(buffer); fout.close(); // to refer to the application path File fileDir = this.getFilesDir(); fileNameWithPath = fileDir.getParent() + java.io.File.separator + fileDir.getName(); fileNameWithPath = fileNameWithPath+java.io.File.separator+"idt_unimagcfg_default.xml"; } catch(Exception e){ e.printStackTrace(); fileNameWithPath = null; } return fileNameWithPath; } public void swipe(View v) { if(myUniMagReader!=null) { myUniMagReader.startSwipeCard(); } if(myUniMagReader.isSwipeCardRunning()==true) { Log.d("SWIPE","Swipe Card Running!"); } } private String getHexStringFromBytes(byte []data) { if(data.length<=0) return null; StringBuffer hexString = new StringBuffer(); String fix = null; for (int i = 0; i < data.length; i++) { fix = Integer.toHexString(0xFF & data[i]); if(fix.length()==1) fix = "0"+fix; hexString.append(fix); } fix = null; fix = hexString.toString(); return fix; } public byte[] getBytesFromHexString(String strHexData) { if (1==strHexData.length()%2) { return null; } byte[] bytes = new byte[strHexData.length()/2]; for (int i=0;i<strHexData.length()/2;i++) { bytes[i] = (byte) Integer.parseInt(strHexData.substring(i*2, (i+1)*2) , 16); } return bytes; } } ``` (There are some unimplemented methods there as well)