import of midlet code
[nfcbtpcscmidlet.git] / src / nfc / BluetoothNFCReader.java
blob002202b3cbc2d3674706327b7a84a6e30ed8cc66
1 /**
2 *
3 */
4 package nfc;
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.io.OutputStream;
9 import java.util.Vector;
11 import javax.bluetooth.BluetoothStateException;
12 import javax.bluetooth.DataElement;
13 import javax.bluetooth.DeviceClass;
14 import javax.bluetooth.DiscoveryAgent;
15 import javax.bluetooth.DiscoveryListener;
16 import javax.bluetooth.LocalDevice;
17 import javax.bluetooth.RemoteDevice;
18 import javax.bluetooth.ServiceRecord;
19 import javax.bluetooth.UUID;
20 import javax.microedition.contactless.ContactlessException;
21 import javax.microedition.contactless.DiscoveryManager;
22 import javax.microedition.contactless.TargetListener;
23 import javax.microedition.contactless.TargetProperties;
24 import javax.microedition.contactless.TargetType;
25 import javax.microedition.contactless.sc.ISO14443Connection;
26 import javax.microedition.io.Connector;
27 import javax.microedition.io.StreamConnection;
28 import javax.microedition.io.StreamConnectionNotifier;
29 import javax.microedition.lcdui.Command;
30 import javax.microedition.lcdui.CommandListener;
31 import javax.microedition.lcdui.Display;
32 import javax.microedition.lcdui.Displayable;
33 import javax.microedition.lcdui.Form;
34 import javax.microedition.lcdui.List;
35 import javax.microedition.lcdui.TextBox;
36 import javax.microedition.lcdui.TextField;
37 import javax.microedition.midlet.MIDlet;
38 import javax.microedition.midlet.MIDletStateChangeException;
41 /**
42 * @author x_beilkk
45 public class BluetoothNFCReader extends MIDlet implements TargetListener,
46 CommandListener, DiscoveryListener {
48 private Display display;
49 private Form formStart;
50 private Form formServerStart;
51 private Form formConnect;
52 private Form formDiscover;
53 private Form formReader;
54 private Form formLog;
55 private Form formError;
56 private TextField tfIn;
57 private TextField tfOut;
58 private TextField tfReadIn;
59 private TextField tfWriteOut;
60 //private TextField msgTf;
61 private Command cmdCancel;
62 private Command cmdDiscover;
63 private Command cmdSelect;
64 private Command cmdExit;
65 private Command cmdServer;
66 private Command cmdLog;
67 private Command cmdBack;
68 private Command cmdRemove;
69 private String uid;
71 /** currently selected target type. cards or tags.*/
72 private TargetType currTargetType = null;
74 /** connection to use for card communication.*/
75 private ISO14443Connection isoConn = null;
77 private DiscoveryAgent discoveryAgent;
78 private Vector devices;
80 private List deviceList;
82 private StreamConnection connection;
84 private String serviceURL;
85 private byte[] buffer;
86 //UUID SPP_UUID = new UUID("1101", true);
87 long SPP_UUID = 0x1101;
88 static int SERVICE_NAME_ATTRID = 0x0100;
90 private boolean isCardPresent = false;
92 Reader r = new Reader();
94 /* (non-Javadoc)
95 * @see javax.microedition.midlet.MIDlet#destroyApp(boolean)
97 protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
98 // TODO Auto-generated method stub
102 /* (non-Javadoc)
103 * @see javax.microedition.midlet.MIDlet#pauseApp()
105 protected void pauseApp() {
106 // TODO Auto-generated method stub
110 /* (non-Javadoc)
111 * @see javax.microedition.midlet.MIDlet#startApp()
113 protected void startApp() throws MIDletStateChangeException {
114 display = Display.getDisplay(this);
116 initCommands();
117 initForms();
119 display.setCurrent(formStart);
120 uid = "";
123 private void initCommands() {
124 cmdCancel = new Command("Cancel", Command.CANCEL, 1);
125 cmdDiscover = new Command("Discover", Command.ITEM, 1);
126 cmdSelect = new Command("Select", Command.OK, 1);
127 cmdExit = new Command("Exit", Command.EXIT, 1);
128 cmdServer = new Command("Server", Command.ITEM, 1);
129 cmdLog = new Command("Log", Command.ITEM, 1);
130 cmdBack = new Command("Back", Command.BACK, 1);
131 cmdRemove = new Command("Remove", Command.ITEM, 1);
134 private void initForms() {
135 formStart = new Form("Bluetooth Reader");
136 formServerStart = new Form("Server");
137 formConnect = new Form("Connect");
138 formDiscover = new Form("Discover");
139 formReader = new Form("Reader");
140 formLog = new Form("Log");
141 formError = new Form("Error");
142 tfIn = new TextField("Last APDU", "", 520, TextField.UNEDITABLE);
143 tfOut = new TextField("Last RAPDU", "", 520, TextField.UNEDITABLE);
144 tfReadIn = new TextField("APDU size", "", 25, TextField.UNEDITABLE);
145 tfWriteOut = new TextField("RAPDU size and responsecode", "", 12, TextField.UNEDITABLE);
146 setupForms();
149 private void setupForms() {
150 resetFormStart();
151 resetFormServerStart();
152 resetFormConnect();
153 resetFormDiscover();
154 resetFormReader();
155 resetFormLog();
156 resetFormError();
159 private void resetFormError() {
160 formError.deleteAll();
161 formError.setTitle("Error");
162 formError.addCommand(cmdCancel);
163 formError.addCommand(cmdExit);
164 formError.addCommand(cmdLog);
165 formError.setCommandListener(this);
168 private void resetFormServerStart() {
169 formServerStart.deleteAll();
170 formServerStart.setTitle("Server");
171 // msgTf = new TextField("msg:", "", 256, TextField.ANY);
172 // formDisplay.append(msgTf);
173 formServerStart.addCommand(cmdCancel);
174 formServerStart.setCommandListener(this);
177 private void resetFormConnect() {
178 formConnect.deleteAll();
179 formConnect.setTitle("Connect");
180 formConnect.append("\n\n connect card!");
181 formConnect.addCommand(cmdCancel);
182 formConnect.setCommandListener(this);
185 private void resetFormDiscover() {
186 formDiscover.deleteAll();
187 formDiscover.setTitle("Discover");
188 formDiscover.addCommand(cmdCancel);
189 formDiscover.setCommandListener(this);
192 private void resetFormReader() {
193 formReader.deleteAll();
194 formReader.setTitle("Reader");
195 formReader.append(tfReadIn);
196 formReader.append(tfWriteOut);
197 formReader.addCommand(cmdCancel);
198 formReader.addCommand(cmdLog);
199 formReader.addCommand(cmdRemove);
200 formReader.setCommandListener(this);
203 private void resetFormStart() {
204 formStart.deleteAll();
205 formStart.setTitle("Bluetooth Reader");
206 formStart.addCommand(cmdServer);
207 formStart.addCommand(cmdDiscover);
208 formStart.addCommand(cmdExit);
209 formStart.setCommandListener(this);
212 private void resetFormLog() {
213 formLog.deleteAll();
214 formLog.setTitle("Log");
215 formLog.append(tfIn);
216 formLog.append(tfOut);
217 formLog.addCommand(cmdBack);
218 formLog.setCommandListener(this);
221 private static String toHexString(byte[] value, int offset, int len) {
222 if (value == null)
223 return "null";
225 if (len < 1 || offset < 0 || offset + 1 > value.length) {
226 return "null";
229 StringBuffer result = new StringBuffer();
231 for (int i = 0; i + offset < value.length && i < len; i++) {
232 result.append(Integer.toHexString((value[i + offset] >>> 4) & 0x0F).toUpperCase());
233 result.append(Integer.toHexString(value[i + offset] & 0xF).toUpperCase());
235 return result.toString();
238 private static byte[] toByteArray(String string) {
239 if (string.length() % 2 != 1) {
240 byte[] result = new byte[string.length() / 2];
241 for (int i = 0; i < result.length; i++) {
242 result[i] = (byte) Integer.parseInt(string.substring(2 * i,
243 2 * i + 2), 16);
245 return result;
246 } else {
247 return null;
251 // Starts the search for the Bluetooth devices
252 private void btSearch() {
254 // Set the right UI
255 deviceList = new List("Searcing devices", List.IMPLICIT);
256 deviceList.setSelectCommand(cmdSelect);
257 deviceList.addCommand(cmdCancel);
258 deviceList.setCommandListener(this);
259 display.setCurrent(deviceList);
261 devices = new Vector();
262 // Start an inquiry to find Bluetooth devices
263 try {
264 LocalDevice local = LocalDevice.getLocalDevice();
265 discoveryAgent = local.getDiscoveryAgent();
266 discoveryAgent.startInquiry(DiscoveryAgent.GIAC, this);
268 } catch (BluetoothStateException e) {
269 formLog.append(e.getMessage());
273 /* (non-Javadoc)
274 * @see javax.microedition.lcdui.CommandListener#commandAction(javax.microedition.lcdui.Command, javax.microedition.lcdui.Displayable)
276 public void commandAction(Command cmd, Displayable displayForm) {
278 if (displayForm == formStart) {
279 if (cmd == cmdDiscover) {
280 formStart.append("starting client\n");
281 btSearch();
282 } else if (cmd == cmdServer) {
283 formStart.append("starting server\n");
284 startServer();
286 } else if (displayForm == deviceList) {
287 if (cmd == cmdCancel) {
288 discoveryAgent.cancelInquiry(this);
289 resetFormStart();
290 display.setCurrent(formStart);
291 } else if (cmd == cmdExit) {
292 notifyDestroyed();
293 } else if (cmd == cmdSelect) {
294 if (deviceList.getSelectedIndex() != deviceList.size() - 1) {
295 RemoteDevice btDevice = (RemoteDevice) devices
296 .elementAt(deviceList.getSelectedIndex());
297 startClient(btDevice);
300 } else if (displayForm == formError) {
301 if (cmd == cmdCancel) {
302 resetFormStart();
303 disconnectCard(formError, true);
304 r.kill();
305 display.setCurrent(formStart);
306 } else if (cmd == cmdLog) {
307 display.setCurrent(formLog);
309 } else if (displayForm == formReader) {
310 if (cmd == cmdCancel) {
311 resetFormStart();
312 disconnectCard(formError, true);
313 r.kill();
314 if (connection != null) {
315 try {
316 connection.close();
317 } catch (IOException e) {
318 // TODO Auto-generated catch block
319 e.printStackTrace();
321 connection = null;
323 display.setCurrent(formStart);
324 } else if (cmd == cmdLog) {
325 display.setCurrent(formLog);
326 } else if (cmd == cmdRemove) {
327 disconnectCard(formError, true);
328 startSmartCardDiscovery();
329 resetFormConnect();
330 display.setCurrent(formConnect);
332 } else if (displayForm == formLog) {
333 if (cmd == cmdBack) {
334 display.setCurrent(formReader);
335 } else if (cmd == cmdCancel) {
336 resetFormStart();
337 disconnectCard(formError, true);
338 r.kill();
339 if (connection != null) {
340 try {
341 connection.close();
342 } catch (IOException e) {
343 // TODO Auto-generated catch block
344 e.printStackTrace();
346 connection = null;
348 display.setCurrent(formStart);
350 } else if (displayForm == formServerStart) {
351 if (cmd == cmdCancel) {
352 resetFormStart();
353 r.kill();
354 display.setCurrent(formStart);
356 } else if (displayForm == formConnect) {
357 if (cmd == cmdCancel) {
358 resetFormStart();
359 r.kill();
360 if (connection != null) {
361 try {
362 connection.close();
363 } catch (IOException e) {
364 // TODO Auto-generated catch block
365 e.printStackTrace();
367 connection = null;
369 display.setCurrent(formStart);
372 //else if (displayForm == formDisplay) {
373 // if (cmd == cancelCmd) {
374 // display.setCurrent(form);
375 // form.addCommand(discoverCmd);
376 // }
377 // } else
378 if (cmd == cmdExit) {
379 try {
380 destroyApp(true);
381 } catch (MIDletStateChangeException e) {
382 // TODO Auto-generated catch block
383 e.printStackTrace();
385 notifyDestroyed();
386 return;
390 private void startClient(RemoteDevice btDevice) {
391 resetFormServerStart();
392 display.setCurrent(formServerStart);
393 formServerStart.append(">>trying to discover remote services\n");
394 try {
395 LocalDevice localDevice = LocalDevice.getLocalDevice();
396 DiscoveryAgent agent = localDevice.getDiscoveryAgent();
397 UUID[] uuids = new UUID[] {new UUID(SPP_UUID)};
398 int[] attrSet = {SERVICE_NAME_ATTRID};
399 int id = agent.searchServices(attrSet, uuids, btDevice, this);
400 formServerStart.append(">>got service: " + id + "\n");
401 } catch (BluetoothStateException e) {
402 // TODO Auto-generated catch block
403 e.printStackTrace();
407 private void startServer() {
408 resetFormServerStart();
409 formServerStart.append(">>starting service\n");
410 display.setCurrent(formServerStart);
411 try {
412 LocalDevice btDevice = LocalDevice.getLocalDevice();
413 btDevice.setDiscoverable(DiscoveryAgent.GIAC);
415 serviceURL = "btspp://localhost:" + new UUID(SPP_UUID).toString()
416 + ";name=SPPServer1";
417 StreamConnectionNotifier notifier =
418 (StreamConnectionNotifier) Connector.open(serviceURL);
419 formServerStart.append(">>waiting for connection on\n" +
420 serviceURL + "\n");
421 connection = notifier.acceptAndOpen();
422 // RemoteDevice rDev = RemoteDevice.getRemoteDevice(connection);
423 // formServerStart.append(">>remote address: " + rDev.getBluetoothAddress() + "\n");
424 // formServerStart.append(">>remote name: " + rDev.getFriendlyName(true) + "\n");
426 startSmartCardDiscovery();
428 // start thread and detach handler
429 Thread reader = new Thread(r);
430 reader.start();
431 formServerStart.append("started reader\n");
432 } catch (BluetoothStateException e) {
433 // TODO Auto-generated catch block
434 e.printStackTrace();
435 } catch (IOException e) {
436 // TODO Auto-generated catch block
437 e.printStackTrace();
439 formServerStart.append(">>done\n");
442 private void startSmartCardDiscovery() {
443 resetFormConnect();
444 display.setCurrent(formConnect);
445 initializeCardDiscManager();
448 /* (non-Javadoc)
449 * @see javax.bluetooth.DiscoveryListener#deviceDiscovered(javax.bluetooth.RemoteDevice, javax.bluetooth.DeviceClass)
451 public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
452 // When device has been found add it to devices Vector..
453 devices.addElement(btDevice);
455 // .. and to the deviceList List
456 String devName;
457 try {
458 devName = btDevice.getFriendlyName(false);
460 if (devName == null || devName.compareTo("") == 0) {
461 devName = btDevice.getBluetoothAddress();
463 deviceList.append(devName, null);
464 } catch (IOException e) {
468 /* (non-Javadoc)
469 * @see javax.bluetooth.DiscoveryListener#inquiryCompleted(int)
471 public void inquiryCompleted(int status) {
472 // When searching of the devices has completed set title to indicate
473 // that
474 if (status == INQUIRY_COMPLETED) {
475 deviceList.setTitle("Inquiry completed");
476 } else if (status == INQUIRY_TERMINATED) {
477 deviceList.setTitle("Inquiry terminated");
478 } else if (status == INQUIRY_ERROR) {
479 deviceList.setTitle("Inquiry error");
482 try {
483 LocalDevice local = LocalDevice.getLocalDevice();
484 String name = local.getFriendlyName();
485 if (name == null || name.compareTo("") == 0) {
486 name = local.getBluetoothAddress();
488 devices.addElement(local);
489 deviceList.append(name, null);
490 } catch (BluetoothStateException e) {
491 // TODO Auto-generated catch block
492 e.printStackTrace();
494 synchronized(this) {
495 try { this.notifyAll(); } catch (Exception e) {}
499 /* (non-Javadoc)
500 * @see javax.bluetooth.DiscoveryListener#serviceSearchCompleted(int, int)
502 public void serviceSearchCompleted(int transID, int respCode) {
503 if (respCode != SERVICE_SEARCH_COMPLETED) {
504 formServerStart.append(">>service discovery failed " + respCode + "\n");
505 return;
507 formServerStart.append(">>service discovery done " + transID + " " + respCode + "\n");
508 if (serviceURL == null) {
509 formServerStart.append("!!url empty, abort\n");
510 return;
512 synchronized (this) {
513 try { this.notifyAll(); } catch (Exception e) {}
515 formServerStart.append(">>connecting to service: " + serviceURL);
516 try {
517 connection = (StreamConnection) Connector.open(serviceURL);
518 startSmartCardDiscovery();
519 } catch (IOException e) {
520 // TODO Auto-generated catch block
521 e.printStackTrace();
526 * Removes targetListener for ISO cards.
528 private void removeCardDiscManager() {
529 currTargetType = TargetType.ISO14443_CARD;
530 DiscoveryManager dm = DiscoveryManager.getInstance();
531 try {
532 dm.removeTargetListener(this, TargetType.ISO14443_CARD);
533 } catch (IllegalStateException e1) {
534 // TODO Auto-generated catch block
535 e1.printStackTrace();
540 * Adds Callback for ISO cards.
542 private void initializeCardDiscManager() {
543 currTargetType = TargetType.ISO14443_CARD;
544 DiscoveryManager dm = DiscoveryManager.getInstance();
545 try {
546 dm.removeTargetListener(this, TargetType.ISO14443_CARD);
547 } catch (IllegalStateException e1) {
548 // TODO Auto-generated catch block
549 e1.printStackTrace();
551 try {
552 dm.addTargetListener(this, TargetType.ISO14443_CARD);
553 return;
555 } catch (IllegalStateException e1) {
556 // TODO Auto-generated catch block
557 e1.printStackTrace();
558 } catch (ContactlessException e1) {
559 // TODO Auto-generated catch block
560 e1.printStackTrace();
565 * Interface callback, when ICC is detected by reader.
566 * @param target Properties of the detected ICC
568 public final void targetDetected(TargetProperties[] target) {
569 if (currTargetType.equals(TargetType.ISO14443_CARD)) {
570 cardDetected(target);
575 * Handle a detected smartcard.
576 * @param target connection
578 private void cardDetected(final TargetProperties[] target) {
579 if (!connectExternalCard(target, formConnect)) {
580 display.setCurrent(formError);
581 return;
583 // // TODO start thread and detach handler
584 // startReader();
585 isCardPresent = true;
586 display.setCurrent(formReader);
590 * Establishes connection to external card.
591 * @param target to make connection
592 * @param currentForm where to display messages
593 * @return success status
595 private boolean connectExternalCard(final TargetProperties[] target,
596 Form currentForm) {
597 Class[] classes = target[0].getConnectionNames();
599 for (int j = 0; j < classes.length; ++j) {
600 try {
601 if (isoConn != null) {
602 disconnectCard(currentForm, false);
604 if (classes[j].equals(Class.forName(
605 "javax.microedition.contactless.sc.ISO14443Connection"))) {
607 String url = target[0].getUrl(classes[j]);
609 try {
610 isoConn = (ISO14443Connection) Connector.open(url);
611 } catch (IOException e) {
612 currentForm.append("IOException\n");
613 return false;
616 uid = target[0].getUid();
617 currentForm.append("connected\n");
618 return true;
620 } catch (ClassNotFoundException e) {
621 // TODO Auto-generated catch block
622 e.printStackTrace();
626 return false;
630 * Closes connection.
631 * @param currentForm where to display messages.
632 * @return true if successful
634 private boolean disconnectCard(final Form currentForm, boolean removeTargetListener) {
635 isCardPresent = false;
636 try {
637 if (isoConn != null) {
638 isoConn.close();
640 // currentForm.append(disconnectStr);
641 } catch (IOException e) {
642 currentForm.append("IOException\n");
643 return false;
645 if (removeTargetListener) {
646 removeCardDiscManager();
648 return true;
653 /* (non-Javadoc)
654 * @see javax.bluetooth.DiscoveryListener#servicesDiscovered(int, javax.bluetooth.ServiceRecord[])
656 public void servicesDiscovered(int transID, ServiceRecord[] records) {
657 formServerStart.append(">>services discovered #: " + records.length + "\n");
658 for (int i = 0; i < records.length; ++i) {
659 serviceURL = records[i].getConnectionURL(
660 ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
661 DataElement serviceNameElement = records[i].getAttributeValue(SERVICE_NAME_ATTRID);
662 if (serviceNameElement != null) {
663 String name = (String) serviceNameElement.getValue();
664 formServerStart.append(">>" + name + "\n");
665 if (serviceURL.startsWith("btspp")
666 && name.indexOf("SPPServer1") > -1) {
667 formServerStart.append(">>got btspp service " + i + "\n");
668 break;
674 public class Reader extends Thread {
676 private static final int READER_CMD_LENGTH = 2;
677 private final byte[] GET_ATTR_CMD = new byte[] {0x20, 0x21};
678 private final byte[] GET_PRESENCE_CMD = new byte[] {0x20, 0x22};
679 private final byte[] END_BYTES = new byte[] {0x20, 0x23};
680 private boolean end = false;
682 private final byte[] NULL_BYTES = new byte[] {0x00};
683 private final byte[] ONE_BYTES = new byte[] {(byte) 1};
685 public void kill() {
686 end = true;
689 public void run() {
690 formLog.append("started\n");
691 end = false;
692 startReader();
695 private void startReader() {
696 resetFormReader();
697 formReader.append(" -- communicating -- \n");
698 //display.setCurrent(formReader);
700 buffer = new byte[258];
701 byte[] response;
702 byte[] responseLength = new byte[1];
704 try {
705 OutputStream os = connection.openOutputStream();
706 InputStream is = connection.openInputStream();
708 int realLen, readLen, offset, len = 0;
710 // reader loop
711 while(!end) {
712 realLen = -1;
713 readLen = 0;
714 len = 0;
716 // get input
717 while (readLen != realLen) {
718 len = is.read(buffer, realLen + 1, 255 - readLen);
720 if (len < 1) {
721 try {
722 sleep(10);
723 } catch (InterruptedException e) {
724 // TODO Auto-generated catch block
725 formReader.append("ending\n");
726 return;
728 continue;
729 } else {
730 if (realLen < 1) {
731 realLen = (int) (buffer[0] & 0xFF);
732 readLen += len -1;
733 } else {
734 readLen += len;
739 len = readLen;
740 offset = 1;
741 // byte[] cmd = new byte[len];
742 // for (int i = 0 ; i < readLen; ++i) {
743 // cmd[i] = buffer[i + 1];
744 // }
746 // write messages to screen
747 if (len > 1 && len != READER_CMD_LENGTH) {
748 tfReadIn.setString(">> " + len + "\n"
749 + toHexString(buffer, 1, 8));
750 tfWriteOut.setString(" \n ");
751 //tfIn.setString(">>got " + len + " " + toHexString(buffer, 1, 8));
756 // handle cmds
757 if (len == READER_CMD_LENGTH) {
758 //formLog.append("might have gotten cmd\n");
760 if (isEnd(buffer, offset, len)) {
761 end = true;
762 formReader.append(">>end command\n");
763 formLog.append(">>end command\n");
764 break;
767 if (equal(GET_ATTR_CMD, buffer, len)) {
768 formLog.append(">>atr\n");
769 responseLength[0] = (byte) (0xFF & uid.length());
770 os.write(responseLength);
771 os.write(uid.getBytes());
772 os.flush();
773 continue;
776 if (equal(GET_PRESENCE_CMD, buffer, len)) {
777 //formLog.append(">>presence\n");
778 responseLength[0] = 1;
779 os.write(responseLength);
780 if (isCardPresent) {
781 os.write(ONE_BYTES);
782 } else {
783 os.write(NULL_BYTES);
785 os.flush();
787 continue;
790 formLog.append("matched no cmd\n");
791 } else {
792 //formLog.append("doing real shit\n");
794 tfIn.setString(toHexString(buffer, 1, len));
795 if (isCardPresent) {
796 response = sendAPDU(buffer, offset, len);
798 if (response != null && response.length > 0) {
799 responseLength[0] = (byte) (0xFF & response.length);
800 os.write(responseLength);
801 os.write(response);
802 os.flush();
803 tfWriteOut.setString("<< " + response.length
804 + "\n" + toHexString(response, response.length - 2, 2));
805 tfOut.setString(toHexString(response, 0, response.length));
806 } else {
807 os.write(NULL_BYTES);
808 os.flush();
810 } else {
811 //formLog.append("nuthing done\n");
812 os.write(NULL_BYTES);
813 os.flush();
816 try {
817 is.close();
818 os.close();
819 } catch (IOException e) {
820 e.printStackTrace();
822 } catch (IOException e) {
823 e.printStackTrace();
824 formError.append(e.getMessage());
825 formError.append("!!Bluetooth error\nrestart necessary\n");
826 disconnectCard(formError, true);
827 display.setCurrent(formError);
828 return;
830 if (connection != null) {
831 try {
832 connection.close();
833 } catch (IOException e) {
834 e.printStackTrace();
836 connection = null;
838 if (display.getCurrent() == formReader) {
839 resetFormStart();
840 display.setCurrent(formLog);//Start);
847 // TODO own exception throwing
848 private byte[] sendAPDU(byte[] buffer, int offset, int len) {
849 if (buffer == null || buffer.length == 0 || len > buffer.length) {
850 return NULL_BYTES;
853 byte[] cmd = new byte[len];
854 for (int i = 0; i < len; ++i) {
855 cmd[i] = buffer[i + offset];
858 try {
859 return isoConn.exchangeData(cmd);
860 } catch (IOException e) {
861 e.printStackTrace();
862 formError.append(e.getMessage());
863 formError.append("!!NFC IO error\n");
864 formLog.append("!!NFC IO error\n");
866 } catch (ContactlessException e) {
867 e.printStackTrace();
868 formError.append(e.getMessage());
869 formError.append("!!NFC contactless error\nrestart necessary\n");
870 formLog.append("!!NFC contactless error\n");
871 disconnectCard(formError, true);
872 display.setCurrent(formError);
873 r.kill();
875 return NULL_BYTES;
878 private boolean isEnd(byte [] buffer, int offset, int length) {
879 return equal(END_BYTES, 0, END_BYTES.length, buffer, offset, length);
882 private boolean equal(byte[] constCmd, byte[] second, int secondLength) {
883 return equal(constCmd, 0, constCmd.length, second, 1, secondLength);
886 private boolean equal(byte[] first, int firstOffset, int firstLength,
887 byte[] second, int secondOffset, int secondLength) {
888 if (first == null && second == null) {
889 //formLog.append("both null\n");
890 return true;
892 if (first == null || second == null) {
893 //formLog.append("one null\n");
894 return false;
896 if (firstLength < 1 || firstOffset < 0
897 || secondLength < 1 || secondOffset < 0) {
898 return false;
900 if (firstLength + firstOffset > first.length
901 || secondLength + secondOffset > second.length) {
902 //formLog.append("wrong length specified\n");
903 return false;
905 if (firstLength != secondLength) {
906 //formLog.append("length wrong " + first.length + " " + second.length + "\n");
907 return false;
909 for (int i = 0; i < firstLength; ++i) {
910 if (first[i + firstOffset] != second[i + secondOffset]) {
911 //formLog.append("different " + i + " " + first[i] + " != " + second[i] + "\n");
912 return false;
915 return true;