diff --git a/app/build.gradle b/app/build.gradle
index ae4e792..f44f8ea 100755
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,34 +1,37 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 27
+ compileSdkVersion 28
defaultConfig {
applicationId "org.dslul.ticketreader"
minSdkVersion 15
- targetSdkVersion 27
- versionCode 20
- versionName "2.0"
+ targetSdkVersion 28
+ versionCode 31
+ versionName "2.1.6"
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 fileTree(include: ['*.jar'], dir: 'libs')
+ 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:27.1.1'
+ 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:15.0.1'
- implementation 'com.android.support:cardview-v7:27.1.1'
+ 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/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 825b3f0..7d284e6 100755
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,35 +1,42 @@
+
+
+
+
+ android:resource="@xml/filter_nfc"/>
+
\ No newline at end of file
diff --git a/app/src/main/java/org/dslul/ticketreader/NfcThread.java b/app/src/main/java/org/dslul/ticketreader/NfcThread.java
index 5692a9c..27f2624 100755
--- a/app/src/main/java/org/dslul/ticketreader/NfcThread.java
+++ b/app/src/main/java/org/dslul/ticketreader/NfcThread.java
@@ -1,214 +1,231 @@
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/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml
index 64806f1..ad84690 100755
--- a/app/src/main/res/layout/content_main.xml
+++ b/app/src/main/res/layout/content_main.xml
@@ -1,222 +1,227 @@
+
+
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index a8d8017..404988e 100755
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -1,37 +1,37 @@
Lettore Biglietti GTT
Info
Data obliterazione:
Minuti rimanenti:
Corse rimaste:
Avvicina un biglietto alla parte posteriore del dispositivo per effettuare la scansione
Immagine biglietto nfc
Per leggere un altro biglietto, avvicinalo nuovamente al sensore NFC
%d corse disponibili
In corso %d:%d
Corse esaurite
Dettagli biglietto
Questo dispositivo non supporta la tecnologia NFC.
NFC disabilitato. Attiva l\'NFC e premi il tasto indietro.
Informazioni
Chiudi
- Semplice applicazione opensource per visualizzare le corse rimanenti nei biglietti GTT.
Se riscontri problemi durante l\'utilizzo dell\'app, scrivimi a questo indirizzo email, incollando una copia del contenuto della carta (effettuata dal menu).
Semplice applicazione opensource per visualizzare le corse rimanenti nei biglietti GTT.
Se riscontri problemi durante l\'utilizzo dell\'app, scrivimi a questo indirizzo email, incollando una copia del contenuto della carta (effettuata dal menu).
Biglietto non valido!
Biglietto letto correttamente.
Lettura fallita, riprovare
Errore di comunicazione. Riprova
Data di scadenza:
Tessera non valida
Tessera letta correttamente.
Scaduto
Illimitato
Valido
Tessere con biglietti non ancora supportate, stay tuned…
Segnala errori
Errore sconosciuto, contatta lo sviluppatore per risolvere questo problema.
Copia contenuto
Contenuto copiato negli appunti
Scansiona un biglietto prima di effettuare la copia del contenuto
Tessera vuota!
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 654620b..eaa42a0 100755
--- a/build.gradle
+++ b/build.gradle
@@ -1,30 +1,30 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.1.4'
+ classpath 'com.android.tools.build:gradle:3.2.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
maven {
url "https://maven.google.com"
}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}