diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index e6a5826..c56980d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,29 +1,29 @@ apply plugin: 'com.android.application' android { compileSdkVersion 26 defaultConfig { applicationId "org.dslul.ticketreader" minSdkVersion 15 targetSdkVersion 26 - versionCode 1 - versionName "1.0" + versionCode 2 + versionName "1.1" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } 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:26.1.0' implementation 'com.android.support.constraint:constraint-layout:1.0.2' implementation 'com.android.support:design:26.1.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.1' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' } diff --git a/app/release/app-release.apk b/app/release/app-release.apk new file mode 100644 index 0000000..9ec8757 Binary files /dev/null and b/app/release/app-release.apk differ diff --git a/app/release/output.json b/app/release/output.json new file mode 100644 index 0000000..15e4575 --- /dev/null +++ b/app/release/output.json @@ -0,0 +1 @@ +[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":2},"path":"app-release.apk","properties":{"packageId":"org.dslul.ticketreader","split":"","minSdkVersion":"15"}}] \ 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 495167c..45d5b00 100644 --- a/app/src/main/java/org/dslul/ticketreader/MainActivity.java +++ b/app/src/main/java/org/dslul/ticketreader/MainActivity.java @@ -1,213 +1,216 @@ package org.dslul.ticketreader; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.View; import android.view.Menu; import android.view.MenuItem; import android.widget.Button; import android.widget.TextView; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.TimeUnit; import android.content.ClipboardManager; import android.content.ClipData; import android.content.Context; 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; public class MainActivity extends AppCompatActivity { private NfcAdapter mNfcAdapter; private IntentFilter tech; private IntentFilter[] intentFiltersArray; private PendingIntent pendingIntent; private Intent intent; private AlertDialog alertDialog; private String pages = "ERROR"; private TextView dataout; private static final int ACTION_NONE = 0; private static final int ACTION_READ = 1; private int scanAction; // list of NFC technologies detected: private final String[][] techListsArray = new String[][] { new String[] { //MifareUltralight.class.getName(), NfcA.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); mNfcAdapter = NfcAdapter.getDefaultAdapter(this); if (mNfcAdapter == null) { // Stop here, we definitely need NFC Toast.makeText(this, "Questo dispositivo non supporta la tecnologia NFC.", Toast.LENGTH_LONG).show(); finish(); return; } if (!mNfcAdapter.isEnabled()) { Toast.makeText(this, "NFC disabilitato. Attiva l'NFC e torna indietro.", 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); scanAction = ACTION_READ; dataout = new TextView(this); } @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)) { String mTextBufferText = "aa"; NfcThread nfcThread = new NfcThread(intent, scanAction, mTextBufferText, mTextBufferHandler, mToastShortHandler, mToastLongHandler, mShowInfoDialogHandler); nfcThread.start(); scanAction = ACTION_READ; } } private Handler mTextBufferHandler = new Handler() { public void handleMessage(Message msg) { pages = (String)msg.obj; if(pages != "ERROR") { dataout = (TextView) findViewById(R.id.outdata); Parser parser = new Parser(pages); dataout.setText("Data obliterazione: " + parser.getDate() + + System.getProperty("line.separator") + + "Minuti rimanenti: " + parser.getRemainingMinutes() + System.getProperty("line.separator") + "Corse residue: " + parser.getRemainingRides()); } } }; private Handler mToastShortHandler = new Handler() { public void handleMessage(Message msg) { String text = (String)msg.obj; Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show(); } }; private Handler mToastLongHandler = new Handler() { public void handleMessage(Message msg) { String text = (String)msg.obj; Toast.makeText(MainActivity.this, text, Toast.LENGTH_LONG).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) { alertDialog = showAlertDialog("Semplice applicazione opensource per visualizzare le " + - "corse rimanenti nei biglietti GTT."); + "corse rimanenti nei biglietti GTT. \nhttps://github.com/dslul/ticketreader"); alertDialog.show(); 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(); scanAction = ACTION_READ; } }; alertDialog = new AlertDialog.Builder(this) .setTitle("Informazioni") - //.setIcon(R.drawable.ic_launcher) + .setIcon(android.R.drawable.ic_dialog_info) .setMessage(message) + .setPositiveButton("Chiudi", null) .create(); alertDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) { scanAction = ACTION_READ; } }); return alertDialog; } } diff --git a/app/src/main/java/org/dslul/ticketreader/Parser.java b/app/src/main/java/org/dslul/ticketreader/Parser.java index 97e3d22..dfeb2e7 100644 --- a/app/src/main/java/org/dslul/ticketreader/Parser.java +++ b/app/src/main/java/org/dslul/ticketreader/Parser.java @@ -1,79 +1,99 @@ package org.dslul.ticketreader; import android.util.Log; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Calendar; import java.util.Date; import java.util.concurrent.TimeUnit; public class Parser { private String pages; private String date; + private int remainingMins; public Parser(String data) { //if(data == null) this.pages = data; this.date = this.pages.substring(90, 96); } public String getDate() { 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(); } + + Date finalDate = addMinutesToDate(Long.parseLong(this.date, 16), date); + + //calcola minuti rimanenti + Calendar c = Calendar.getInstance(); + long diff = (c.getTime().getTime() - finalDate.getTime()) / 60000; + if(diff >= 90) { + remainingMins = 0; + } else { + remainingMins = (int)(90 - diff); + } + + return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT) - .format(addMinutesToDate(Long.parseLong(this.date, 16), date)); + .format(finalDate); } //TODO: corse in metropolitana (forse bit piĆ¹ significativo pag. 3) public int getRemainingRides() { int tickettype = (int)getBytesFromPage(5, 0, 1); int tickets; if(tickettype == 3) { //extraurbano tickets = (int) (~getBytesFromPage(3, 0, 4)); } else { tickets = (int)(~getBytesFromPage(3, 2, 2)) & 0xFFFF; } return Integer.bitCount(tickets); } + public int getRemainingMinutes() { + return remainingMins; + } + + private long getBytesFromPage(int page, int offset, int bytesnum) { return Long.parseLong( pages.substring(9 * page + offset * 2, 9 * page + offset * 2 + bytesnum * 2), 16); } private static Date addMinutesToDate(long minutes, Date beforeTime){ final long ONE_MINUTE_IN_MILLIS = 60000; long curTimeInMs = beforeTime.getTime(); Date afterAddingMins = new Date(curTimeInMs + (minutes * ONE_MINUTE_IN_MILLIS)); return afterAddingMins; } private static byte[] hexStringToByteArray(String s) { int len = s.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16)); } return data; } }