diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser
index cf0869b..ba473a4 100755
Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ
diff --git a/app/build.gradle b/app/build.gradle
index 7936434..9604cf9 100755
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,34 +1,34 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
defaultConfig {
applicationId "org.dslul.ticketreader"
minSdkVersion 15
targetSdkVersion 27
- versionCode 14
- versionName "2.0"
+ versionCode 16
+ versionName "2.0beta3"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:customtabs:27.1.1'
- implementation 'com.android.support.constraint:constraint-layout:1.1.2'
+ implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:design:27.1.1'
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:15.0.1'
implementation 'com.android.support:cardview-v7:27.1.1'
implementation 'com.yarolegovich:lovely-dialog:1.1.0'
}
diff --git a/app/release/output.json b/app/release/output.json
index e305b20..920a5a5 100755
--- a/app/release/output.json
+++ b/app/release/output.json
@@ -1 +1 @@
-[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":13,"versionName":"1.9.2","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":16,"versionName":"2.0beta3","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/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e5c0b6e..825b3f0 100755
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,33 +1,35 @@
+
\ No newline at end of file
diff --git a/app/src/main/java/org/dslul/ticketreader/MainActivity.java b/app/src/main/java/org/dslul/ticketreader/MainActivity.java
index 34b9695..8f3df93 100755
--- a/app/src/main/java/org/dslul/ticketreader/MainActivity.java
+++ b/app/src/main/java/org/dslul/ticketreader/MainActivity.java
@@ -1,394 +1,404 @@
package org.dslul.ticketreader;
import android.annotation.SuppressLint;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.nfc.tech.IsoDep;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.CardView;
import android.support.v7.widget.Toolbar;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.TableLayout;
import android.widget.TextView;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.TimeUnit;
import android.nfc.NfcAdapter;
import android.nfc.tech.NfcA;
import android.widget.Toast;
import android.content.Intent;
import android.content.IntentFilter;
import android.app.PendingIntent;
import android.os.Handler;
import android.os.Message;
import android.app.AlertDialog;
import android.content.DialogInterface;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
import com.google.android.gms.ads.MobileAds;
import com.yarolegovich.lovelydialog.LovelyCustomDialog;
import com.yarolegovich.lovelydialog.LovelyInfoDialog;
import com.yarolegovich.lovelydialog.LovelyStandardDialog;
import org.dslul.ticketreader.util.HelperFunctions;
public class MainActivity extends AppCompatActivity {
private NfcAdapter mNfcAdapter;
private IntentFilter tech;
private IntentFilter[] intentFiltersArray;
private PendingIntent pendingIntent;
private Intent intent;
private AlertDialog alertDialog;
private Toast currentToast;
private AdView adview;
private ImageView imageNfc;
private CardView ticketCard;
private CardView statusCard;
private ImageView statusImg;
private TextView statoBiglietto;
private TextView infoLabel;
private TableLayout infoTable;
private TextView tipologia;
private TextView dataLabel;
private TextView dataObliterazione;
private TextView corseRimanenti;
private CountDownTimer timer;
private List dump;
// list of NFC technologies detected:
private final String[][] techListsArray = new String[][] {
new String[] {
//MifareUltralight.class.getName(),
NfcA.class.getName()
},
new String[] {
IsoDep.class.getName()
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
adview = (AdView) findViewById(R.id.adView);
imageNfc = (ImageView) findViewById(R.id.imagenfcView);
ticketCard = (CardView) findViewById(R.id.ticketCardView);
statusCard = (CardView) findViewById(R.id.statusCardView);
statusImg = (ImageView) findViewById(R.id.statusImg);
statoBiglietto = (TextView) findViewById(R.id.stato_biglietto);
infoLabel = (TextView) findViewById(R.id.infolabel);
infoTable = (TableLayout) findViewById(R.id.info_table);
tipologia = (TextView) findViewById(R.id.tipologia);
dataLabel = (TextView) findViewById(R.id.validation_or_expire);
dataObliterazione = (TextView) findViewById(R.id.data_obliterazione);
corseRimanenti = (TextView) findViewById(R.id.corse_rimaste);
MobileAds.initialize(this, "ca-app-pub-2102716674867426~1964394961");
AdRequest adRequest = new AdRequest.Builder().build();
adview.loadAd(adRequest);
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (mNfcAdapter == null) {
Toast.makeText(this, R.string.nfc_not_supported, Toast.LENGTH_LONG).show();
finish();
return;
}
if (!mNfcAdapter.isEnabled()) {
Toast.makeText(this, R.string.nfc_disabled, Toast.LENGTH_LONG).show();
startActivity(new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS));
}
tech = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
intentFiltersArray = new IntentFilter[] {tech};
intent = new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
//FLAG_ACTIVITY_REORDER_TO_FRONT FLAG_RECEIVER_REPLACE_PENDING
pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
onNewIntent(getIntent());
+ new LovelyInfoDialog(this)
+ .setTopColorRes(R.color.darkBlueGrey)
+ .setIcon(R.drawable.ic_info_outline_white_36dp)
+ //This will add Don't show again checkbox to the dialog. You can pass any ID as argument
+ .setNotShowAgainOptionEnabled(0)
+ .setNotShowAgainOptionChecked(false)
+ .setTitle("BETA")
+ .setMessage("Questa versione รจ una beta e potrebbe restituire risultati sbagliati. Segnalare per favore ogni incongruenza (insieme ad una copia del contenuto della carta) all'indirizzo email specificato nelle informazioni. Grazie.")
+ .show();
+
}
@Override
protected void onResume() {
super.onResume();
mNfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, this.techListsArray);
}
@Override
protected void onPause() {
// disabling foreground dispatch:
//NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
mNfcAdapter.disableForegroundDispatch(this);
super.onPause();
}
@Override
protected void onNewIntent(Intent intent) {
if (intent.getAction().equals(NfcAdapter.ACTION_TECH_DISCOVERED)) {
NfcThread nfcThread = new NfcThread(getBaseContext(), intent, mContentHandler, mToastShortHandler, mToastLongHandler, mShowInfoDialogHandler);
nfcThread.start();
}
}
@SuppressLint("HandlerLeak")
private Handler mContentHandler = new Handler() {
public void handleMessage(Message msg) {
List dumplist = (List)msg.obj;
dump = dumplist;
if(timer != null)
timer.cancel();
try {
//smartcard
if(dumplist.size() == 15) {
SmartCard smartcard = new SmartCard(dumplist);
- if(smartcard.isSubscription()) {
+ if(smartcard.hasSubscriptions() && !smartcard.hasTickets()) {
dataLabel.setText(R.string.expire_date);
tipologia.setText(smartcard.getSubscriptionName());
- dataObliterazione.setText(smartcard.getDate());
+ dataObliterazione.setText(smartcard.getExpireDate());
- if(smartcard.isExpired()) {
+ if(smartcard.isSubscriptionExpired()) {
corseRimanenti.setText("0");
statoBiglietto.setText(R.string.expired);
statusImg.setImageResource(R.drawable.ic_error_grey_800_36dp);
statusCard.setCardBackgroundColor(getResources().getColor(R.color.colorRed));
} else {
corseRimanenti.setText(R.string.unlimited);
statoBiglietto.setText(R.string.valid);
statusImg.setImageResource(R.drawable.ic_check_circle_grey_800_36dp);
statusCard.setCardBackgroundColor(getResources().getColor(R.color.colorGreen));
}
statusCard.setVisibility(View.VISIBLE);
ticketCard.setVisibility(View.VISIBLE);
infoLabel.setText(R.string.read_another_ticket);
imageNfc.setVisibility(View.GONE);
- } else {
- createTicketInterface(smartcard.getName(),smartcard.getValidationDate(),
+ } else if(smartcard.hasTickets()){
+ createTicketInterface(smartcard.getTicketName(),smartcard.getValidationDate(),
smartcard.getRemainingRides(), smartcard.getRemainingMinutes());
//Toast.makeText(getBaseContext(), R.string.smartcard_tickets_not_supported_yet, Toast.LENGTH_LONG).show();
}
}
//chip on paper
else if(dumplist.size() > 15) {
-
ChipOnPaper chipOnPaper = new ChipOnPaper(dumplist);
createTicketInterface(chipOnPaper.getTypeName(),chipOnPaper.getDate(),
chipOnPaper.getRemainingRides(), chipOnPaper.getRemainingMinutes());
} else {
statusCard.setVisibility(View.GONE);
ticketCard.setVisibility(View.GONE);
infoLabel.setText(R.string.info_instructions);
imageNfc.setVisibility(View.VISIBLE);
}
} catch (Exception ex) {
Toast.makeText(getBaseContext(), R.string.unknown_error, Toast.LENGTH_LONG).show();
Log.d("card", ex.getMessage());
+ ex.printStackTrace();
}
}
};
private void createTicketInterface(String name, String date, int remainingRides, long remainingMinutes) {
dataLabel.setText(R.string.data_obliterazione);
tipologia.setText(name);
dataObliterazione.setText(date);
corseRimanenti.setText(Integer.toString(remainingRides));
if(remainingMinutes != 0) {
statoBiglietto.setText(R.string.in_corso);
statusImg.setImageResource(R.drawable.ic_restore_grey_800_36dp);
statusCard.setCardBackgroundColor(getResources().getColor(R.color.colorBlue));
Calendar calendar = Calendar.getInstance();
int sec = calendar.get(Calendar.SECOND);
timer = new CountDownTimer((remainingMinutes*60 - sec)*1000, 1000) {
public void onTick(long millis) {
statoBiglietto.setText(String.format(getResources().getString(R.string.in_corso),
TimeUnit.MILLISECONDS.toMinutes(millis),
TimeUnit.MILLISECONDS.toSeconds(millis) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))));
}
public void onFinish() {
statoBiglietto.setText(R.string.corse_esaurite);
statusImg.setImageResource(R.drawable.ic_error_grey_800_36dp);
statusCard.setCardBackgroundColor(getResources().getColor(R.color.colorRed));
if(timer != null)
timer.cancel();
}
}.start();
} else if(remainingRides == 0 && remainingMinutes == 0) {
statoBiglietto.setText(R.string.corse_esaurite);
statusImg.setImageResource(R.drawable.ic_error_grey_800_36dp);
statusCard.setCardBackgroundColor(getResources().getColor(R.color.colorRed));
} else if(remainingRides != 0 && remainingMinutes == 0) {
statoBiglietto.setText(String.format(getResources().getString(R.string.corse_disponibili), remainingRides));
statusImg.setImageResource(R.drawable.ic_check_circle_grey_800_36dp);
statusCard.setCardBackgroundColor(getResources().getColor(R.color.colorGreen));
}
statusCard.setVisibility(View.VISIBLE);
ticketCard.setVisibility(View.VISIBLE);
infoLabel.setText(R.string.read_another_ticket);
imageNfc.setVisibility(View.GONE);
}
private Handler mToastShortHandler = new Handler() {
public void handleMessage(Message msg) {
String text = (String)msg.obj;
if(currentToast != null)
currentToast.cancel();
currentToast = Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT);
currentToast.show();
}
};
private Handler mToastLongHandler = new Handler() {
public void handleMessage(Message msg) {
String text = (String)msg.obj;
if(currentToast != null)
currentToast.cancel();
currentToast = Toast.makeText(MainActivity.this, text, Toast.LENGTH_LONG);
currentToast.show();
}
};
private Handler mShowInfoDialogHandler = new Handler() {
public void handleMessage(Message msg) {
String text = (String)msg.obj;
//infoDialog = showInfoDialog(text);
//infoDialog.show();
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_info) {
TextView view = new TextView(getBaseContext());
view.setText(Html.fromHtml(getString(R.string.html_info)));
view.setMovementMethod(LinkMovementMethod.getInstance());
view.setPadding( 40, 40, 40, 40 );
new LovelyCustomDialog(this)
.setTopColorRes(R.color.darkBlueGrey)
.setIcon(R.drawable.ic_info_outline_white_36dp)
.setTitle("Info")
.setView(view)
.show();
return true;
}
if (id == R.id.action_copy_content) {
try {
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
String content = "";
if (dump != null && dump.size() >= 15) {
for (byte[] page : dump) {
content = content.concat(HelperFunctions.byteArrayToHexString(page));
}
ClipData clip = ClipData.newPlainText("content", content);
if (clipboard != null) {
clipboard.setPrimaryClip(clip);
}
Toast.makeText(getBaseContext(), R.string.content_copied, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getBaseContext(), R.string.no_content, Toast.LENGTH_LONG).show();
}
} catch (Exception ex) {
ex.printStackTrace();
}
return true;
}
return super.onOptionsItemSelected(item);
}
private AlertDialog showAlertDialog(String message) {
DialogInterface.OnClickListener dialogInterfaceListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
alertDialog.cancel();
}
};
alertDialog = new AlertDialog.Builder(this)
.setTitle(R.string.information)
.setIcon(android.R.drawable.ic_dialog_info)
.setMessage(message)
.setPositiveButton(R.string.close_dialog, null)
.create();
alertDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
}
});
return alertDialog;
}
}
diff --git a/app/src/main/java/org/dslul/ticketreader/SmartCard.java b/app/src/main/java/org/dslul/ticketreader/SmartCard.java
index dc6e0b9..c02e6b0 100644
--- a/app/src/main/java/org/dslul/ticketreader/SmartCard.java
+++ b/app/src/main/java/org/dslul/ticketreader/SmartCard.java
@@ -1,322 +1,334 @@
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.byteArrayToHexString;
import static org.dslul.ticketreader.util.HelperFunctions.getBytesFromPage;
public class SmartCard {
public enum Type {
BIP,
PYOU,
EDISU
}
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(4003, "Annuale Formula U a Zone");
}};
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 boolean isValid;
private boolean isTicket;
private boolean isSubscription;
private Date startDate;
private Date endDate;
public Contract(byte[] data) {
//get contract type
code = ((data[4] & 0xff) << 8) | data[5] & 0xff;
if(code == 0) {
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 Date getEndDate() {
return endDate;
}
public boolean isContract() {
return isValid;
}
public boolean isSubscription() {
if(isSubscription)
return true;
else
return false;
}
public boolean isTicket() {
if(isTicket)
return true;
else
return false;
}
public String getTypeName() {
if(isTicket)
return ticketCodes.get(code);
else if(isSubscription)
return subscriptionCodes.get(code);
else
return "Sconosciuto";
}
}
private byte[] efEnvironment;
private Date validationDate;
private Date creationDate;
private Type type;
- private List contracts = new ArrayList<>();
- private boolean isSubscription = false;
- private Contract latestContract;
+ private List tickets = new ArrayList<>();
+ private List subscriptions = new ArrayList<>();
+ private Contract subscription;
- private String subscriptionName;
private int ridesLeft = 0;
private long remainingMins;
SmartCard(List dumplist) {
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[] minutes = new byte[3];
System.arraycopy(efEnvironment, 9, minutes, 0, 3);
creationDate = GttDate.decode(minutes);
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;
- Date latestExpireDate = GttDate.getGttEpoch();
for (int i = 0; i < 8; i++) {
Contract contract = new Contract(dumplist.get(i+3));
if(contract.isContract()) {
- if(latestExpireDate.before(contract.getEndDate())) {
- latestExpireDate = contract.getEndDate();
- latestContract = contract;
- }
if(contract.isSubscription()) {
- isSubscription = true;
- subscriptionName = contract.getTypeName();
- if(!isExpired(contract.getEndDate()))
- break;
+ subscriptions.add(contract);
}
if(contract.isTicket()) {
- //ridesLeft += 1;
- if(isExpired(latestContract.getEndDate()))
- isSubscription = false;
- //TODO: count tickets in daily 7 carnets
+ tickets.add(contract);
}
+ }
- //isSubscription = contract.isSubscription();
+ }
- contracts.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(efContractList, efEventLogs1, efEventLogs2, efEventLogs3);
-
//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) {
maxtime = GttDate.getMinutesUntilMidnight();
}
if(diff >= maxtime) {
remainingMins = 0;
} else {
remainingMins = maxtime - diff;
}
-
}
private int countTickets(byte[] contractsList, byte[] evLogs1, byte[] evLogs2, byte[] evLogs3) {
int count = 0;
for (int i = 2; i < 24; i+=3) {
- int num = abs(contractsList[i+1]) >> 4;
- //int used = contractsList[i+2];
- if(num != 0 && num <= 8 && (contractsList[i]&0x0f) != 0) {
+ //int pos = abs(contractsList[i+1]) >> 4;
+ //real pos is given by the 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 lognum1 = abs(evLogs1[25]) >> 4;
int lognum2 = abs(evLogs2[25]) >> 4;
int lognum3 = abs(evLogs3[25]) >> 4;
//TODO: find out how to count multi daily 7 tickets
- if(num != lognum1 && num != lognum2 && num != lognum3)
+ if(pos != lognum1 && pos != lognum2 && pos != lognum3)
count += 1;
}
}
return count;
}
- public String getName() {
- return type + " - " + latestContract.getTypeName();
+ public String getTicketName() {
+ if(hasTickets())
+ return type + " - " + tickets.get(0).getTypeName();
+ else
+ return "Invalid";
}
public String getSubscriptionName() {
- return type + " - " + subscriptionName;
+ if(hasSubscriptions())
+ return type + " - " + subscription.getTypeName();
+ else
+ return "Invalid";
+ }
+
+ public boolean hasTickets() {
+ return ridesLeft != 0;
}
- public String getDate() {
+ public boolean hasSubscriptions() {
+ return subscriptions.size() != 0;
+ }
+
+ public String getExpireDate() {
return DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT)
- .format(latestContract.getEndDate());
+ .format(subscription.getEndDate());
}
public String getValidationDate() {
return DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT)
.format(validationDate);
}
- public boolean isExpired() {
+ public boolean isSubscriptionExpired() {
Calendar c = Calendar.getInstance();
- return c.getTime().after(latestContract.getEndDate());
+ 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() {
return remainingMins;
}
- public boolean isSubscription() {
- return isSubscription;
- }
}
diff --git a/app/src/test/java/org/dslul/ticketreader/ChipOnPaperUnitTest.java b/app/src/test/java/org/dslul/ticketreader/ChipOnPaperUnitTest.java
index ae9d4cd..57d8ada 100755
--- a/app/src/test/java/org/dslul/ticketreader/ChipOnPaperUnitTest.java
+++ b/app/src/test/java/org/dslul/ticketreader/ChipOnPaperUnitTest.java
@@ -1,108 +1,136 @@
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("05012060014020014030014040014050012010012070012180000000009000"));
- list.set(11, hexStringToByteArray("0501000000216DA6820004F800002A00000000006DA68200008000F9249000"));
- list.set(12, hexStringToByteArray("0501000000216D9B2C0004F800002A00000000006D9B2C000060008D809000"));
- list.set(13, hexStringToByteArray("0501000000216D959E0004F800002A00000000006D959E00001000674E9000"));
+ 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());
+
+
+ //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