diff --git a/.gitignore b/.gitignore
index 39fb081..2fa2de7 100755
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,12 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.externalNativeBuild
+/app/build
+/app/libs
+/app/release
diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser
old mode 100755
new mode 100644
index d4581c9..0ac0485
Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 99202cc..c0f68ed 100755
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,34 +1,34 @@
-
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index f44f8ea..c39ecab 100755
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,37 +1,37 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "org.dslul.ticketreader"
minSdkVersion 15
targetSdkVersion 28
- versionCode 31
- versionName "2.1.6"
+ versionCode 33
+ versionName "2.3"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
- implementation fileTree(include: ['*.jar'], dir: 'libs')
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:animated-vector-drawable:28.0.0'
implementation 'com.android.support:support-media-compat:28.0.0'
implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.android.support:customtabs:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:design:28.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.google.android.gms:play-services-ads:17.1.1'
implementation 'com.android.support:cardview-v7:28.0.0'
implementation 'com.yarolegovich:lovely-dialog:1.1.0'
}
diff --git a/app/release/output.json b/app/release/output.json
index 89bf5d6..d4ba1fa 100755
--- a/app/release/output.json
+++ b/app/release/output.json
@@ -1 +1 @@
-[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":20,"versionName":"2.0","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
\ No newline at end of file
+[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":33,"versionName":"2.3","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
\ No newline at end of file
diff --git a/app/src/main/java/org/dslul/ticketreader/ChipOnPaper.java b/app/src/main/java/org/dslul/ticketreader/ChipOnPaper.java
index a046505..c4b831e 100755
--- a/app/src/main/java/org/dslul/ticketreader/ChipOnPaper.java
+++ b/app/src/main/java/org/dslul/ticketreader/ChipOnPaper.java
@@ -1,119 +1,124 @@
package org.dslul.ticketreader;
+import android.util.Log;
+
import org.dslul.ticketreader.util.GttDate;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import static org.dslul.ticketreader.util.GttDate.addMinutesToDate;
import static org.dslul.ticketreader.util.HelperFunctions.getBytesFromPage;
public class ChipOnPaper {
private Date date;
private int type;
private long remainingMins;
private int remainingRides;
ChipOnPaper(List dumplist) {
dumplist = dumplist;
type = (int)getBytesFromPage(dumplist.get(5), 2, 2);
long minutes = getBytesFromPage(dumplist.get(10), 0, 3);
if(type == 9521)
minutes = getBytesFromPage(dumplist.get(12), 0, 3);
date = addMinutesToDate(minutes, GttDate.getGttEpoch());
//calcola minuti rimanenti
Calendar c = Calendar.getInstance();
long diff = (c.getTime().getTime() - date.getTime()) / 60000;
+
long maxtime = 90;
//city 100
- if(type == 302 || type == 304) {
+ if(type == 302 || type == 304 || type == 650) {
maxtime = 100;
}
//Tour TODO: make a distinction between the two types
if(type == 704) {
maxtime = 2*24*60;
}
//daily
if(type == 303 || type == 305) {
remainingMins = GttDate.getMinutesUntilEndOfService(date);
}
else if(diff >= maxtime) {
remainingMins = 0;
} else {
remainingMins = maxtime - diff;
}
//calcola le corse rimanenti
//TODO: corse in metropolitana (forse bit piĆ¹ significativo pag. 3)
int tickets;
if(type == 300) { //extraurbano
tickets = (int) (~getBytesFromPage(dumplist.get(3), 0, 4));
} else {
tickets = (int)(~getBytesFromPage(dumplist.get(3), 2, 2))
& 0xFFFF;
}
remainingRides = Integer.bitCount(tickets);
}
public String getTypeName() {
//http://www.gtt.to.it/cms/biglietti-abbonamenti/biglietti/biglietti-carnet
switch (type) {
case 302:
case 304:
return "City 100";
case 303:
case 305:
return "Daily";
+ case 650:
+ return "MultiCity";
case 704:
return "Tour";
case 301:
return "Multicorsa extraurbano";
case 702:
case 706:
return "Carnet 5 corse";
case 701:
case 705:
return "Carnet 15 corse";
case 300:
return "Extraurbano";
case 9521:
return "Sadem Aeroporto Torino";
default:
return "Non riconosciuto";
}
}
public String getDate() {
return DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT)
.format(date);
}
public int getRemainingRides() {
return remainingRides;
}
public long getRemainingMinutes() {
if(remainingMins < 0)
return 0;
else
return remainingMins;
}
}
diff --git a/app/src/main/java/org/dslul/ticketreader/NfcThread.java b/app/src/main/java/org/dslul/ticketreader/NfcThread.java
index 27f2624..5692a9c 100755
--- a/app/src/main/java/org/dslul/ticketreader/NfcThread.java
+++ b/app/src/main/java/org/dslul/ticketreader/NfcThread.java
@@ -1,231 +1,214 @@
package org.dslul.ticketreader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.content.Intent;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.IsoDep;
import android.nfc.tech.NfcA;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import static org.dslul.ticketreader.util.HelperFunctions.byteArrayToHexString;
import static org.dslul.ticketreader.util.HelperFunctions.hexStringToByteArray;
//parts of code from http://www.emutag.com/soft.php
public class NfcThread extends Thread {
private Context context;
private Intent intent;
private Handler mTextBufferHandler, mToastShortHandler, mToastLongHandler, mShowInfoDialogHandler;
private byte[] readBuffer = new byte[1024]; // maximum theoretical capacity of MIFARE Ultralight
NfcThread(
Context context,
Intent intent,
Handler mTextBufferHandler, Handler mToastShortHandler, Handler mToastLongHandler, Handler mShowInfoDialogHandler
) {
this.context = context;
this.intent = intent;
this.mTextBufferHandler = mTextBufferHandler;
this.mToastShortHandler = mToastShortHandler;
this.mToastLongHandler = mToastLongHandler;
this.mShowInfoDialogHandler = mShowInfoDialogHandler;
}
public void run() {
final Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if(tagFromIntent.getTechList()[0].equals(IsoDep.class.getName())) {
handleIsoDep(tagFromIntent);
} else {
handleNfcA(tagFromIntent);
}
}
private void handleIsoDep(Tag tagFromIntent) {
IsoDep isoDep = IsoDep.get(tagFromIntent);
if (isoDep != null) {
try {
isoDep.connect();
List dumplist = new ArrayList<>();
//selectApplication
dumplist.add(isoDep.transceive(hexStringToByteArray("00A404000E315449432E494341D38012009101")));
//efEnvironment
dumplist.add(isoDep.transceive(hexStringToByteArray("00B2013C1D")));
//efContractList
dumplist.add(isoDep.transceive(hexStringToByteArray("00B201F41D")));
//efContract1
dumplist.add(isoDep.transceive(hexStringToByteArray("00B2014C1D")));
//efContract2
dumplist.add(isoDep.transceive(hexStringToByteArray("00B2024C1D")));
//efContract3
dumplist.add(isoDep.transceive(hexStringToByteArray("00B2034C1D")));
//efContract4
dumplist.add(isoDep.transceive(hexStringToByteArray("00B2044C1D")));
//efContract5
dumplist.add(isoDep.transceive(hexStringToByteArray("00B2054C1D")));
//efContract6
dumplist.add(isoDep.transceive(hexStringToByteArray("00B2064C1D")));
//efContract7
dumplist.add(isoDep.transceive(hexStringToByteArray("00B2074C1D")));
//efContract8
dumplist.add(isoDep.transceive(hexStringToByteArray("00B2084C1D")));
//efEventLogs1
dumplist.add(isoDep.transceive(hexStringToByteArray("00B201441D")));
//efEventLogs2
dumplist.add(isoDep.transceive(hexStringToByteArray("00B202441D")));
//efEventLogs3
dumplist.add(isoDep.transceive(hexStringToByteArray("00B203441D")));
//efValidation
dumplist.add(isoDep.transceive(hexStringToByteArray("00B201CC1D")));
-/*
- dumplist.set(0, hexStringToByteArray("6F28840E315449432E494341D38012009101A516BF0C13C70800000000380712F45307062C23C00002019000"));
- dumplist.set(1, hexStringToByteArray("0501030D1E7B2000026C5AAC434C4D4C534E3630433231473232344BC09000"));
- dumplist.set(2, hexStringToByteArray("05012110012120012130012140012150000000000000000000000000009000"));
- dumplist.set(3, hexStringToByteArray("0105000002C800000093CEBB83BEDCFFAE10AC64014437A0005485E4479000"));
- dumplist.set(4, hexStringToByteArray("0105000002CA00000091B85B81AE1CFFAE10AA0C002857A000E0E8BAA89000"));
- dumplist.set(5, hexStringToByteArray("0105000002CA00000091B85B81AE1CFFAE10AA0C002858A000292F7D039000"));
- dumplist.set(6, hexStringToByteArray("0105000002CA00000091B85B81AE1CFFAE10AA0C002859A000051117559000"));
- dumplist.set(7, hexStringToByteArray("0105000002CA00000091B85B81AE1CFFAE10AA0C00285AA000FBDD7F709000"));
- dumplist.set(8, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
- dumplist.set(9, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
- dumplist.set(10,hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
- dumplist.set(11,hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
- dumplist.set(12,hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
- dumplist.set(13,hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
- dumplist.set(14,hexStringToByteArray("00000900000900000900000900000900000000000000000000000000009000"));
-*/
if(dumplist.size() == 15 && dumplist.get(1)[0] != 0) {
if(dumplist.get(2)[1] == 0) {
showToastLong(context.getString(R.string.smartcard_empty));
return;
}
setContentBuffer(dumplist);
showToastLong(context.getString(R.string.smartcard_read_correctly));
} else {
showToastLong(context.getString(R.string.invalid_smartcard));
}
isoDep.close();
} catch (IOException e) {
showToastLong(context.getString(R.string.read_failure));
}
}
}
private void handleNfcA(Tag tagFromIntent) {
final NfcA mfu = NfcA.get(tagFromIntent);
if (mfu == null) {
showToastLong(context.getString(R.string.ticket_not_supported));
return;
}
byte[] ATQA = mfu.getAtqa();
if (mfu.getSak() != 0x00 || ATQA.length != 2 || ATQA[0] != 0x44 || ATQA[1] != 0x00) {
showToastLong(context.getString(R.string.ticket_not_supported));
return;
}
int pagesRead;
List dumplist = new ArrayList<>();
try {
mfu.connect();
pagesRead = rdNumPages(mfu, 16); // 0 for no limit (until error)
mfu.close();
for (int i = 0; i < pagesRead*4; i += 4) {
byte[] mfuPage = new byte[4];
System.arraycopy(readBuffer, i, mfuPage, 0, 4);
dumplist.add(mfuPage);
}
if(pagesRead >= 16) {
showToastShort(context.getString(R.string.ticket_correctly_read));
setContentBuffer(dumplist);
} else {
throw new RuntimeException(context.getString(R.string.read_failure));
}
}
catch (RuntimeException e) {
showToastLong(context.getString(R.string.read_failure));
}
catch (Exception e) {
showToastLong(context.getString(R.string.communication_error));
}
}
private void setContentBuffer(List content) {
Message msg = new Message();
msg.obj = content;
mTextBufferHandler.sendMessage(msg);
}
private void showToastShort(String text) {
Message msg = new Message();
msg.obj = text;
mToastShortHandler.sendMessage(msg);
}
private void showToastLong(String text) {
Message msg = new Message();
msg.obj = text;
mToastLongHandler.sendMessage(msg);
}
private void showInfoDialog(String text) {
Message msg = new Message();
msg.obj = text;
mShowInfoDialogHandler.sendMessage(msg);
}
private int rdNumPages(NfcA mfu, int num) {
int pagesRead = 0;
while (rdPages(mfu, pagesRead) == 0) {
pagesRead++;
if (pagesRead == num || pagesRead == 256) break;
}
return pagesRead;
}
// first failure (NAK) causes response 0x00 (or possibly other 1-byte values)
// second failure (NAK) causes transceive() to throw IOException
private byte rdPages(NfcA tag, int pageOffset) {
byte[] cmd = {0x30, (byte)pageOffset};
byte[] response = new byte[16];
try {
response = tag.transceive(cmd);
}
catch (IOException e) {
return 1;
}
if (response.length != 16)
return 1;
System.arraycopy(response, 0, readBuffer, pageOffset * 4, 4);
return 0;
}
}
diff --git a/app/src/main/java/org/dslul/ticketreader/SmartCard.java b/app/src/main/java/org/dslul/ticketreader/SmartCard.java
index 50c713e..1486a3e 100644
--- a/app/src/main/java/org/dslul/ticketreader/SmartCard.java
+++ b/app/src/main/java/org/dslul/ticketreader/SmartCard.java
@@ -1,372 +1,331 @@
package org.dslul.ticketreader;
import android.util.Log;
import org.dslul.ticketreader.util.GttDate;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.lang.Math.abs;
import static org.dslul.ticketreader.util.HelperFunctions.getBytesFromPage;
public class SmartCard {
public enum Type {
BIP,
PYOU,
EDISU
}
- static final Map subscriptionCodes = new HashMap() {{
+ private static final Map subscriptionCodes = new HashMap() {{
put(68, "Mensile UNDER 26");
put(72, "Mensile Studenti Rete Urbana");
put(101, "Settimanale Formula 1");
put(102, "Settimanale Formula 2");
put(103, "Settimanale Formula 3");
put(104, "Settimanale Formula 4");
put(105, "Settimanale Formula 5");
put(106, "Settimanale Formula 6");
put(107, "Settimanale Formula 7");
put(108, "Settimanale Intera Area Formula");
put(109, "Settimanale Personale Rete Urbana");
put(199, "Mensile Personale Rete Urbana (Formula U)");
put(201, "Mensile Formula 1");
put(202, "Mensile Formula 2");
put(203, "Mensile Formula 3");
put(204, "Mensile Formula 4");
put(205, "Mensile Formula 5");
put(206, "Mensile Formula 6");
put(207, "Mensile Formula 7");
put(208, "Mensile Intera Area Formula");
put(261, "Mensile Studenti Urbano+Suburbano");
put(290, "Mensile 65+ Urbano Orario Ridotto");
put(291, "Mensile 65+ Urbano");
put(307, "Annuale Ivrea Rete Urbana e Dintorni");
put(308, "Annuale Extraurbano O/D");
put(310, "Plurimensile Studenti Extraurbano O/D");
put(721, "Annuale UNDER 26");
put(722, "Annuale UNDER 26 Fascia A");
put(723, "Annuale UNDER 26 Fascia B");
put(724, "Annuale UNDER 26 Fascia C");
put(730, "Mensile urbano Over 65");
put(761, "Annuale Over A");
put(731, "Annuale Over B");
put(732, "Annuale Over C");
put(733, "Annuale Over D");
put(911, "10 Mesi Studenti");
put(912, "Annuale Studenti");
put(990, "Junior");
put(993, "Annuale Formula U");
put(4001, "Settimanale Formula 4");
put(4002, "Mensile Formula 3 U+A");
put(4003, "Annuale Formula U a Zone");
}};
- static final Map ticketCodes = new HashMap() {{
+ private static final Map ticketCodes = new HashMap() {{
put(712, "Ordinario Urbano");
put(714, "City 100");
put(715, "Daily");
put(716, "Multidaily");
}};
private class Contract {
private int code;
private int counters;
private boolean isValid;
private boolean isTicket;
private boolean isSubscription;
private Date startDate;
private Date endDate;
- public Contract(byte[] data, int counters) {
+ Contract(byte[] data, int counters) {
int company = data[0];
this.counters = counters;
//get contract type
code = ((data[4] & 0xff) << 8) | data[5] & 0xff;
//support for GTT S.p.A. tickets only for now
if(code == 0 || company != 1) {
isValid = false;
} else {
isValid = true;
}
if(ticketCodes.containsKey(code)) {
isTicket = true;
isSubscription = false;
} else if(subscriptionCodes.containsKey(code)) {
isTicket = false;
isSubscription = true;
} else {
isTicket = false;
isSubscription = false;
}
long minutes = ~(data[9] << 16 & 0xff0000 | data[10] << 8 & 0xff00 |
data[11] & 0xff) & 0xffffff;
startDate = GttDate.decode(minutes);
minutes = ~(data[12] << 16 & 0xff0000 | data[13] << 8 & 0xff00 |
data[14] & 0xff) & 0xffffff;
endDate = GttDate.decode(minutes);
}
public int getCode() {
return code;
}
public Date getStartDate() {
return startDate;
}
- public int getRides() {
+ int getRides() {
if(code == 712 || code == 714)
return (((counters & 0x0000ff)&0x78) >> 3);
else
return (counters >> 19);
}
- public Date getEndDate() {
+ Date getEndDate() {
return endDate;
}
- public boolean isContract() {
+ boolean isContract() {
return isValid;
}
- public boolean isSubscription() {
- if(isSubscription)
- return true;
- else
- return false;
+ boolean isSubscription() {
+ return isSubscription;
}
- public boolean isTicket() {
- if(isTicket)
- return true;
- else
- return false;
+ boolean isTicket() {
+ return isTicket;
}
- public String getTypeName() {
+ String getTypeName() {
if(isTicket)
return ticketCodes.get(code);
else if(isSubscription)
return subscriptionCodes.get(code);
else
return "Sconosciuto";
}
}
private Date validationDate;
private Date creationDate;
private Type type;
private List tickets = new ArrayList<>();
private List subscriptions = new ArrayList<>();
private Contract subscription;
private int ridesLeft = 0;
private long remainingMins;
SmartCard(List dumplist) {
byte[] selectApplication = dumplist.get(0);
byte[] efEnvironment = dumplist.get(1);
byte[] efContractList = dumplist.get(2);
byte[] efEventLogs1 = dumplist.get(11);
byte[] efEventLogs2 = dumplist.get(12);
byte[] efEventLogs3 = dumplist.get(13);
byte[] efCounters = dumplist.get(14);
if(efEnvironment[28] == (byte)0xC0)
type = Type.BIP;
else if(efEnvironment[28] == (byte)0xC1)
type = Type.PYOU;
else if(efEnvironment[28] == (byte)0xC2)
type = Type.EDISU;
byte[] minutes = new byte[3];
System.arraycopy(efEnvironment, 9, minutes, 0, 3);
creationDate = GttDate.decode(minutes);
//scan contractlist for tickets and subscriptions
for(int i = 1; i < 23; i+=3) {
//only GTT tickets atm
if(efContractList[i] == 1) {
//check validity
if((efContractList[i+1]&0x0f) == 1) {
//position in counters
int cpos = ((abs(efContractList[i+2]&0xff) >> 4)-1)*3;
int counter = 0;
if(cpos >= 0)
counter = (efCounters[cpos+2] & 0xff) | ((efCounters[cpos+1] & 0xff) << 8)
| ((efCounters[cpos] & 0xff) << 16);
- Log.d("card", String.valueOf(counter >> 19));
Contract contract = new Contract(dumplist.get(i/3+1 + 2), counter);
if(contract.isContract()) {
if(contract.isSubscription()) {
subscriptions.add(contract);
}
if(contract.isTicket()) {
tickets.add(contract);
ridesLeft += contract.getRides();
}
}
}
}
}
- /*
- for (int i = 0; i < 8; i++) {
- Contract contract = new Contract(dumplist.get(i+3));
-
- if(contract.isContract()) {
- if(contract.isSubscription()) {
- subscriptions.add(contract);
- }
- if(contract.isTicket()) {
- tickets.add(contract);
- }
- }
-
- */
-
//get a valid subscription, if there's any
Date latestExpireDate = GttDate.getGttEpoch();
for (Contract sub : subscriptions) {
if (latestExpireDate.before(sub.getEndDate())) {
latestExpireDate = sub.getEndDate();
subscription = sub;
}
}
- //actual tickets count
- //ridesLeft = countTickets(efCounters, efContractList);
-
//get last validation time
long mins = getBytesFromPage(efEventLogs1, 20, 3);
if(mins == 0)
mins = getBytesFromPage(efEventLogs2, 20, 3);
if(mins == 0)
mins = getBytesFromPage(efEventLogs3, 20, 3);
validationDate = GttDate.addMinutesToDate(mins, GttDate.getGttEpoch());
Calendar c = Calendar.getInstance();
long diff = (c.getTime().getTime() - validationDate.getTime()) / 60000;
int num = (int)(getBytesFromPage(efEventLogs1, 25, 1) >> 4);
int tickettype = (int)getBytesFromPage(dumplist.get(num+2), 4, 2);
long maxtime = 90;
//city 100
if(tickettype == 714) {
maxtime = 100;
}
//daily
if(tickettype == 715 || tickettype == 716) {
remainingMins = GttDate.getMinutesUntilEndOfService(validationDate);
}
else if(diff >= maxtime) {
remainingMins = 0;
} else {
remainingMins = maxtime - diff;
}
}
- private int countTickets(byte[] validations, byte[] contractsList) {
- int count = 0;
- for (int i = 2; i < 24; i+=3) {
- int valpos = abs(contractsList[i+1]) >> 4;
- //position in contractslist
- int pos = i/3 + 1;
- //check if it's a subscription
- int sub = abs(contractsList[i]&0xf0) >> 4;
- if(pos > 0 && pos <= 8 && (contractsList[i]&0x0f) != 0 && sub < 0xA) {
- int rides = (abs(validations[valpos*3-3] & 0xff) >> 3);
- count += rides;
- }
- }
- return count;
- }
-
public String getTicketName() {
if(hasTickets())
return type + " - " + tickets.get(0).getTypeName();
else
return type.toString();
}
public String getSubscriptionName() {
if(hasSubscriptions())
return type + " - " + subscription.getTypeName();
else
return type.toString();
}
public boolean hasTickets() {
- return ridesLeft != 0;
+ return ridesLeft != 0 || remainingMins > 0;
}
public boolean hasSubscriptions() {
return subscriptions.size() != 0;
}
public String getExpireDate() {
return DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT)
.format(subscription.getEndDate());
}
public String getValidationDate() {
return DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT)
.format(validationDate);
}
public boolean isSubscriptionExpired() {
Calendar c = Calendar.getInstance();
return c.getTime().after(subscription.getEndDate());
}
private boolean isExpired(Date date) {
Calendar c = Calendar.getInstance();
return c.getTime().after(date);
}
public int getRemainingRides() {
return ridesLeft;
}
public long getRemainingMinutes() {
if(remainingMins < 0)
return 0;
else
return remainingMins;
}
}
diff --git a/app/src/main/java/org/dslul/ticketreader/util/GttDate.java b/app/src/main/java/org/dslul/ticketreader/util/GttDate.java
index f730b9c..cf8e2ff 100644
--- a/app/src/main/java/org/dslul/ticketreader/util/GttDate.java
+++ b/app/src/main/java/org/dslul/ticketreader/util/GttDate.java
@@ -1,67 +1,94 @@
package org.dslul.ticketreader.util;
import android.util.Log;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
+import java.util.concurrent.TimeUnit;
public final class GttDate {
public static Date decode(byte[] minutes) {
return addMinutesToDate(byteArrayToLong(minutes), getGttEpoch());
}
public static Date decode(long minutes) {
return addMinutesToDate(minutes, getGttEpoch());
}
public static Date getGttEpoch() {
String startingDate = "05/01/01 00:00:00";
SimpleDateFormat format = new SimpleDateFormat("yy/MM/dd HH:mm:ss");
Date date = null;
try {
date = format.parse(startingDate);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
public static long getMinutesUntilEndOfService(Date startDate) {
Calendar curr = Calendar.getInstance();
Calendar after = Calendar.getInstance();
Calendar start = Calendar.getInstance();
start.setTime(startDate);
+ if((curr.getTimeInMillis() - start.getTimeInMillis())/60000 > 24*60) {
+ return 0;
+ }
int dayoff = 0;
if(start.get(Calendar.DAY_OF_MONTH) == curr.get(Calendar.DAY_OF_MONTH))
dayoff = 1;
after.add(Calendar.DAY_OF_MONTH, dayoff);
after.set(Calendar.HOUR_OF_DAY, 3);
after.set(Calendar.MINUTE, 0);
after.set(Calendar.SECOND, 0);
after.set(Calendar.MILLISECOND, 0);
return (after.getTimeInMillis() - curr.getTimeInMillis())/60000;
}
public static Date addMinutesToDate(long minutes, Date beforeTime) {
final long ONE_MINUTE_IN_MILLIS = 60000;
long curTimeInMs = beforeTime.getTime();
return new Date(curTimeInMs + (minutes * ONE_MINUTE_IN_MILLIS));
}
private static long byteArrayToLong(byte[] bytes) {
long value = 0;
for (int i = 0; i < bytes.length; i++) {
value = (value << 8) + (bytes[i] & 0xff);
}
return value;
}
+ //only for unit testing
+ public static String genDate() {
+
+ String dateStart = "05/01/01 00:00:00";
+ Date now = new Date();
+ SimpleDateFormat format = new SimpleDateFormat("yy/MM/dd HH:mm:ss");
+ Date d1 = null;
+ Date d2 = new Date();
+ try {
+ d1 = format.parse(dateStart);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ long diff = d2.getTime() - d1.getTime();
+ long diffMinutes = diff / (60 * 1000) % 60;
+
+ String page = Long.toHexString(TimeUnit.MILLISECONDS.toMinutes(diff));
+ for (int i = 0; i <= 8 - page.length(); i++) {
+ page += "0";
+ }
+ return page;
+ }
+
}
diff --git a/app/src/test/java/org/dslul/ticketreader/ChipOnPaperUnitTest.java b/app/src/test/java/org/dslul/ticketreader/ChipOnPaperUnitTest.java
deleted file mode 100755
index fbc6a60..0000000
--- a/app/src/test/java/org/dslul/ticketreader/ChipOnPaperUnitTest.java
+++ /dev/null
@@ -1,145 +0,0 @@
-package org.dslul.ticketreader;
-
-import android.test.AndroidTestCase;
-import android.test.ApplicationTestCase;
-import android.test.InstrumentationTestCase;
-import android.util.Log;
-
-import org.dslul.ticketreader.util.HelperFunctions;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.dslul.ticketreader.util.HelperFunctions.hexStringToByteArray;
-import static org.junit.Assert.*;
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * @see Testing documentation
- */
-public class ChipOnPaperUnitTest {
-
- List ticket2 = new ArrayList<>();
- List ticket3 = new ArrayList<>();
- List ticket4 = new ArrayList<>();
- List ticket5 = new ArrayList<>();
- List ticket6 = new ArrayList<>();
-
- @Test
- public void ChipOnPaper_isCorrect() throws Exception {
- List ticket1 = new ArrayList<>();
- ticket1.add(hexStringToByteArray("057D6292"));
- ticket1.add(hexStringToByteArray("AD2954E9"));
- ticket1.add(hexStringToByteArray("3915F203"));
- ticket1.add(hexStringToByteArray("07FFFFF0"));
- ticket1.add(hexStringToByteArray("01040000"));
- ticket1.add(hexStringToByteArray("020102BE"));
- ticket1.add(hexStringToByteArray("68970000"));
- ticket1.add(hexStringToByteArray("00AE10A7"));
- ticket1.add(hexStringToByteArray("0200645C"));
- ticket1.add(hexStringToByteArray("397D91B4"));
- ticket1.add(hexStringToByteArray("68A4F900"));
- ticket1.add(hexStringToByteArray("04F80000"));
- ticket1.add(hexStringToByteArray("68A4F900"));
- ticket1.add(hexStringToByteArray("00050004"));
- ticket1.add(hexStringToByteArray("F8AE1079"));
- ticket1.add(hexStringToByteArray("9E1291E4"));
- ChipOnPaper chip = new ChipOnPaper(ticket1);
- assertEquals(4, chip.getRemainingRides());
- assertEquals(0, chip.getRemainingMinutes());
-
- }
-
- @Test
- public void Smartcard_Count_Ticket_isCorrect() throws Exception {
- List list = new ArrayList<>();
- list.add(hexStringToByteArray("6F208970ABA0B980986C9A09078F098087E0A980DF0101010A0101090E109019011022354345676010019000"));
- list.add(hexStringToByteArray("050110129845479323849432659823874899264578987A09A9692348799000"));
-
- list.add(hexStringToByteArray("05012160014020014030014040014050012110012170012180000000009000"));
-
- list.add(hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
- list.add(hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
- list.add(hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
- list.add(hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
- list.add(hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
- list.add(hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
- list.add(hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
- list.add(hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
-
- list.add(hexStringToByteArray("0501000000216D7F0D0004F800002A00000000006D7F0D00007000BEE39000"));
- list.add(hexStringToByteArray("0501000000216D00050004F800000400000000006CFFF00000400007779000"));
- list.add(hexStringToByteArray("0501000000216CFFF00004F80000D800000000006CFFF000004000316A9000"));
-
- list.add(hexStringToByteArray("60000234D95D6F5840000000000060004000004000000000234321E56A821000019000"));
- SmartCard smartcard = new SmartCard(list);
-
- assertEquals(3, smartcard.getRemainingRides());
-
- list.set(2, hexStringToByteArray("05012160014020014030014040014050012110012170012180000000009000"));
- list.set(11, hexStringToByteArray("0501000000216D959E0004F800002A00000000006D959E00001000674E9000"));
- list.set(12, hexStringToByteArray("0501000000216D7F0D0004F800002A00000000006D7F0D00007000BEE39000"));
- list.set(13, hexStringToByteArray("0501000000216D00050004F800000400000000006CFFF00000400007779000"));
- SmartCard s2 = new SmartCard(list);
-
- assertEquals(2, s2.getRemainingRides());
-
-
- list.set(2, hexStringToByteArray("05012060014020014030014040014050012110012170012180000000009000"));
- list.set(11, hexStringToByteArray("0501000000216D9B2C0004F800002A00000000006D9B2C000060008D809000"));
- list.set(12, hexStringToByteArray("0501000000216D959E0004F800002A00000000006D959E00001000674E9000"));
- list.set(13, hexStringToByteArray("0501000000216D7F0D0004F800002A00000000006D7F0D00007000BEE39000"));
- smartcard = new SmartCard(list);
-
- assertEquals(1, smartcard.getRemainingRides());
-
-
- list.set(2, hexStringToByteArray("05012060014020014030014040014050012110012170012180000000009000"));
- list.set(11, hexStringToByteArray("0501000000216D9B2C0004F800002A00000000006D9B2C000060008D809000"));
- list.set(12, hexStringToByteArray("0501000000216D959E0004F800002A00000000006D959E00001000674E9000"));
- list.set(13, hexStringToByteArray("0501000000216D7F0D0004F800002A00000000006D7F0D00007000BEE39000"));
- smartcard = new SmartCard(list);
-
- assertEquals(1, smartcard.getRemainingRides());
-
- //1 used ticket
- list.set(2, hexStringToByteArray("05012110000000000000000000000000000000000000000000000000009000"));
- list.set(11, hexStringToByteArray("0501000000216C9EF30004F800007400000000006C9EB100001000F66B9000"));
- list.set(12, hexStringToByteArray("0501000000216C9EC80004F80003E700000000006C9EB100001000E9E29000"));
- list.set(13, hexStringToByteArray("0501000000216C9EB10004F800007400000000006C9EB10000100098509000"));
- smartcard = new SmartCard(list);
-
- assertEquals(0, smartcard.getRemainingRides());
-
-
- //1 used ticket
- list.set(2, hexStringToByteArray("05012110000000000000000000000000000000000000000000000000009000"));
- list.set(11, hexStringToByteArray("0501000000216C9EF30004F800007400000000006C9EB100001000F66B9000"));
- list.set(12, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
- list.set(13, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
- smartcard = new SmartCard(list);
-
- assertEquals(0, smartcard.getRemainingRides());
-
- //1 full multidaily
- list.set(2, hexStringToByteArray("0501A10001511001A100000000000000000000000000000000000000009000"));
- list.set(11, hexStringToByteArray("0501030258216C41130004F800007400000000006C355D0000300017D89000"));
- list.set(12, hexStringToByteArray("0501030258216C3F8A0004F800000F00000000006C355D000030002EE19000"));
- list.set(13, hexStringToByteArray("0501030258216C356A0004F800000A00000000006C355D000030007F249000"));
- smartcard = new SmartCard(list);
-
- assertEquals(7, smartcard.getRemainingRides());
-
-
- //expired subscriptions only
- list.set(2, hexStringToByteArray("0501A10001000001A100000000000000000000000000000000000000009000"));
- list.set(11, hexStringToByteArray("0501030258216C41130004F800007400000000006C355D0000300017D89000"));
- list.set(12, hexStringToByteArray("0501030258216C3F8A0004F800000F00000000006C355D000030002EE19000"));
- list.set(13, hexStringToByteArray("0501030258216C356A0004F800000A00000000006C355D000030007F249000"));
- smartcard = new SmartCard(list);
-
- assertEquals(false, smartcard.hasTickets());
- }
-}
\ No newline at end of file
diff --git a/app/src/test/java/org/dslul/ticketreader/TicketsUnitTest.java b/app/src/test/java/org/dslul/ticketreader/TicketsUnitTest.java
new file mode 100755
index 0000000..457e90d
--- /dev/null
+++ b/app/src/test/java/org/dslul/ticketreader/TicketsUnitTest.java
@@ -0,0 +1,314 @@
+package org.dslul.ticketreader;
+
+
+import org.dslul.ticketreader.util.GttDate;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.dslul.ticketreader.util.HelperFunctions.hexStringToByteArray;
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class TicketsUnitTest {
+
+ @Test
+ public void ChipOnPaper_isCorrect() {
+ List ticket1 = new ArrayList<>();
+ ticket1.add(hexStringToByteArray("057D6292"));
+ ticket1.add(hexStringToByteArray("AD2954E9"));
+ ticket1.add(hexStringToByteArray("3915F203"));
+ ticket1.add(hexStringToByteArray("07FFFFF0"));
+ ticket1.add(hexStringToByteArray("01040000"));
+ ticket1.add(hexStringToByteArray("020102BE"));
+ ticket1.add(hexStringToByteArray("68970000"));
+ ticket1.add(hexStringToByteArray("00AE10A7"));
+ ticket1.add(hexStringToByteArray("0200645C"));
+ ticket1.add(hexStringToByteArray("397D91B4"));
+ ticket1.add(hexStringToByteArray("68A4F900"));
+ ticket1.add(hexStringToByteArray("04F80000"));
+ ticket1.add(hexStringToByteArray("68A4F900"));
+ ticket1.add(hexStringToByteArray("00050004"));
+ ticket1.add(hexStringToByteArray("F8AE1079"));
+ ticket1.add(hexStringToByteArray("9E1291E4"));
+ ChipOnPaper chip = new ChipOnPaper(ticket1);
+ assertEquals(4, chip.getRemainingRides());
+ assertEquals(0, chip.getRemainingMinutes());
+
+
+ ticket1.set(0, hexStringToByteArray("043FDA69"));
+ ticket1.set(1, hexStringToByteArray("AAD75B81"));
+ ticket1.set(2, hexStringToByteArray("A748F203"));
+ ticket1.set(3, hexStringToByteArray("7FFFFFFF"));
+ ticket1.set(4, hexStringToByteArray("010B0000"));
+ ticket1.set(5, hexStringToByteArray("0101012F"));
+ ticket1.set(6, hexStringToByteArray("6F072000"));
+ ticket1.set(7, hexStringToByteArray("00AE10A7"));
+ ticket1.set(8, hexStringToByteArray("F1006A3D"));
+ ticket1.set(9, hexStringToByteArray("99EE380F"));
+ ticket1.set(10, hexStringToByteArray("6F09BE00"));
+ ticket1.set(11, hexStringToByteArray("04F80000"));
+ ticket1.set(12, hexStringToByteArray("6F09BE00"));
+ ticket1.set(13, hexStringToByteArray("00D80004"));
+ ticket1.set(14, hexStringToByteArray("F8AE10A0"));
+ ticket1.set(15, hexStringToByteArray("02121827"));
+ chip = new ChipOnPaper(ticket1);
+ assertEquals(0, chip.getRemainingRides());
+ assertEquals(0, chip.getRemainingMinutes());
+
+
+ ticket1.set(0, hexStringToByteArray("04CF7132"));
+ ticket1.set(1, hexStringToByteArray("1A675D80"));
+ ticket1.set(2, hexStringToByteArray("A048F203"));
+ ticket1.set(3, hexStringToByteArray("7FFFFFFF"));
+ ticket1.set(4, hexStringToByteArray("01030000"));
+ ticket1.set(5, hexStringToByteArray("0101012E"));
+ ticket1.set(6, hexStringToByteArray("6C0FC000"));
+ ticket1.set(7, hexStringToByteArray("00AE112F"));
+ ticket1.set(8, hexStringToByteArray("C9000152"));
+ ticket1.set(9, hexStringToByteArray("A22C4C8E"));
+ ticket1.set(10, hexStringToByteArray("6C958400"));
+ ticket1.set(11, hexStringToByteArray("04F80000"));
+ ticket1.set(12, hexStringToByteArray("6C958400"));
+ ticket1.set(13, hexStringToByteArray("000F0004"));
+ ticket1.set(14, hexStringToByteArray("F8AE10FE"));
+ ticket1.set(15, hexStringToByteArray("C7123D71"));
+ chip = new ChipOnPaper(ticket1);
+ assertEquals(0, chip.getRemainingRides());
+ assertEquals(0, chip.getRemainingMinutes());
+
+
+ ticket1.set(10, hexStringToByteArray(GttDate.genDate()));
+ chip = new ChipOnPaper(ticket1);
+ assertEquals(100, chip.getRemainingMinutes());
+ }
+
+ @Test
+ public void Smartcard_Count_Ticket_isCorrect() {
+ List list = new ArrayList<>();
+ list.add(hexStringToByteArray("6F208970ABA0B980986C9A09078F098087E0A980DF0101010A0101090E109019011022354345676010019000"));
+ list.add(hexStringToByteArray("0501030C72BF2000026B0CC4435354504C413639423632443936394DC09000"));
+ list.add(hexStringToByteArray("05010100016010016120000000000000000000000000000000000000009000"));
+ list.add(hexStringToByteArray("01050000000000000094F33B94ED9CFFAE10AC40007661A00092EB6D539000"));
+ list.add(hexStringToByteArray("0105000002CC000000930F7B8B267CFFAE10A71800F7BFA000B8CC23E69000"));
+ list.add(hexStringToByteArray("0105000002CC0000009228DB8A3FDCFFAE10A718011440A000F722D0509000"));
+ list.add(hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.add(hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.add(hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.add(hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.add(hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.add(hexStringToByteArray("0501000000216E34F700000B00032100000000006E34F700003000E7BC9000"));
+ list.add(hexStringToByteArray("0501000000216E347B00001400032100000000006E347B000030008A999000"));
+ list.add(hexStringToByteArray("0501000000216E329D00000700032100000000006E329D0000300083079000"));
+ list.add(hexStringToByteArray("06D3DD37A48600000000000000000000000000000000000000000000009000"));
+ SmartCard smartcard = new SmartCard(list);
+
+ assertEquals(6, smartcard.getRemainingRides());
+
+ list.set(1, hexStringToByteArray("0501030C72BB2000026B0CC4535643534C5630315035304C32313941C09000"));
+ list.set(2, hexStringToByteArray("05010100016010016120000000000000000000000000000000000000009000"));
+ list.set(3, hexStringToByteArray("01050000000000000094F33B94ED9CFFAE10AC40007660A00012425D4A9000"));
+ list.set(4, hexStringToByteArray("0105000002CC000000930F7B8B267CFFAE10A71800F7C0A0003DE647B39000"));
+ list.set(5, hexStringToByteArray("0105000002CC0000009228DB8A3FDCFFAE10A718011441A0008AD75F7F9000"));
+ list.set(6, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(7, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(8, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(9, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(10, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(11, hexStringToByteArray("0501000000216E3B7600000700032100000000006E3B76000030001BD19000"));
+ list.set(12, hexStringToByteArray("0501000000216E1DCD00000B00032100000000006E1DCD00003000D3669000"));
+ list.set(13, hexStringToByteArray("0501000000216E194200000F00032100000000006E194200003000089A9000"));
+ list.set(14, hexStringToByteArray("06F4161F9BAD00000000000000000000000000000000000000000000009000"));
+ smartcard = new SmartCard(list);
+
+ assertEquals(3, smartcard.getRemainingRides());
+
+
+ list.set(1, hexStringToByteArray("0501030BE11820000269F05D524D4E42524E36314530384C3231394FC09000"));
+ list.set(2, hexStringToByteArray("05014120014110000000000000000000000000000000000000000000009000"));
+ list.set(3, hexStringToByteArray("0105000002CB000000921D9B8A349CFFAE10A3CA00A4CCA00025EFFF919000"));
+ list.set(4, hexStringToByteArray("0105000002CB000000921D9B8A349CFFAE10A3CA00A4CDA000E885A0709000"));
+ list.set(5, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(6, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(7, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(8, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(9, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(10, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(11, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(12, hexStringToByteArray("0501000000216DE5E60004F800000900000000006DE59D00001000A5079000"));
+ list.set(13, hexStringToByteArray("0501000000216DE5E20004F800000900000000006DE59D00001000D1C69000"));
+ list.set(14, hexStringToByteArray("0FFFFF0FFFFF00000000000000000000000000000000000000000000009000"));
+ smartcard = new SmartCard(list);
+
+ assertEquals(2, smartcard.getRemainingRides());
+
+
+ list.set(1, hexStringToByteArray("0501030C544E2000026AFE93424E5444564436334130364439333348C09000"));
+ list.set(2, hexStringToByteArray("05016120000000000000000000000000000000000000000000000000009000"));
+ list.set(3, hexStringToByteArray("0105000002CC00000092DCDB8AF3DCFFAE10A6B800AEFBA00045509B0E9000"));
+ list.set(4, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(5, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(6, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(7, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(8, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(9, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(10, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(11, hexStringToByteArray("0501000000216DDB0E0004F80003E700000000006DD8A900001000F0639000"));
+ list.set(12, hexStringToByteArray("0501000000216DD8A90004F800004700000000006DD8A900001000EF2A9000"));
+ list.set(13, hexStringToByteArray("0501000000216D653E0004F800004700000000006D62A80000100092DC9000"));
+ list.set(14, hexStringToByteArray("000000274A7A00000000000000000000000000000000000000000000009000"));
+ smartcard = new SmartCard(list);
+
+ assertEquals(4, smartcard.getRemainingRides());
+
+
+ list.set(1, hexStringToByteArray("05010304CEBD2010023E3F64534C4D4E544E3934413135413834314FC29000"));
+ list.set(2, hexStringToByteArray("0501A100000000000000000000000000000000000000000000000000009000"));
+ list.set(3, hexStringToByteArray("010503900390000000C27A3BBA751BFFAE10AC480002AEA0005C37C9E19000"));
+ list.set(4, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(5, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(6, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(7, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(8, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(9, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(10, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(11, hexStringToByteArray("0501000000214410E000000B00032100000000004410E000000000EB969000"));
+ list.set(12, hexStringToByteArray("05010000002143D37700000D000321000000000043D3770000000048749000"));
+ list.set(13, hexStringToByteArray("0501000000214313F500000D00032100000000004313F50000000068FA9000"));
+ list.set(14, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ smartcard = new SmartCard(list);
+
+ assertEquals(0, smartcard.getRemainingRides());
+
+
+ list.set(1, hexStringToByteArray("05010304864E2010023DA7844C444E444E4C39334D30384638393245C29000"));
+ list.set(2, hexStringToByteArray("0501A10001611001A100000000000000000000000000000000000000009000"));
+ list.set(3, hexStringToByteArray("010503900390000000C27A3BBA751BFFAE1045EC00004AA000271C893D9000"));
+ list.set(4, hexStringToByteArray("0105000002CC00000092233B8A3A3CFFAE10A7F10052A3A000065CFC0B9000"));
+ list.set(5, hexStringToByteArray("01050000038F0302589A5AFB93B29CFFAE10FEC000007FA00003D605A29000"));
+ list.set(6, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(7, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(8, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(9, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(10, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(11, hexStringToByteArray("0501000000216E175E0004F800000C00000000006E175E00002000E9AA9000"));
+ list.set(12, hexStringToByteArray("0501000000216DFD4D0004F800000A00000000006DFD3600002000832A9000"));
+ list.set(13, hexStringToByteArray("0501000000216DFD3600000100032100000000006DFD360000200057569000"));
+ list.set(14, hexStringToByteArray("2FC56500000000000000000000000000000000000000000000000000009000"));
+ smartcard = new SmartCard(list);
+
+ assertEquals(5, smartcard.getRemainingRides());
+
+
+ list.set(0, hexStringToByteArray("6F28840E315449432E494341D38012009101A516BF0C13C70800000000381ADC645307063C23C01010019000"));
+ list.set(1, hexStringToByteArray("0501030D1E7B2000026C5AAC434C4D4C534E3630433231473232344BC09000"));
+ list.set(2, hexStringToByteArray("05012110012120012130012140012150000000000000000000000000009000"));
+ list.set(3, hexStringToByteArray("0105000002C800000093CEBB83BEDCFFAE10AC64014437A0005485E4479000"));
+ list.set(4, hexStringToByteArray("0105000002CA00000091B85B81AE1CFFAE10AA0C002857A000E0E8BAA89000"));
+ list.set(5, hexStringToByteArray("0105000002CA00000091B85B81AE1CFFAE10AA0C002858A000292F7D039000"));
+ list.set(6, hexStringToByteArray("0105000002CA00000091B85B81AE1CFFAE10AA0C002859A000051117559000"));
+ list.set(7, hexStringToByteArray("0105000002CA00000091B85B81AE1CFFAE10AA0C00285AA000FBDD7F709000"));
+ list.set(8, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(9, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(10, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(11, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(12, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(13, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(14, hexStringToByteArray("00000900000900000900000900000900000000000000000000000000009000"));
+ smartcard = new SmartCard(list);
+
+ assertEquals(5, smartcard.getRemainingRides());
+
+
+ list.set(1, hexStringToByteArray("05010304864E2010023DA7844C444E444E4C39334D30384638393245C29000"));
+ list.set(2, hexStringToByteArray("0501A10001611001A100014120000000000000000000000000000000009000"));
+ list.set(3, hexStringToByteArray("010503900390000000C27A3BBA751BFFAE1045EC00004AA000271C893D9000"));
+ list.set(4, hexStringToByteArray("0105000002CC00000092233B8A3A3CFFAE10A7F10052A3A000065CFC0B9000"));
+ list.set(5, hexStringToByteArray("01050000038F0302589A5AFB93B29CFFAE10FEC000007FA00003D605A29000"));
+ list.set(6, hexStringToByteArray("0105000002CB00000090501F886720FFAE10A7BD007D57A000C743C9519000"));
+ list.set(7, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(8, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(9, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(10, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(11, hexStringToByteArray("0501000000216F98540004F800000F00000000006F979900002000D87B9000"));
+ list.set(12, hexStringToByteArray("0501000000216F97990004F800000F00000000006F97990000200051459000"));
+ list.set(13, hexStringToByteArray("0501000000216EFB420004F800000F00000000006EF8870000200015E39000"));
+ list.set(14, hexStringToByteArray("0645660FFFFF00000000000000000000000000000000000000000000009000"));
+ smartcard = new SmartCard(list);
+
+ assertEquals(1, smartcard.getRemainingRides());
+ assertEquals("EDISU - Daily", smartcard.getTicketName());
+
+
+ list.set(1, hexStringToByteArray("05010304864E2010023DA7844C444E444E4C39334D30384638393245C29000"));
+ list.set(2, hexStringToByteArray("0501A10001601001A100014120000000000000000000000000000000009000"));
+ list.set(3, hexStringToByteArray("010503900390000000C27A3BBA751BFFAE1045EC00004AA000271C893D9000"));
+ list.set(4, hexStringToByteArray("0105000002CC00000092233B8A3A3CFFAE10A7F10052A3A000065CFC0B9000"));
+ list.set(5, hexStringToByteArray("01050000038F0302589A5AFB93B29CFFAE10FEC000007FA00003D605A29000"));
+ list.set(6, hexStringToByteArray("0105000002CB00000090501F886720FFAE10A7BD007D57A000C743C9519000"));
+ list.set(7, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(8, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(9, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(10, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(11, hexStringToByteArray("0501000000216FB3A20004F800000F00000000006FB3A200004000210C9000"));
+ list.set(12, hexStringToByteArray("0501000000216F98540004F800000F00000000006F979900002000D87B9000"));
+ list.set(13, hexStringToByteArray("0501000000216F97990004F800000F00000000006F97990000200051459000"));
+ list.set(14, hexStringToByteArray("06456607FC3D00000000000000000000000000000000000000000000009000"));
+ smartcard = new SmartCard(list);
+
+ assertEquals(0, smartcard.getRemainingRides());
+
+
+ list.set(1, hexStringToByteArray("050103089E8D2000025DC1A4524E44524C4130304432324C32313959C19000"));
+ list.set(2, hexStringToByteArray("0501A00001F00001A10001F10001A00001F000000000000000000000009000"));
+ list.set(3, hexStringToByteArray("010500000FA100000094231B93FBBCFFAE10AC7000D9B0A0026D5A4AC69000"));
+ list.set(4, hexStringToByteArray("F110060000000000000051504F415500000000000000000000BA9E15609000"));
+ list.set(5, hexStringToByteArray("010500000FA100000091FBDB91D47CFFAE10AD3A005C23A00426C74CDE9000"));
+ list.set(6, hexStringToByteArray("F130040000000000000051504F41000000000000000000000071AB2ADB9000"));
+ list.set(7, hexStringToByteArray("010500000FA100000096717F964A20FFAE10ACB40042C6A006ECF2BC6E9000"));
+ list.set(8, hexStringToByteArray("F150040000000000000051504F4100000000000000000000008A523C0E9000"));
+ list.set(9, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(10, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(11, hexStringToByteArray("0501000000216E05DE0004490005E600000000006E05DE0000300017379000"));
+ list.set(12, hexStringToByteArray("0501000000216BF78A0004000005E600000000006BE44200001000EAB79000"));
+ list.set(13, hexStringToByteArray("0501000000216BF75E0004F800002200000000006BE4420000100059469000"));
+ list.set(14, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ smartcard = new SmartCard(list);
+
+ assertFalse(smartcard.hasTickets());
+ assertTrue(smartcard.hasSubscriptions());
+ assertEquals(0, smartcard.getRemainingRides());
+
+
+ list.set(1, hexStringToByteArray("0501030888942011F24E44044C4D544652433931443539433334324FC29000"));
+ list.set(2, hexStringToByteArray("0501A100010100014110000000000000000000000000000000000000009000"));
+ list.set(3, hexStringToByteArray("0105000003E10388A096609F8E5B80FFAE10FE4F0000A0A000674A13489000"));
+ list.set(4, hexStringToByteArray("0105000003900130FDAA6ADBA2601CFFAE1046110016DAA00032711AF99000"));
+ list.set(5, hexStringToByteArray("0105000002CB00000092887B8A9F7CFFAE10AAE8003EBAA00037DBB1FE9000"));
+ list.set(6, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(7, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(8, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(9, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(10, hexStringToByteArray("00000000000000000000000000000000000000000000000000000000009000"));
+ list.set(11, hexStringToByteArray("05010388A0216E1EBA0004F800001200000000006D95A700001000FA1A9000"));
+ list.set(12, hexStringToByteArray("05010388A0216DF7540004F800004400000000006D95A70000100091A49000"));
+ list.set(13, hexStringToByteArray("05010388A0216DCDFA0004F800000400000000006D95A70000100041CD9000"));
+ list.set(14, hexStringToByteArray("07FDFA00000000000000000000000000000000000000000000000000009000"));
+ smartcard = new SmartCard(list);
+
+ assertFalse(smartcard.hasTickets());
+ assertTrue(smartcard.hasSubscriptions());
+ assertEquals(0, smartcard.getRemainingRides());
+
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 4b9ed6e..e9cd780 100755
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Thu Apr 12 12:46:27 CEST 2018
+#Sat Dec 01 10:58:45 CET 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip