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 }