diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 5e84ee7..aa6b1e9 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,128 +1,129 @@ diff --git a/ic_launcher-playstore.png b/ic_launcher-playstore.png new file mode 100644 index 0000000..07ca9b1 Binary files /dev/null and b/ic_launcher-playstore.png differ diff --git a/ic_launcher-web.png b/ic_launcher-web.png deleted file mode 120000 index 69597d4..0000000 --- a/ic_launcher-web.png +++ /dev/null @@ -1 +0,0 @@ -res/drawable-xxxhdpi/ic_launcher.png \ No newline at end of file diff --git a/res/drawable-hdpi/ic_launcher.png b/res/drawable-hdpi/ic_launcher.png index 21d81e5..266a759 100644 Binary files a/res/drawable-hdpi/ic_launcher.png and b/res/drawable-hdpi/ic_launcher.png differ diff --git a/res/drawable-mdpi/ic_launcher.png b/res/drawable-mdpi/ic_launcher.png index 3a46e02..71abcbe 100644 Binary files a/res/drawable-mdpi/ic_launcher.png and b/res/drawable-mdpi/ic_launcher.png differ diff --git a/res/drawable-xhdpi/ic_launcher.png b/res/drawable-xhdpi/ic_launcher.png index f6e9727..7f0be0d 100644 Binary files a/res/drawable-xhdpi/ic_launcher.png and b/res/drawable-xhdpi/ic_launcher.png differ diff --git a/res/drawable-xxhdpi/ic_launcher.png b/res/drawable-xxhdpi/ic_launcher.png index 560bc84..643c9c6 100644 Binary files a/res/drawable-xxhdpi/ic_launcher.png and b/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/res/drawable-xxxhdpi/ic_launcher.png b/res/drawable-xxxhdpi/ic_launcher.png index 3095109..7cd95e5 100644 Binary files a/res/drawable-xxxhdpi/ic_launcher.png and b/res/drawable-xxxhdpi/ic_launcher.png differ diff --git a/res/menu/main.xml b/res/menu/main.xml index bb8fa22..9eda3d3 100644 --- a/res/menu/main.xml +++ b/res/menu/main.xml @@ -1,57 +1,53 @@ - \ No newline at end of file diff --git a/res/mipmap-anydpi-v26/ic_launcher.xml b/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..036d09b --- /dev/null +++ b/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/mipmap-anydpi-v26/ic_launcher_round.xml b/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..036d09b --- /dev/null +++ b/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/mipmap-hdpi/ic_launcher.png b/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..ffc7e49 Binary files /dev/null and b/res/mipmap-hdpi/ic_launcher.png differ diff --git a/res/mipmap-hdpi/ic_launcher_background.png b/res/mipmap-hdpi/ic_launcher_background.png new file mode 100644 index 0000000..f4c6132 Binary files /dev/null and b/res/mipmap-hdpi/ic_launcher_background.png differ diff --git a/res/mipmap-hdpi/ic_launcher_foreground.png b/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..5df23f9 Binary files /dev/null and b/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/res/mipmap-hdpi/ic_launcher_round.png b/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..ff37f4b Binary files /dev/null and b/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/res/mipmap-mdpi/ic_launcher.png b/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..2289815 Binary files /dev/null and b/res/mipmap-mdpi/ic_launcher.png differ diff --git a/res/mipmap-mdpi/ic_launcher_background.png b/res/mipmap-mdpi/ic_launcher_background.png new file mode 100644 index 0000000..ccfc690 Binary files /dev/null and b/res/mipmap-mdpi/ic_launcher_background.png differ diff --git a/res/mipmap-mdpi/ic_launcher_foreground.png b/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..8ff1620 Binary files /dev/null and b/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/res/mipmap-mdpi/ic_launcher_round.png b/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..eb8e9ef Binary files /dev/null and b/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/res/mipmap-xhdpi/ic_launcher.png b/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..e6352dc Binary files /dev/null and b/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/res/mipmap-xhdpi/ic_launcher_background.png b/res/mipmap-xhdpi/ic_launcher_background.png new file mode 100644 index 0000000..2b64a14 Binary files /dev/null and b/res/mipmap-xhdpi/ic_launcher_background.png differ diff --git a/res/mipmap-xhdpi/ic_launcher_foreground.png b/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..d210af2 Binary files /dev/null and b/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/res/mipmap-xhdpi/ic_launcher_round.png b/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..e8ac438 Binary files /dev/null and b/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/res/mipmap-xxhdpi/ic_launcher.png b/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..ad2af1e Binary files /dev/null and b/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/res/mipmap-xxhdpi/ic_launcher_background.png b/res/mipmap-xxhdpi/ic_launcher_background.png new file mode 100644 index 0000000..2a8f406 Binary files /dev/null and b/res/mipmap-xxhdpi/ic_launcher_background.png differ diff --git a/res/mipmap-xxhdpi/ic_launcher_foreground.png b/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..9ba9e5f Binary files /dev/null and b/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/res/mipmap-xxhdpi/ic_launcher_round.png b/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..e0dcec9 Binary files /dev/null and b/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/res/mipmap-xxxhdpi/ic_launcher.png b/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..5580ae4 Binary files /dev/null and b/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/res/mipmap-xxxhdpi/ic_launcher_background.png b/res/mipmap-xxxhdpi/ic_launcher_background.png new file mode 100644 index 0000000..fa22841 Binary files /dev/null and b/res/mipmap-xxxhdpi/ic_launcher_background.png differ diff --git a/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..960fba0 Binary files /dev/null and b/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/res/mipmap-xxxhdpi/ic_launcher_round.png b/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..f55623c Binary files /dev/null and b/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index b7bafc1..7097089 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -1,141 +1,142 @@ Stai utilizzando l\'ultimo ritrovato in materia di rispetto della tua privacy. Cerca QR Code Numero fermata Nome fermata Inserisci il numero della fermata Inserisci il nome della fermata Verifica l\'accesso ad Internet! Sembra che nessuna fermata abbia questo nome Errore di lettura del sito 5T/GTT (dannato sito!) Fermata: %1$s Linee: %1$s Scegli la fermata… Nessun passaggio Nessun QR code Preferiti Aiuto Informazioni Più informazioni - News - Invia bug + Hack + https://gitpull.it/w/librebusto/it/ Codice sorgente Licenza Incontra l\'autore Fermata aggiunta ai preferiti Impossibile aggiungere ai preferiti (memoria piena o database corrotto?)! Preferiti Mappa Nessun preferito? Arghh!\nSchiaccia sulla stella di una fermata per aggiungerla a questa lista! Rimuovi Rinomina Rinomina fermata Reset Informazioni Tocca la stella per aggiungere la fermata ai preferiti\n\nCome leggere gli orari: \n   12:56* Orario in tempo reale\n   12:56   Orario programmato\n\nTrascina giù per aggiornare l\'orario. \nTocca a lungo su Fonte Orari per cambiare sorgente degli orari di arrivo. OK! Benvenuto!

Grazie per aver scelto BusTO, un\'app indipendente da GTT/5T, per spostarsi a Torino attraverso software libero:

Perché usare BusTO?

- Non sei monitorato
- Non ci sono pubblicità
- La tua privacy è al sicuro
- Inoltre l\'app è molto leggera!

Come Funziona?

Quest\'app ottiene i passaggi dei bus in tempo reale filtrando i dati forniti pubblicamente sul sito www.gtt.to.it o www.5t.torino.it "per uso personale".

Ingredienti:
- Fabio Mazza attuale rockstar developer anziano.
- Andrea Ugo attuale rockstar developer in formazione.
- - Ludovico Pavesi ex rockstar developer anziano.
+ - Silviu Chiriac designer del logo 2021.
+ - Ludovico Pavesi ex rockstar developer anziano asd.
- Valerio Bozzolan attuale manutentore.
- Marco Gagino apprezzato ex collaboratore, ideatore icona e grafica.
- JSoup libreria per "web scaping".
- Google icone e libreria di supporto per il Material Design.
- Tutti i contributori!

Licenze

L\'app e il relativo codice sorgente sono distribuiti sotto la licenza GNU General Public License v3+. Ciò significa che puoi usare, studiare, migliorare e ricondividere quest\'app con qualunque mezzo e per qualsiasi scopo: a patto di mantenere sempre questi diritti a tua volta e di dare credito a Valerio Bozzolan.

Note

Quest\'applicazione è rilasciata nella speranza che sia utile a tutti ma senza NESSUNA garanzia.

Buon utilizzo! :)

]]>
Nome troppo corto, digita più caratteri e riprova %1$s verso %2$s %s (destinazione sconosciuta) Errore interno inaspettato, impossibile estrarre dati dal sito GTT/5T Visualizza sulla mappa Non trovo un\'applicazione dove mostrarla Posizione della fermata non trovata Fermate vicine Ricerca della posizione in corso… Nessuna fermata nei dintorni Preferenze Aggiornamento del database… Numero di fermate Impostazioni Impostazioni Fermate recenti Impostazioni generali Gestione del database Comincia aggiornamento manuale del database Abilitare il GPS Raggio di ricerca Funzionalità sperimentali arriva alle alla fermata Mostra arrivi Mostra fermate Arrivi qui vicino Fermata rimossa dai preferiti La mia posizione Segui posizione Fonte orari: %1$s App GTT Sito GTT Sito 5T Torino Cambiamento sorgente orari… Premi a lungo per cambiare la sorgente degli orari Canale unico delle notifiche Chiesto troppe volte per il permesso %1$s Non si può usare questa funzionalità senza il permesso di archivio di archivio L\'app è andata in crash. Invia il report agli sviluppatori toccando OK. \n Il report potrebbe contenere informazioni sulla tua configurazione del telefono, o sullo stato al momento del crash. \n Tutte le informazioni sensibili nel report verranno utilizzate solo per scopi diagnostici dagli sviluppatori, e non verranno mai pubblicate e/o divulgate. L\'applicazione è crashata, e il crash report è stato messo negli allegati. Se vuoi, descrivi cosa stavi facendo prima del crash: \n
diff --git a/res/values/ic_launcher_background.xml b/res/values/ic_launcher_background.xml new file mode 100644 index 0000000..ae92c38 --- /dev/null +++ b/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #4A6D95 + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index a719a37..df3e375 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1,151 +1,152 @@ BusTO You\'re using the latest in technology when it comes to respecting your privacy. Search Scan QR Code Bus stop number Bus stop name Insert bus stop number Insert bus stop name %1$s towards %2$s %s (unknown destination) Verify your Internet connection! Seems that no bus stop have this name Error parsing the 5T/GTT website (damn site!) Name too short, type more characters and retry Arrivals at: %1$s Choose the bus stop… Lines: %1$s No timetable found No QR code Unexpected internal error, cannot extract data from GTT/5T website Help About More about - News releases - Bug submission + Hack + https://gitpull.it/w/librebusto/en/ Source code - Licence + Licence11 Meet the author Bus stop is now in your favorites Bus stop removed from your favorites Favorites Favorites Map No favorites? Arghh! Press on a bus stop star to populate this list! Delete Rename Rename the bus stop Reset About Tap the star to add the bus stop to the favourites\n\nHow to read timelines:\n   12:56* Real-time arrivals\n   12:56   Scheduled arrivals\n\nPull down to refresh the timetable \n Long press on Arrivals source to change the source of the arrival times GOT IT! Welcome!

Thanks for using BusTO, a "politically" independent app useful to move around Torino using a Free/Libre software.

Why use this app?

- You\'ll never be tracked
- You\'ll never see boring ads
- We\'ll always respect your privacy
- Moreover, it\'s lightweight!

How does it work?

This app will show you bus timetables gathering data from www.gtt.to.it or www.5t.torino.it "for personal use".

Who worked on BusTO:
- Fabio Mazza current senior rockstar developer.
- Andrea Ugo current junior rockstar developer.
- - Ludovico Pavesi previous senior rockstar developer.
+ - Silviu Chiriac designer of the 2021 logo.
+ - Ludovico Pavesi previous senior rockstar developer asd.
- Valerio Bozzolan maintainer and infrastructure sponsor.
- Marco Gagino contributor and icon creator.
- JSoup web scraper library.
- makovkastar floating buttons.
- Google Material Design icons.
- All the contributors!

Licenses

The app and the related source code are released by Valerio Bozzolan under the terms of the GNU General Public License v3+). So everyone is allowed to use, to study, to improve and to share this app by any kind of means and for any purpose: under the conditions of maintaining this rights and of attributing the original work to Valerio Bozzolan.

Notes

This app has been developed hoping to be useful to everyone but without ANY warranty.

This translation is kindly provided by Riccardo Caniato and Marco Gagino.

Get involved! :)

]]>
Cannot add to favorites (storage full or corrupted database?)! View on a map Cannot find any application to show it in Cannot find the position of the stop ListFragment - BusTO it.reyboz.bustorino.preferences db_is_updating Nearby stops Nearby connections Finding the position… No stops nearby Number of stops Preferences Settings Settings Experimental features Search radius Recent stops General settings Database management Launch manual database update Please enable GPS Database update in progress… is arriving at at the stop %1$s - %2$s Show arrivals Show stops Center on my location Follow me Arrivals source: %1$s GTT App GTT Website 5T Torino website Changing arrival times source… Long press to change the source of arrivals Default Default channel for notifications Asked for %1$s permission too many times Cannot use the map with the storage permission! storage The application has crashed. If you want, you can send the send the report via email to the developers by pressing \"OK\". \n Note that sensitive information may be contained in the report, and if so, it will be only used for diagnostic purposes by the developers, and never published. The application crashed and the crash report is in the attachments. Please describe what you were doing before the crash: \n
diff --git a/src/it/reyboz/bustorino/ActivityMain.java b/src/it/reyboz/bustorino/ActivityMain.java index aa2e794..1557e99 100644 --- a/src/it/reyboz/bustorino/ActivityMain.java +++ b/src/it/reyboz/bustorino/ActivityMain.java @@ -1,963 +1,960 @@ /* BusTO - Arrival times for Turin public transports. Copyright (C) 2014 Valerio Bozzolan This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package it.reyboz.bustorino; import android.Manifest; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.res.Resources; import android.database.sqlite.SQLiteDatabase; import android.location.*; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import androidx.annotation.NonNull; import androidx.core.app.ActivityCompat; import androidx.work.BackoffPolicy; import androidx.work.Constraints; import androidx.work.ExistingPeriodicWorkPolicy; import androidx.work.NetworkType; import androidx.work.PeriodicWorkRequest; import androidx.work.WorkInfo; import androidx.work.WorkManager; import com.google.android.material.snackbar.Snackbar; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import androidx.core.app.NavUtils; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.*; import com.google.zxing.integration.android.IntentIntegrator; import com.google.zxing.integration.android.IntentResult; import com.google.android.material.floatingactionbutton.FloatingActionButton; import it.reyboz.bustorino.backend.*; import it.reyboz.bustorino.fragments.*; import it.reyboz.bustorino.middleware.*; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; public class ActivityMain extends GeneralActivity implements FragmentListener { /* * Layout elements */ private EditText busStopSearchByIDEditText; private EditText busStopSearchByNameEditText; private ProgressBar progressBar; private TextView howDoesItWorkTextView; private Button hideHintButton; private MenuItem actionHelpMenuItem; private SwipeRefreshLayout swipeRefreshLayout; private FloatingActionButton floatingActionButton; private FragmentManager framan; private Snackbar snackbar; /* * Search mode */ private static final int SEARCH_BY_NAME = 0; private static final int SEARCH_BY_ID = 1; private static final int SEARCH_BY_ROUTE = 2; // TODO: implement this -- https://gitpull.it/T12 private int searchMode; private ImageButton addToFavorites; /* * Options */ private final String OPTION_SHOW_LEGEND = "show_legend"; private static final String DEBUG_TAG = "BusTO - MainActivity"; /* // useful for testing: public class MockFetcher implements ArrivalsFetcher { @Override public Palina ReadArrivalTimesAll(String routeID, AtomicReference res) { SystemClock.sleep(5000); res.set(result.SERVER_ERROR); return new Palina(); } } private ArrivalsFetcher[] ArrivalFetchers = {new MockFetcher(), new MockFetcher(), new MockFetcher(), new MockFetcher(), new MockFetcher()};*/ private ArrivalsFetcher[] arrivalsFetchers = new ArrivalsFetcher[]{new FiveTAPIFetcher(), new GTTJSONFetcher(), new FiveTScraperFetcher()}; private StopsFinderByName[] stopsFinderByNames = new StopsFinderByName[]{new GTTStopsFetcher(), new FiveTStopsFetcher()}; /* * Position */ //Fine location criteria private final Criteria cr = new Criteria(); private boolean pendingNearbyStopsRequest = false; private LocationManager locmgr; private FragmentHelper fh; ///////////////////////////////// EVENT HANDLERS /////////////////////////////////////////////// /* * @see swipeRefreshLayout */ private final Handler theHandler = new Handler(); private final Runnable refreshing = new Runnable() { public void run() { if (framan.findFragmentById(R.id.resultFrame) instanceof ArrivalsFragment) { ArrivalsFragment fragment = (ArrivalsFragment) framan.findFragmentById(R.id.resultFrame); String stopName = fragment.getStopID(); new AsyncDataDownload(fh, fragment.getCurrentFetchersAsArray()).execute(stopName); } else //we create a new fragment, which is WRONG new AsyncDataDownload(fh, arrivalsFetchers).execute(); } }; //// MAIN METHOD /// @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); framan = getSupportFragmentManager(); final SharedPreferences theShPr = getMainSharedPreferences(); /* * Database Access */ setContentView(R.layout.activity_main); busStopSearchByIDEditText = findViewById(R.id.busStopSearchByIDEditText); busStopSearchByNameEditText = findViewById(R.id.busStopSearchByNameEditText); progressBar = findViewById(R.id.progressBar); howDoesItWorkTextView = findViewById(R.id.howDoesItWorkTextView); hideHintButton = findViewById(R.id.hideHintButton); swipeRefreshLayout = findViewById(R.id.listRefreshLayout); floatingActionButton = findViewById(R.id.floatingActionButton); framan.addOnBackStackChangedListener(() -> Log.d("MainActivity, BusTO", "BACK STACK CHANGED")); busStopSearchByIDEditText.setSelectAllOnFocus(true); busStopSearchByIDEditText .setOnEditorActionListener((v, actionId, event) -> { // IME_ACTION_SEARCH alphabetical option if (actionId == EditorInfo.IME_ACTION_SEARCH) { onSearchClick(v); return true; } return false; }); busStopSearchByNameEditText .setOnEditorActionListener((v, actionId, event) -> { // IME_ACTION_SEARCH alphabetical option if (actionId == EditorInfo.IME_ACTION_SEARCH) { onSearchClick(v); return true; } return false; }); // Called when the layout is pulled down swipeRefreshLayout .setOnRefreshListener(() -> theHandler.post(refreshing)); /** * @author Marco Gagino!!! */ //swipeRefreshLayout.setColorSchemeColors(R.color.blue_500, R.color.orange_500); // setColorScheme is deprecated, setColorSchemeColors isn't swipeRefreshLayout.setColorSchemeResources(R.color.blue_500, R.color.orange_500); fh = new FragmentHelper(this, R.id.listRefreshLayout, R.id.resultFrame); setSearchModeBusStopID(); //---------------------------- START INTENT CHECK QUEUE ------------------------------------ // Intercept calls from URL intent boolean tryedFromIntent = false; String busStopID = null; String busStopDisplayName = null; Uri data = getIntent().getData(); if (data != null) { busStopID = getBusStopIDFromUri(data); tryedFromIntent = true; } // Intercept calls from other activities if (!tryedFromIntent) { Bundle b = getIntent().getExtras(); if (b != null) { busStopID = b.getString("bus-stop-ID"); busStopDisplayName = b.getString("bus-stop-display-name"); /** * I'm not very sure if you are coming from an Intent. * Some launchers work in strange ways. */ tryedFromIntent = busStopID != null; } } //---------------------------- END INTENT CHECK QUEUE -------------------------------------- if (busStopID == null) { // Show keyboard if can't start from intent // JUST DON'T // showKeyboard(); // You haven't obtained anything... from an intent? if (tryedFromIntent) { // This shows a luser warning Toast.makeText(getApplicationContext(), R.string.insert_bus_stop_number_error, Toast.LENGTH_SHORT).show(); } } else { // If you are here an intent has worked successfully setBusStopSearchByIDEditText(busStopID); /* //THIS PART SHOULDN'T BE NECESSARY SINCE THE LAST SUCCESSFULLY SEARCHED BUS // STOP IS ADDED AUTOMATICALLY Stop nextStop = new Stop(busStopID); // forcing it as user name even though it could be standard name, it doesn't really matter nextStop.setStopUserName(busStopDisplayName); //set stop as last succe fh.setLastSuccessfullySearchedBusStop(nextStop); */ createFragmentForStop(busStopID); } //Try (hopefully) database update //TODO: Check if service shows the notification //Old code for the db update //DatabaseUpdateService.startDBUpdate(getApplicationContext()); PeriodicWorkRequest wr = new PeriodicWorkRequest.Builder(DBUpdateWorker.class, 1, TimeUnit.DAYS) .setBackoffCriteria(BackoffPolicy.LINEAR, 30, TimeUnit.MINUTES) .setConstraints(new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED) .build()) .build(); final WorkManager workManager = WorkManager.getInstance(this); final int version = theShPr.getInt(DatabaseUpdate.DB_VERSION_KEY, -10); if (version >= 0) workManager.enqueueUniquePeriodicWork(DBUpdateWorker.DEBUG_TAG, ExistingPeriodicWorkPolicy.KEEP, wr); else workManager.enqueueUniquePeriodicWork(DBUpdateWorker.DEBUG_TAG, ExistingPeriodicWorkPolicy.REPLACE, wr); /* Set database update */ workManager.getWorkInfosForUniqueWorkLiveData(DBUpdateWorker.DEBUG_TAG) .observe(this, workInfoList -> { // If there are no matching work info, do nothing if (workInfoList == null || workInfoList.isEmpty()) { return; } Log.d(DEBUG_TAG, "WorkerInfo: "+workInfoList); boolean showProgress = false; for (WorkInfo workInfo : workInfoList) { if (workInfo.getState() == WorkInfo.State.RUNNING) { showProgress = true; } } if (showProgress) { createDefaultSnackbar(); } else { if(snackbar!=null) { snackbar.dismiss(); snackbar = null; } } }); //locationHandler = new GPSLocationAdapter(getApplicationContext()); //--------- NEARBY STOPS--------// //SETUP LOCATION locmgr = (LocationManager) getSystemService(LOCATION_SERVICE); cr.setAccuracy(Criteria.ACCURACY_FINE); cr.setAltitudeRequired(false); cr.setBearingRequired(false); cr.setCostAllowed(true); cr.setPowerRequirement(Criteria.NO_REQUIREMENT); //We want the nearby bus stops! theHandler.post(new NearbyStopsRequester()); //If there are no providers available, then, wait for them Log.d("MainActivity", "Created"); } /** * Reload bus stop timetable when it's fulled resumed from background. */ /** * @Override protected void onPostResume() { * super.onPostResume(); * Log.d("ActivityMain", "onPostResume fired. Last successfully bus stop ID: " + fh.getLastSuccessfullySearchedBusStop()); * if (searchMode == SEARCH_BY_ID && fh.getLastSuccessfullySearchedBusStop() != null) { * setBusStopSearchByIDEditText(fh.getLastSuccessfullySearchedBusStop().ID); * new AsyncDataDownload(AsyncDataDownload.RequestType.ARRIVALS,fh).execute(); * } else { * //we have new activity or we don't have a new searched stop. * //Let's search stops nearby * LocationManager locManager = (LocationManager) getSystemService(LOCATION_SERVICE); * Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.resultFrame); *

*

* } * //show the FAB since it remains hidden * floatingActionButton.show(); *

* } **/ @Override protected void onPause() { super.onPause(); fh.stopLastRequestIfNeeded(); fh.setBlockAllActivities(true); locmgr.removeUpdates(locListener); } @Override protected void onResume() { super.onResume(); fh.setBlockAllActivities(false); //TODO: check if current LiveData-bound observer works if (pendingNearbyStopsRequest) theHandler.post(new NearbyStopsRequester()); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); actionHelpMenuItem = menu.findItem(R.id.action_help); return true; } /** * Callback fired when a MenuItem is selected * * @param item * @return */ @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. + Resources res = getResources(); switch (item.getItemId()) { case android.R.id.home: // Respond to the action bar's Up/Home button NavUtils.navigateUpFromSameTask(this); return true; case R.id.action_help: showHints(); return true; case R.id.action_favorites: startActivity(new Intent(ActivityMain.this, ActivityFavorites.class)); return true; case R.id.action_map: //ensure storage permission is granted final String permission = Manifest.permission.WRITE_EXTERNAL_STORAGE; int result = askForPermissionIfNeeded(permission, STORAGE_PERMISSION_REQ); switch (result) { case PERMISSION_OK: startActivity(new Intent(ActivityMain.this, ActivityMap.class)); break; case PERMISSION_ASKING: permissionDoneRunnables.put(permission, () -> startActivity(new Intent(ActivityMain.this, ActivityMap.class))); break; case PERMISSION_NEG_CANNOT_ASK: - Resources res = getResources(); String storage_perm = res.getString(R.string.storage_permission); String text = res.getString(R.string.too_many_permission_asks, storage_perm); Toast.makeText(getApplicationContext(),text, Toast.LENGTH_LONG).show(); } return true; case R.id.action_about: startActivity(new Intent(ActivityMain.this, ActivityAbout.class)); return true; - case R.id.action_news: - openIceweasel("https://gitpull.it/w/librebusto/#how-to-get-news"); - return true; - case R.id.action_bugs: - openIceweasel("https://gitpull.it/w/librebusto/#how-to-create-a-bug-feature"); + case R.id.action_hack: + openIceweasel(res.getString(R.string.hack_url)); return true; case R.id.action_source: - openIceweasel("https://gitpull.it/w/librebusto/#how-to-hack-busto"); + openIceweasel("https://gitpull.it/source/libre-busto/"); return true; case R.id.action_licence: openIceweasel("https://www.gnu.org/licenses/gpl-3.0.html"); return true; case R.id.action_settings: Log.d("MAINBusTO", "Pressed button preferences"); startActivity(new Intent(ActivityMain.this, ActivitySettings.class)); } return super.onOptionsItemSelected(item); } /** * OK this is pure shit * * @param v View clicked */ public void onSearchClick(View v) { if (searchMode == SEARCH_BY_ID) { String busStopID = busStopSearchByIDEditText.getText().toString(); createFragmentForStop(busStopID); } else { // searchMode == SEARCH_BY_NAME String query = busStopSearchByNameEditText.getText().toString(); //new asyncWgetBusStopSuggestions(query, stopsDB, StopsFindersByNameRecursionHelper); new AsyncDataDownload(fh, stopsFinderByNames).execute(query); } } /** * PERMISSION STUFF **/ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { case PERMISSION_REQUEST_POSITION: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { setOption(LOCATION_PERMISSION_GIVEN, true); //if we sent a request for a new NearbyStopsFragment if (pendingNearbyStopsRequest) { pendingNearbyStopsRequest = false; theHandler.post(new NearbyStopsRequester()); } } else { //permission denied setOption(LOCATION_PERMISSION_GIVEN, false); } //add other cases for permissions break; case STORAGE_PERMISSION_REQ: final String storageKey = Manifest.permission.WRITE_EXTERNAL_STORAGE; if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Log.d(DEBUG_TAG, "Permissions check: " + Arrays.toString(permissions)); if (permissionDoneRunnables.containsKey(storageKey)) { Runnable toRun = permissionDoneRunnables.get(storageKey); if (toRun != null) toRun.run(); permissionDoneRunnables.remove(storageKey); } } else { //permission denied showToastMessage(R.string.permission_storage_maps_msg, false); /*final int canGetPermission = askForPermissionIfNeeded(Manifest.permission.ACCESS_FINE_LOCATION, STORAGE_PERMISSION_REQ); switch (canGetPermission) { case PERMISSION_ASKING: break; case PERMISSION_NEG_CANNOT_ASK: permissionDoneRunnables.remove(storageKey); showToastMessage(R.string.closing_act_crash_msg, false); }*/ } } } @Override public void createFragmentForStop(String ID) { if (ID == null || ID.length() <= 0) { // we're still in UI thread, no need to mess with Progress showToastMessage(R.string.insert_bus_stop_number_error, true); toggleSpinner(false); } else if (framan.findFragmentById(R.id.resultFrame) instanceof ArrivalsFragment) { ArrivalsFragment fragment = (ArrivalsFragment) framan.findFragmentById(R.id.resultFrame); if (fragment.getStopID() != null && fragment.getStopID().equals(ID)){ // Run with previous fetchers //fragment.getCurrentFetchers().toArray() new AsyncDataDownload(fh,fragment.getCurrentFetchersAsArray()).execute(ID); } else{ new AsyncDataDownload(fh, arrivalsFetchers).execute(ID); } } else { new AsyncDataDownload(fh,arrivalsFetchers).execute(ID); Log.d("MainActiv", "Started search for arrivals of stop " + ID); } } /** * QR scan button clicked * * @param v View QRButton clicked */ public void onQRButtonClick(View v) { IntentIntegrator integrator = new IntentIntegrator(this); integrator.initiateScan(); } /** * Receive the Barcode Scanner Intent */ public void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent); Uri uri; try { uri = Uri.parse(scanResult != null ? scanResult.getContents() : null); // this apparently prevents NullPointerException. Somehow. } catch (NullPointerException e) { Toast.makeText(getApplicationContext(), R.string.no_qrcode, Toast.LENGTH_SHORT).show(); return; } String busStopID = getBusStopIDFromUri(uri); busStopSearchByIDEditText.setText(busStopID); createFragmentForStop(busStopID); } public void onHideHint(View v) { hideHints(); setOption(OPTION_SHOW_LEGEND, false); } public void onToggleKeyboardLayout(View v) { if (searchMode == SEARCH_BY_NAME) { setSearchModeBusStopID(); if (busStopSearchByIDEditText.requestFocus()) { showKeyboard(); } } else { // searchMode == SEARCH_BY_ID setSearchModeBusStopName(); if (busStopSearchByNameEditText.requestFocus()) { showKeyboard(); } } } private void createDefaultSnackbar() { if (snackbar == null) { snackbar = Snackbar.make(findViewById(R.id.searchButton), R.string.database_update_message, Snackbar.LENGTH_INDEFINITE); } snackbar.show(); } ///////////////////////////////// POSITION STUFF////////////////////////////////////////////// private void resolveStopRequest(String provider) { Log.d(DEBUG_TAG, "Provider " + provider + " got enabled"); if (locmgr != null && pendingNearbyStopsRequest && locmgr.getProvider(provider).meetsCriteria(cr)) { pendingNearbyStopsRequest = false; theHandler.post(new NearbyStopsRequester()); } } final LocationListener locListener = new LocationListener() { @Override public void onLocationChanged(Location location) { Log.d(DEBUG_TAG, "Location changed"); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { Log.d(DEBUG_TAG, "Location provider status: " + status); if (status == LocationProvider.AVAILABLE) { resolveStopRequest(provider); } } @Override public void onProviderEnabled(String provider) { resolveStopRequest(provider); } @Override public void onProviderDisabled(String provider) { } }; /** * Run location requests separately and asynchronously */ class NearbyStopsRequester implements Runnable { @Override public void run() { final boolean canRunPosition = Build.VERSION.SDK_INT < Build.VERSION_CODES.M || getOption(LOCATION_PERMISSION_GIVEN, false); final boolean noPermission = ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED; //if we don't have the permission, we have to ask for it, if we haven't // asked too many times before if (noPermission) { if (!canRunPosition) { pendingNearbyStopsRequest = true; assertLocationPermissions(); Log.w(DEBUG_TAG, "Cannot get position: Asking permission, noPositionFromSys: " + noPermission); return; } else { Toast.makeText(getApplicationContext(), "Asked for permission position too many times", Toast.LENGTH_LONG).show(); } } else setOption(LOCATION_PERMISSION_GIVEN, true); LocationManager locManager = (LocationManager) getSystemService(LOCATION_SERVICE); if (locManager == null) { Log.e(DEBUG_TAG, "location manager is nihil, cannot create NearbyStopsFragment"); return; } if (anyLocationProviderMatchesCriteria(locManager, cr, true) && fh.getLastSuccessfullySearchedBusStop() == null && !framan.isDestroyed()) { //Go ahead with the request Log.d("mainActivity", "Recreating stop fragment"); swipeRefreshLayout.setVisibility(View.VISIBLE); NearbyStopsFragment fragment = NearbyStopsFragment.newInstance(NearbyStopsFragment.TYPE_STOPS); Fragment oldFrag = framan.findFragmentById(R.id.resultFrame); FragmentTransaction ft = framan.beginTransaction(); if (oldFrag != null) ft.remove(oldFrag); ft.add(R.id.resultFrame, fragment, "nearbyStop_correct"); ft.commit(); framan.executePendingTransactions(); pendingNearbyStopsRequest = false; } else if (!anyLocationProviderMatchesCriteria(locManager, cr, true)) { //Wait for the providers Log.d(DEBUG_TAG, "Queuing position request"); pendingNearbyStopsRequest = true; locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10, 0.1f, locListener); } } } private boolean anyLocationProviderMatchesCriteria(LocationManager mng, Criteria cr, boolean enabled) { List providers = mng.getProviders(cr, enabled); Log.d(DEBUG_TAG, "Getting enabled location providers: "); for (String s : providers) { Log.d(DEBUG_TAG, "Provider " + s); } return providers.size() > 0; } ///////////////////////////////// OTHER STUFF ////////////////////////////////////////////////// /** * Get the last successfully searched bus stop or NULL * * @return */ @Override public Stop getLastSuccessfullySearchedBusStop() { return fh.getLastSuccessfullySearchedBusStop(); } /** * Get the last successfully searched bus stop ID or NULL * * @return */ @Override public String getLastSuccessfullySearchedBusStopID() { Stop stop = getLastSuccessfullySearchedBusStop(); return stop == null ? null : stop.ID; } /** * Update the star "Add to favorite" icon */ @Override public void updateStarIconFromLastBusStop() { // no favorites no party! addToFavorites = (ImageButton) findViewById(R.id.addToFavorites); if (addToFavorites == null) { Log.d("MainActivity", "Why the fuck the star is not here?!"); return; } // check if there is a last Stop String stopID = getLastSuccessfullySearchedBusStopID(); if (stopID == null) { addToFavorites.setVisibility(View.INVISIBLE); } else { // filled or outline? if (isStopInFavorites(stopID)) { addToFavorites.setImageResource(R.drawable.ic_star_filled); } else { addToFavorites.setImageResource(R.drawable.ic_star_outline); } addToFavorites.setVisibility(View.VISIBLE); } } /** * Check if the last Bus Stop is in the favorites * * @return */ public boolean isStopInFavorites(String busStopId) { boolean found = false; // no stop no party if (busStopId != null) { SQLiteDatabase userDB = new UserDB(getApplicationContext()).getReadableDatabase(); found = UserDB.isStopInFavorites(userDB, busStopId); } return found; } /** * Add the last Stop to favorites */ @Override public void toggleLastStopToFavorites() { Stop stop = getLastSuccessfullySearchedBusStop(); if (stop != null) { // toggle the status in background new AsyncStopFavoriteAction(getApplicationContext(), AsyncStopFavoriteAction.Action.TOGGLE) { /** * Callback fired when the Stop is saved in the favorites * @param result */ @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); // update the star icon updateStarIconFromLastBusStop(); } }.execute(stop); } else { // this case have no sense, but just immediately update the favorite icon updateStarIconFromLastBusStop(); } } @Override public void showFloatingActionButton(boolean yes) { if (yes) floatingActionButton.show(); else floatingActionButton.hide(); } @Override public void enableRefreshLayout(boolean yes) { swipeRefreshLayout.setEnabled(yes); } ////////////////////////////////////// GUI HELPERS ///////////////////////////////////////////// public void showKeyboard() { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); View view = searchMode == SEARCH_BY_ID ? busStopSearchByIDEditText : busStopSearchByNameEditText; imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT); } private void setSearchModeBusStopID() { searchMode = SEARCH_BY_ID; busStopSearchByNameEditText.setVisibility(View.GONE); busStopSearchByNameEditText.setText(""); busStopSearchByIDEditText.setVisibility(View.VISIBLE); floatingActionButton.setImageResource(R.drawable.alphabetical); } private void setSearchModeBusStopName() { searchMode = SEARCH_BY_NAME; busStopSearchByIDEditText.setVisibility(View.GONE); busStopSearchByIDEditText.setText(""); busStopSearchByNameEditText.setVisibility(View.VISIBLE); floatingActionButton.setImageResource(R.drawable.numeric); } /** * Having that cursor at the left of the edit text makes me cancer. * * @param busStopID bus stop ID */ private void setBusStopSearchByIDEditText(String busStopID) { busStopSearchByIDEditText.setText(busStopID); busStopSearchByIDEditText.setSelection(busStopID.length()); } private void showHints() { howDoesItWorkTextView.setVisibility(View.VISIBLE); hideHintButton.setVisibility(View.VISIBLE); actionHelpMenuItem.setVisible(false); } private void hideHints() { howDoesItWorkTextView.setVisibility(View.GONE); hideHintButton.setVisibility(View.GONE); actionHelpMenuItem.setVisible(true); } //TODO: toggle spinner from mainActivity @Override public void toggleSpinner(boolean enable) { if (enable) { //already set by the RefreshListener when needed //swipeRefreshLayout.setRefreshing(true); progressBar.setVisibility(View.VISIBLE); } else { swipeRefreshLayout.setRefreshing(false); progressBar.setVisibility(View.GONE); } } private void prepareGUIForBusLines() { swipeRefreshLayout.setEnabled(true); swipeRefreshLayout.setVisibility(View.VISIBLE); actionHelpMenuItem.setVisible(true); } private void prepareGUIForBusStops() { swipeRefreshLayout.setEnabled(false); swipeRefreshLayout.setVisibility(View.VISIBLE); actionHelpMenuItem.setVisible(false); } /** * This provides a temporary fix to make the transition * to a single asynctask go smoother * * @param fragmentType the type of fragment created */ @Override public void readyGUIfor(FragmentKind fragmentType) { hideKeyboard(); //if we are getting results, already, stop waiting for nearbyStops if (pendingNearbyStopsRequest && (fragmentType == FragmentKind.ARRIVALS || fragmentType == FragmentKind.STOPS)) { locmgr.removeUpdates(locListener); pendingNearbyStopsRequest = false; } if (fragmentType == null) Log.e("ActivityMain", "Problem with fragmentType"); else switch (fragmentType) { case ARRIVALS: prepareGUIForBusLines(); if (getOption(OPTION_SHOW_LEGEND, true)) { showHints(); } break; case STOPS: prepareGUIForBusStops(); break; default: Log.e("BusTO Activity", "Called readyGUI with unsupported type of Fragment"); return; } // Shows hints } /** * Open an URL in the default browser. * * @param url URL */ public void openIceweasel(String url) { Intent browserIntent1 = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(browserIntent1); } ///////////////////// INTENT HELPER //////////////////////////////////////////////////////////// /** * Try to extract the bus stop ID from a URi * * @param uri The URL * @return bus stop ID or null */ public static String getBusStopIDFromUri(Uri uri) { String busStopID; // everithing catches fire when passing null to a switch. String host = uri.getHost(); if (host == null) { Log.e("ActivityMain", "Not an URL: " + uri); return null; } switch (host) { case "m.gtt.to.it": // http://m.gtt.to.it/m/it/arrivi.jsp?n=1254 busStopID = uri.getQueryParameter("n"); if (busStopID == null) { Log.e("ActivityMain", "Expected ?n from: " + uri); } break; case "www.gtt.to.it": case "gtt.to.it": // http://www.gtt.to.it/cms/percorari/arrivi?palina=1254 busStopID = uri.getQueryParameter("palina"); if (busStopID == null) { Log.e("ActivityMain", "Expected ?palina from: " + uri); } break; default: Log.e("ActivityMain", "Unexpected intent URL: " + uri); busStopID = null; } return busStopID; } public void changeStarType(String stopID) { if (isStopInFavorites(stopID)) { changeStarFilled(); } else { changeStarOutline(); } } public void changeStarFilled() { addToFavorites.setImageResource(R.drawable.ic_star_filled); } public void changeStarOutline() { addToFavorites.setImageResource(R.drawable.ic_star_outline); } } \ No newline at end of file