package nordpol.android; import java.io.IOException; import java.util.List; import java.util.ArrayList; import java.util.concurrent.CopyOnWriteArrayList; import android.nfc.Tag; import android.nfc.tech.IsoDep; import nordpol.IsoCard; import nordpol.OnCardErrorListener; public class AndroidCard implements IsoCard { private static final int DEFAULT_TIMEOUT = 15000; private static final int SAMSUNG_S5_MINI_MAX = 253; private IsoDep card; private List<OnCardErrorListener> errorListeners = new CopyOnWriteArrayList<OnCardErrorListener>(); private AndroidCard(IsoDep card) { this.card = card; } public static AndroidCard get(Tag tag) throws IOException { IsoDep card = IsoDep.get(tag); /* Workaround for the Samsung Galaxy S5 (since the * first connection always hangs on transceive). * TODO: This could be improved if we could identify * Samsung Galaxy S5 devices */ card.connect(); card.close(); if(card != null) { return new AndroidCard(card); } else { return null; } } private void notifyListeners(IOException exception) { for(OnCardErrorListener listener: errorListeners) { listener.error(this, exception); } } public void addOnCardErrorListener(OnCardErrorListener listener) { errorListeners.add(listener); } public void removeOnCardErrorListener(OnCardErrorListener listener) { errorListeners.remove(listener); } public boolean isConnected() { return card.isConnected(); } public void connect() throws IOException { try { card.connect(); card.setTimeout(DEFAULT_TIMEOUT); } catch(IOException e) { notifyListeners(e); throw e; } } public int getMaxTransceiveLength() throws IOException { /* TODO: This could be improved if we could identify * Samsung Galaxy S5 mini devices */ return Math.min(card.getMaxTransceiveLength(), SAMSUNG_S5_MINI_MAX); } public int getTimeout() { return card.getTimeout(); } public void setTimeout(int timeout) { card.setTimeout(timeout); } public void close() throws IOException { try { card.close(); } catch(IOException e) { notifyListeners(e); throw e; } } public byte[] transceive(byte [] command) throws IOException { try { return card.transceive(command); } catch(IOException e) { notifyListeners(e); throw e; } } public List<byte[]> transceive(List<byte[]> commands) throws IOException { try { ArrayList<byte[]> responses = new ArrayList<byte[]>(); for(byte[] command: commands) { responses.add(card.transceive(command)); } return responses; } catch(IOException e) { notifyListeners(e); throw e; } } public Tag getTag() { return card.getTag(); } }