Page Menu
Home
GitPull.it
Search
Configure Global Search
Log In
Files
F2444116
D92.1729696839.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
50 KB
Referenced Files
None
Subscribers
None
D92.1729696839.diff
View Options
diff --git a/build.gradle b/build.gradle
--- a/build.gradle
+++ b/build.gradle
@@ -30,7 +30,7 @@
dependencies {
classpath 'com.android.tools.build:gradle:4.2.2'
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21"
}
}
allprojects {
@@ -171,5 +171,8 @@
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
api "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
+ implementation 'androidx.legacy:legacy-support-v4:1.0.0'
+ implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1'
+ implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1'
}
diff --git a/res/layout/activity_experiments.xml b/res/layout/activity_experiments.xml
--- a/res/layout/activity_experiments.xml
+++ b/res/layout/activity_experiments.xml
@@ -7,34 +7,11 @@
android:layout_height="match_parent"
tools:context=".ActivityExperiments">
- <Button
- android:id="@+id/button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:onClick="runExp"
- android:text="Download GTFS data"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_bias="0.497"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintVertical_bias="0.292" />
+ <androidx.fragment.app.FragmentContainerView
+ android:id="@+id/fragment_container_view"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
- <Button
- android:text="Delete temporary GTFS file"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" android:id="@+id/deleteButton"
- app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/button"/>
-
- <Button
- android:id="@+id/deleteDbButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Clean GTFS data"
- app:layout_constraintBottom_toTopOf="@+id/deleteButton"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/button" />
+ app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/res/layout/activity_map.xml b/res/layout/activity_map.xml
--- a/res/layout/activity_map.xml
+++ b/res/layout/activity_map.xml
@@ -8,7 +8,7 @@
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:id="@+id/ic_center_map"
+ android:id="@+id/icon_center_map"
android:src="@drawable/ic_center_map"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
@@ -22,13 +22,13 @@
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:id="@+id/ic_follow_me"
+ android:id="@+id/icon_follow"
android:src="@drawable/ic_follow_me"
android:background="#00ffffff"
android:contentDescription="@string/bt_follow_me_description"
android:cropToPadding="true"
- android:layout_below="@+id/ic_center_map"
- android:layout_alignLeft="@+id/ic_center_map"
- android:layout_alignStart="@+id/ic_center_map"
+ android:layout_below="@+id/icon_center_map"
+ android:layout_alignLeft="@+id/icon_center_map"
+ android:layout_alignStart="@+id/icon_center_map"
android:layout_marginTop="10dp" />
</RelativeLayout>
\ No newline at end of file
diff --git a/res/layout/fragment_lines_detail.xml b/res/layout/fragment_lines_detail.xml
new file mode 100644
--- /dev/null
+++ b/res/layout/fragment_lines_detail.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".fragments.LinesDetailFragment">
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <TextView android:layout_width="match_parent" android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearance.AppCompat.Headline"
+ android:text="Line 10"
+ android:id="@+id/titleTextView"
+ android:textAlignment="center"
+
+ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"
+ android:layout_marginTop="8dp" android:gravity="center_horizontal|center_vertical"/>
+ <Spinner
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:id="@+id/patternsSpinner"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/titleTextView"
+ android:layout_marginTop="16dp" />
+ <TextView
+ android:text="Descr"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:id="@+id/routeDescrTextView"
+ app:layout_constraintStart_toEndOf="@id/patternsSpinner"
+ app:layout_constraintBottom_toBottomOf="@id/patternsSpinner"
+ app:layout_constraintEnd_toEndOf="parent"
+
+ android:layout_marginTop="8dp"
+ android:layout_marginLeft="16dp"
+ android:layout_marginStart="16dp"
+ android:textAppearance="@style/TextAppearance.AppCompat.Medium"
+
+ android:gravity="center_vertical"
+
+ android:layout_marginRight="16dp" android:layout_marginEnd="16dp"/>
+ <org.osmdroid.views.MapView android:id="@+id/lineMap"
+ android:layout_width="fill_parent"
+ android:layout_height="0dp"
+ android:layout_marginTop="20dp"
+ app:layout_constraintTop_toBottomOf="@id/patternsSpinner"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"/>
+ <ImageButton
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/icon_center_map"
+ android:src="@drawable/ic_center_map"
+
+ android:layout_marginTop="10dp"
+ android:layout_marginRight="10dp"
+ android:layout_marginEnd="10dp"
+ android:background="#00ffffff"
+ android:contentDescription="@string/bt_center_map_description"
+ app:layout_constraintTop_toTopOf="@id/lineMap"
+ app:layout_constraintEnd_toEndOf="@id/lineMap"
+ android:cropToPadding="true" />
+
+ <ImageButton
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/icon_follow"
+ android:src="@drawable/ic_follow_me"
+ android:background="#00ffffff"
+ android:contentDescription="@string/bt_follow_me_description"
+ android:cropToPadding="true"
+ app:layout_constraintEnd_toEndOf="@id/lineMap"
+ app:layout_constraintTop_toBottomOf="@id/icon_center_map"
+ android:layout_marginTop="10dp"
+ android:layout_marginRight="10dp"
+ android:layout_marginEnd="10dp"
+ />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -5,6 +5,10 @@
<string name="app_description">Stai utilizzando l\'ultimo ritrovato in materia di rispetto della tua privacy.</string>
<string name="search">Cerca</string>
<string name="qrcode">QR Code</string>
+ <string name="yes">Si</string>
+ <string name="no">No</string>
+ <string name="title_barcode_scanner_install">Installare Barcode Scanner?</string>
+ <string name="message_install_barcode_scanner">Questa azione richiede un\'altra app per scansionare i codici QR. Vuoi installare Barcode Scanner?</string>
<string name="insert_bus_stop_number">Numero fermata</string>
<string name="insert_bus_stop_name">Nome fermata</string>
<string name="insert_bus_stop_number_error">Inserisci il numero della fermata</string>
@@ -21,7 +25,7 @@
<string name="lines_fill">Linee: %1$s</string>
<string name="results">Scegli la fermata…</string>
<string name="no_passages">Nessun passaggio</string>
- <string name="no_qrcode">Nessun QR code</string>
+ <string name="no_qrcode">Nessun QR code trovato, prova ad usare un\'altra app</string>
<string name="action_favorites">Preferiti</string>
<string name="action_help">Aiuto</string>
<string name="action_about">Informazioni</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -8,6 +8,11 @@
</string>
<string name="search">Search</string>
<string name="qrcode">Scan QR Code</string>
+ <string name="yes">Yes</string>
+ <string name="no">No</string>
+ <string name="title_barcode_scanner_install">Install Barcode Scanner?</string>
+ <string name="message_install_barcode_scanner">This application requires an app to scan the QR codes. Would you like to install Barcode Scanner now?</string>
+
<string name="insert_bus_stop_number">Bus stop number</string>
<string name="insert_bus_stop_name">Bus stop name</string>
<string name="insert_bus_stop_number_error">Insert bus stop number</string>
@@ -27,7 +32,7 @@
<string name="lines_fill">Lines: %1$s</string>
<string name="line_fill">Line: %1$s</string>
<string name="no_passages">No timetable found</string>
- <string name="no_qrcode">No QR code</string>
+ <string name="no_qrcode">No QR code found, try using another app to scan</string>
<string name="internal_error">Unexpected internal error, cannot extract data from GTT/5T website</string>
<string name="action_help">Help</string>
<string name="action_about">About</string>
diff --git a/src/com/google/zxing/integration/android/IntentIntegrator.java b/src/com/google/zxing/integration/android/IntentIntegrator.java
--- a/src/com/google/zxing/integration/android/IntentIntegrator.java
+++ b/src/com/google/zxing/integration/android/IntentIntegrator.java
@@ -347,6 +347,7 @@
PackageManager pm = activity.getPackageManager();
List<ResolveInfo> availableApps = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (availableApps != null) {
+ Log.d("IntentIntegrator","Available app to scan QR Code: "+availableApps);
for (String targetApp : targetApplications) {
if (contains(availableApps, targetApp)) {
return targetApp;
diff --git a/src/it/reyboz/bustorino/ActivityExperiments.java b/src/it/reyboz/bustorino/ActivityExperiments.java
--- a/src/it/reyboz/bustorino/ActivityExperiments.java
+++ b/src/it/reyboz/bustorino/ActivityExperiments.java
@@ -17,139 +17,24 @@
*/
package it.reyboz.bustorino;
-import android.content.Context;
-import android.util.Log;
-import android.view.View;
-import android.widget.Button;
-import android.widget.Toast;
import android.os.Bundle;
-import it.reyboz.bustorino.backend.Fetcher;
-import it.reyboz.bustorino.backend.gtfs.GtfsDataParser;
-import it.reyboz.bustorino.backend.networkTools;
-import it.reyboz.bustorino.data.gtfs.GtfsDatabase;
-import it.reyboz.bustorino.data.gtfs.GtfsDBDao;
+import it.reyboz.bustorino.fragments.LinesDetailFragment;
import it.reyboz.bustorino.middleware.GeneralActivity;
-import java.io.*;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.*;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-
public class ActivityExperiments extends GeneralActivity {
- ExecutorService executorService;
final static String DEBUG_TAG = "ExperimentsGTFS";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_experiments);
- Button deleteButton = findViewById(R.id.deleteButton);
- if(deleteButton!=null)
- deleteButton.setOnClickListener(view -> {
- File saveFile = new File(getFilesDir(), "gtfs_data.zip");
- if(!saveFile.isDirectory() && saveFile.exists()){
- //delete the file
- if(saveFile.delete())
- Toast.makeText(this, "Gtfs zip deleted", Toast.LENGTH_SHORT).show();
- else
- Toast.makeText(this, "Cannot delete gtfs zip", Toast.LENGTH_SHORT).show();
- } else
- Toast.makeText(this, "Gtfs data zip not present", Toast.LENGTH_SHORT).show();
- });
-
- Button cleanDBButton = findViewById(R.id.deleteDbButton);
- if(cleanDBButton!=null)
- cleanDBButton.setOnClickListener(this::deleteDatabase);
-
- executorService = Executors.newFixedThreadPool(2);
- }
-
- public void runExp(View v){
-
- final Context appContext = v.getContext().getApplicationContext();
-
- Runnable run = new Runnable() {
- @Override
- public void run() {
-
- AtomicReference<Fetcher.Result> res = new AtomicReference<>();
- //List<String> files = GtfsDataParser.readFilesList(res);
- Date updateDate = GtfsDataParser.getLastGTFSUpdateDate(res);
- Log.w(
- "ExperimentGTFS", "Last update date is " + updateDate//utils.joinList(files, "\n")
- );
- //Toast.makeText(v.getContext(), "Gtfs data already downloaded", Toast.LENGTH_SHORT).show();
- GtfsDBDao dao = GtfsDatabase.Companion.getGtfsDatabase(appContext).gtfsDao();
- Log.d(DEBUG_TAG, String.valueOf(dao));
- dao.deleteAllStopTimes();
-
-
- File saveFile = new File(getFilesDir(), "gtfs_data.zip");
- if (!saveFile.isDirectory() && saveFile.exists()) {
- Log.w(DEBUG_TAG, "Zip exists: " + saveFile);
-
-
- try (ZipFile zipFile = new ZipFile(saveFile)) {
- //ZipInputStream stream = new ZipInputStream(fileStream);
- // now iterate through each item in the stream. The get next
- // entry call will return a ZipEntry for each file in the
- // stream
- /*
- Enumeration<? extends ZipEntry> entries = zipFile.entries();
- ZipEntry entry;
- String line;
- //final BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
-
- HashSet<ZipEntry> readLater = new HashSet<>();
- while(entries.hasMoreElements()){
- entry = entries.nextElement();
- //String tableName = entry.getName().split("\\.")[0].trim();
- if(entry.getName().trim().equals("stop_times.txt")) {
- readLater.add(entry);
- continue;
- }
- GtfsDataParser.readGtfsZipEntry(entry, zipFile, v.getContext().getApplicationContext());
- }
- for(ZipEntry laterEntry: readLater){
- GtfsDataParser.readGtfsZipEntry(laterEntry, zipFile, v.getContext().getApplicationContext());
- }
-
- */
- } catch (IOException e) {
- e.printStackTrace();
- }
- //saveFile.delete();
- } else
- try {
- //Toast.makeText(v.getContext(), "Downloading gtfs data", Toast.LENGTH_SHORT).show();
-
- networkTools.saveFileInCache(saveFile, new URL(GtfsDataParser.GTFS_ADDRESS));
- Log.w(DEBUG_TAG, "File saved");
- } catch (MalformedURLException e) {
- e.printStackTrace();
- }
-
- }
- };
-
- Toast.makeText(this, "Test disabled", Toast.LENGTH_SHORT).show();
- //Looper looper = new Looper(true);
- //Handler handler = new Handler();
- //handler.post(run);
- //executorService.execute(run);
-
-
- }
-
- public void deleteDatabase(View v){
- //final Context con = getApplicationContext().getApplicationContext();
- Toast.makeText(this, "Deleting GTFS DB contents isn't allowed anymore", Toast.LENGTH_SHORT).show();
-
+ if (savedInstanceState==null) {
+ getSupportFragmentManager().beginTransaction()
+ .setReorderingAllowed(true)
+ .add(R.id.fragment_container_view, LinesDetailFragment.class,
+ LinesDetailFragment.Companion.makeArgs("gtt:56U"))
+ .commit();
+ }
}
}
\ No newline at end of file
diff --git a/src/it/reyboz/bustorino/ActivityPrincipal.java b/src/it/reyboz/bustorino/ActivityPrincipal.java
--- a/src/it/reyboz/bustorino/ActivityPrincipal.java
+++ b/src/it/reyboz/bustorino/ActivityPrincipal.java
@@ -70,6 +70,7 @@
private Snackbar snackbar;
private boolean showingMainFragmentFromOther = false;
+ private boolean onCreateComplete = false;
@Override
@@ -77,7 +78,7 @@
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_principal);
final SharedPreferences theShPr = getMainSharedPreferences();
- boolean showingArrivalsForStop = false;
+ boolean showingArrivalsFromIntent = false;
//database check
GtfsDatabase gtfsDB = GtfsDatabase.Companion.getGtfsDatabase(this);
@@ -153,7 +154,9 @@
String busStopID = null;
Uri data = getIntent().getData();
if (data != null) {
+
busStopID = getBusStopIDFromUri(data);
+ Log.d(DEBUG_TAG, "Opening Intent: busStopID: "+busStopID);
tryedFromIntent = true;
}
@@ -188,9 +191,9 @@
} else {
// If you are here an intent has worked successfully
//setBusStopSearchByIDEditText(busStopID);
-
- requestArrivalsForStopID(busStopID);
- showingArrivalsForStop = true;
+ //Log.d(DEBUG_TAG, "Requesting arrivals for stop "+busStopID+" from intent");
+ requestArrivalsForStopID(busStopID); //this shows the fragment, too
+ showingArrivalsFromIntent = true;
}
//Try (hopefully) database update
if(!dataUpdateRequested)
@@ -233,18 +236,19 @@
//if (vl.length() == 0 || vl.equals("arrivals")) {
// showMainFragment();
Log.d(DEBUG_TAG, "The default screen to open is: "+vl);
- if(showingArrivalsForStop){
- showMainFragment(false);
- } else if (vl.equals("map")){
+ if (showingArrivalsFromIntent){
+ //do nothing but exclude a case
+ }
+ else if (vl.equals("map")){
requestMapFragment(false);
} else if(vl.equals("favorites")){
checkAndShowFavoritesFragment(getSupportFragmentManager(), false);
} else if(vl.equals("lines")){
showLinesFragment(getSupportFragmentManager(), false, null);
- } else{
+ } else {
showMainFragment(false);
}
-
+ onCreateComplete = true;
}
private ActionBarDrawerToggle setupDrawerToggle(Toolbar toolbar) {
@@ -435,6 +439,25 @@
if (addToBackStack) ft.addToBackStack(null);
ft.commit();
}
+ /**
+ * Show the fragment by adding it to the backstack
+ * @param fraMan the fragmentManager
+ * @param arguments args for the fragment
+ */
+ private static void createShowMainFragment(FragmentManager fraMan, Bundle arguments, boolean addToBackStack){
+ FragmentTransaction ft = fraMan.beginTransaction()
+ .replace(R.id.mainActContentFrame, MainScreenFragment.class, arguments, MainScreenFragment.FRAGMENT_TAG)
+ .setReorderingAllowed(false)
+ /*.setCustomAnimations(
+ R.anim.slide_in, // enter
+ R.anim.fade_out, // exit
+ R.anim.fade_in, // popEnter
+ R.anim.slide_out // popExit
+ )*/
+ .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
+ if (addToBackStack) ft.addToBackStack(null);
+ ft.commit();
+ }
private void requestMapFragment(final boolean allowReturn){
final String permission = Manifest.permission.WRITE_EXTERNAL_STORAGE;
@@ -592,15 +615,19 @@
// set the flag
probableFragment.setSuppressArrivalsReload(true);
showMainFragment(fraMan, probableFragment, true);
+ probableFragment.requestArrivalsForStopID(ID);
} else {
//createAndShowMainFragment
// we have no fragment
- probableFragment = MainScreenFragment.newInstance();
- showMainFragment(fraMan, probableFragment,true);
+ final Bundle args = new Bundle();
+ args.putString(MainScreenFragment.PENDING_STOP_SEARCH, ID);
+ //if onCreate is complete, then we are not asking for the first showing fragment
+ boolean addtobackstack = onCreateComplete;
+ createShowMainFragment(fraMan, args ,addtobackstack);
//probableFragment = createAndShowMainFragment();
}
}
- probableFragment.requestArrivalsForStopID(ID);
+
mNavView.setCheckedItem(R.id.nav_arrivals);
}
diff --git a/src/it/reyboz/bustorino/backend/gtfs/PolylineParser.java b/src/it/reyboz/bustorino/backend/gtfs/PolylineParser.java
--- a/src/it/reyboz/bustorino/backend/gtfs/PolylineParser.java
+++ b/src/it/reyboz/bustorino/backend/gtfs/PolylineParser.java
@@ -4,7 +4,7 @@
import java.util.ArrayList;
-public final class PolylineParser {
+public abstract class PolylineParser {
/**
* Decode a Google polyline
* Thanks to https://stackoverflow.com/questions/9341020/how-to-decode-googles-polyline-algorithm
diff --git a/src/it/reyboz/bustorino/fragments/LinesDetailFragment.kt b/src/it/reyboz/bustorino/fragments/LinesDetailFragment.kt
new file mode 100644
--- /dev/null
+++ b/src/it/reyboz/bustorino/fragments/LinesDetailFragment.kt
@@ -0,0 +1,154 @@
+package it.reyboz.bustorino.fragments
+
+import android.os.Bundle
+import android.os.Parcelable
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.AdapterView
+import android.widget.ArrayAdapter
+import android.widget.Spinner
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import it.reyboz.bustorino.R
+import it.reyboz.bustorino.backend.gtfs.PolylineParser
+import it.reyboz.bustorino.data.gtfs.MatoPatternWithStops
+import it.reyboz.bustorino.data.gtfs.PatternStop
+import org.osmdroid.tileprovider.tilesource.TileSourceFactory
+import org.osmdroid.views.MapView
+import org.osmdroid.views.overlay.Polyline
+
+class LinesDetailFragment() : Fragment() {
+
+ private lateinit var lineID: String
+
+
+ private lateinit var patternsSpinner: Spinner
+ private var patternsAdapter: ArrayAdapter<String>? = null
+
+ private var patternsSpinnerState: Parcelable? = null
+
+ private lateinit var currentPatterns: List<MatoPatternWithStops>
+ private lateinit var gtfsStopsForCurrentPattern: List<PatternStop>
+
+ private lateinit var map: MapView
+ private lateinit var polyLine: Polyline
+
+ private lateinit var viewingPattern: MatoPatternWithStops
+
+ private lateinit var viewModel: LinesViewModel
+
+
+
+ companion object {
+ private const val LINEID_KEY="lineID"
+ fun newInstance() = LinesDetailFragment()
+ const val DEBUG_TAG="LinesDetailFragment"
+
+ fun makeArgs(lineID: String): Bundle{
+ val b = Bundle()
+ b.putString(LINEID_KEY, lineID)
+ return b
+ }
+ }
+
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ val rootView = inflater.inflate(R.layout.fragment_lines_detail, container, false)
+ lineID = requireArguments().getString(LINEID_KEY, "")
+
+ patternsSpinner = rootView.findViewById(R.id.patternsSpinner)
+ patternsAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_dropdown_item, ArrayList<String>())
+ patternsSpinner.adapter = patternsAdapter
+
+ map = rootView.findViewById(R.id.lineMap)
+ map.setTileSource(TileSourceFactory.MAPNIK)
+ //map.setTilesScaledToDpi(true);
+ //map.setTilesScaledToDpi(true);
+ map.setFlingEnabled(true)
+
+ // add ability to zoom with 2 fingers
+ map.setMultiTouchControls(true)
+ map.minZoomLevel = 13.0
+
+
+
+ viewModel.patternsWithStopsByRouteLiveData.observe(viewLifecycleOwner){
+ patterns -> savePatternsToShow(patterns)
+ }
+
+
+ /*
+ We have the pattern and the stops here, time to display them
+ */
+ viewModel.stopsForPatternLiveData.observe(viewLifecycleOwner) { stops ->
+ Log.d(DEBUG_TAG, "Got the stops: ${stops.map { s->s.gtfsID }}}")
+
+ val pattern = viewingPattern.pattern
+
+ val pointsList = PolylineParser.decodePolyline(pattern.patternGeometryPoly, pattern.patternGeometryLength)
+ val polyLine=Polyline(map)
+ polyLine.setPoints(pointsList)
+
+ map.overlayManager.add(polyLine)
+ map.controller.animateTo(pointsList[0])
+ }
+
+ viewModel.setRouteIDQuery(lineID)
+
+ Log.d(DEBUG_TAG,"Data ${viewModel.stopsForPatternLiveData.value}")
+
+ //listeners
+ patternsSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
+ override fun onItemSelected(p0: AdapterView<*>?, p1: View?, position: Int, p3: Long) {
+ val patternWithStops = currentPatterns.get(position)
+ setPatternAndReqStops(patternWithStops)
+ }
+
+ override fun onNothingSelected(p0: AdapterView<*>?) {
+ }
+ }
+
+
+ return rootView
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ viewModel = ViewModelProvider(this).get(LinesViewModel::class.java)
+ }
+
+ private fun savePatternsToShow(patterns: List<MatoPatternWithStops>){
+ currentPatterns = patterns.sortedBy { p-> p.pattern.code }
+
+ patternsAdapter?.let {
+ it.clear()
+ it.addAll(currentPatterns.map { p->"${p.pattern.directionId} - ${p.pattern.headsign}" })
+ it.notifyDataSetChanged()
+ }
+
+ val pos = patternsSpinner.selectedItemPosition
+ //might be possible that the selectedItem is different (larger than list size)
+ if(pos!= AdapterView.INVALID_POSITION && pos >= 0 && (pos < currentPatterns.size)){
+ val p = currentPatterns[pos]
+ Log.d(LinesFragment.DEBUG_TAG, "Setting patterns with pos $pos and p gtfsID ${p.pattern.code}")
+ setPatternAndReqStops(currentPatterns[pos])
+ }
+ Log.d(DEBUG_TAG, "Patterns changed")
+
+ }
+
+ private fun setPatternAndReqStops(patternWithStops: MatoPatternWithStops){
+ Log.d(DEBUG_TAG, "Requesting stops for pattern ${patternWithStops.pattern.code}")
+ gtfsStopsForCurrentPattern = patternWithStops.stopsIndices.sortedBy { i-> i.order }
+ viewingPattern = patternWithStops
+
+ viewModel.requestStopsForPatternWithStops(patternWithStops)
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/it/reyboz/bustorino/fragments/LinesFragment.kt b/src/it/reyboz/bustorino/fragments/LinesFragment.kt
--- a/src/it/reyboz/bustorino/fragments/LinesFragment.kt
+++ b/src/it/reyboz/bustorino/fragments/LinesFragment.kt
@@ -167,6 +167,7 @@
if (linesSpinner.onItemSelectedListener != null){
Log.d(DEBUG_TAG, "linesSpinner listener != null")
}
+ //listener
linesSpinner.onItemSelectedListener = object: OnItemSelectedListener{
override fun onItemSelected(p0: AdapterView<*>?, p1: View?, pos: Int, p3: Long) {
val selRoute = currentRoutes.get(pos)
diff --git a/src/it/reyboz/bustorino/fragments/LinesViewModel.kt b/src/it/reyboz/bustorino/fragments/LinesViewModel.kt
--- a/src/it/reyboz/bustorino/fragments/LinesViewModel.kt
+++ b/src/it/reyboz/bustorino/fragments/LinesViewModel.kt
@@ -23,7 +23,7 @@
val stopsForPatternLiveData = MutableLiveData<List<Stop>>()
- val executor = Executors.newFixedThreadPool(2)
+ private val executor = Executors.newFixedThreadPool(2)
init {
val gtfsDao = GtfsDatabase.getGtfsDatabase(application).gtfsDao()
@@ -50,6 +50,9 @@
}
var shouldShowMessage = true
+ /**
+ * Find the
+ */
private fun requestStopsForGTFSIDs(gtfsIDs: List<String>){
if (gtfsIDs.equals(lastShownPatternStops)){
//nothing to do
diff --git a/src/it/reyboz/bustorino/fragments/MainScreenFragment.java b/src/it/reyboz/bustorino/fragments/MainScreenFragment.java
--- a/src/it/reyboz/bustorino/fragments/MainScreenFragment.java
+++ b/src/it/reyboz/bustorino/fragments/MainScreenFragment.java
@@ -3,9 +3,11 @@
import android.Manifest;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.Location;
+import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -38,7 +40,6 @@
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
-import com.google.zxing.integration.android.IntentIntegrator;
import java.util.Map;
@@ -47,9 +48,13 @@
import it.reyboz.bustorino.middleware.AppLocationManager;
import it.reyboz.bustorino.middleware.AsyncArrivalsSearcher;
import it.reyboz.bustorino.middleware.AsyncStopsSearcher;
+import it.reyboz.bustorino.middleware.BarcodeScanContract;
+import it.reyboz.bustorino.middleware.BarcodeScanOptions;
+import it.reyboz.bustorino.middleware.BarcodeScanUtils;
import it.reyboz.bustorino.util.LocationCriteria;
import it.reyboz.bustorino.util.Permissions;
+import static it.reyboz.bustorino.backend.utils.getBusStopIDFromUri;
import static it.reyboz.bustorino.util.Permissions.LOCATION_PERMISSIONS;
import static it.reyboz.bustorino.util.Permissions.LOCATION_PERMISSION_GIVEN;
@@ -67,6 +72,8 @@
private static final String DEBUG_TAG = "BusTO - MainFragment";
+ public static final String PENDING_STOP_SEARCH="PendingStopSearch";
+
public final static String FRAGMENT_TAG = "MainScreenFragment";
/// UI ELEMENTS //
@@ -81,8 +88,9 @@
private MenuItem actionHelpMenuItem;
private FloatingActionButton floatingActionButton;
- private boolean setupOnAttached = true;
+ private boolean setupOnResume = true;
private boolean suppressArrivalsReload = false;
+ private boolean instanceStateSaved = false;
//private Snackbar snackbar;
/*
* Search mode
@@ -114,6 +122,34 @@
new AsyncArrivalsSearcher(fragmentHelper, arrivalsFetchers, getContext()).execute();
}
};
+ //
+ private final ActivityResultLauncher<BarcodeScanOptions> barcodeLauncher = registerForActivityResult(new BarcodeScanContract(),
+ result -> {
+ if(result!=null && result.getContents()!=null) {
+ //Toast.makeText(MyActivity.this, "Cancelled", Toast.LENGTH_LONG).show();
+ Uri uri;
+ try {
+ uri = Uri.parse(result.getContents()); // this apparently prevents NullPointerException. Somehow.
+ } catch (NullPointerException e) {
+ if (getContext()!=null)
+ Toast.makeText(getContext().getApplicationContext(),
+ R.string.no_qrcode, Toast.LENGTH_SHORT).show();
+ return;
+ }
+ String busStopID = getBusStopIDFromUri(uri);
+ busStopSearchByIDEditText.setText(busStopID);
+ requestArrivalsForStopID(busStopID);
+
+ } else {
+ //Toast.makeText(MyActivity.this, "Scanned: " + result.getContents(), Toast.LENGTH_LONG).show();
+ if (getContext()!=null)
+ Toast.makeText(getContext().getApplicationContext(),
+ R.string.no_qrcode, Toast.LENGTH_SHORT).show();
+
+
+
+ }
+ });
/// LOCATION STUFF ///
boolean pendingNearbyStopsRequest = false;
@@ -213,6 +249,9 @@
super.onCreate(savedInstanceState);
if (getArguments() != null) {
//do nothing
+ Log.d(DEBUG_TAG, "ARGS ARE NOT NULL: "+getArguments());
+ if (getArguments().getString(PENDING_STOP_SEARCH)!=null)
+ pendingStopID = getArguments().getString(PENDING_STOP_SEARCH);
}
}
@@ -291,18 +330,20 @@
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Log.d(DEBUG_TAG, "onViewCreated, SwipeRefreshLayout visible: "+(swipeRefreshLayout.getVisibility()==View.VISIBLE));
- Log.d(DEBUG_TAG, "Setup on attached: "+setupOnAttached);
+ Log.d(DEBUG_TAG, "Setup on attached: "+ setupOnResume);
//Restore instance state
if (savedInstanceState!=null){
Fragment fragment = getChildFragmentManager().getFragment(savedInstanceState, SAVED_FRAGMENT);
if (fragment!=null){
getChildFragmentManager().beginTransaction().add(R.id.resultFrame, fragment).commit();
- setupOnAttached = false;
+ setupOnResume = false;
}
}
if (getChildFragmentManager().findFragmentById(R.id.resultFrame)!= null){
swipeRefreshLayout.setVisibility(View.VISIBLE);
}
+ instanceStateSaved = false;
+
}
@Override
@@ -312,6 +353,8 @@
if (fragment!=null)
getChildFragmentManager().putFragment(outState, SAVED_FRAGMENT, fragment);
fragmentHelper.setBlockAllActivities(true);
+
+ instanceStateSaved = true;
}
public void setSuppressArrivalsReload(boolean value){
@@ -346,7 +389,7 @@
public void onAttach(@NonNull Context context) {
super.onAttach(context);
- Log.d(DEBUG_TAG, "OnAttach called, setupOnAttach: "+setupOnAttached);
+ Log.d(DEBUG_TAG, "OnAttach called, setupOnAttach: "+ setupOnResume);
mainHandler = new Handler();
if (context instanceof CommonFragmentListener) {
mListener = (CommonFragmentListener) context;
@@ -354,17 +397,6 @@
throw new RuntimeException(context
+ " must implement CommonFragmentListener");
}
- if (setupOnAttached) {
- if (pendingStopID==null)
- //We want the nearby bus stops!
- mainHandler.post(new NearbyStopsRequester(context, cr));
- else{
- ///TODO: if there is a stop displayed, we need to hold the update
- }
-
- setupOnAttached = false;
- }
-
}
@Override
@@ -414,13 +446,26 @@
}
suppressArrivalsReload = false;
}
+ if (setupOnResume) {
+ if (pendingStopID==null)
+ //We want the nearby bus stops!
+ mainHandler.post(new NearbyStopsRequester(getContext(), cr));
+ else{
+ ///TODO: if there is a stop displayed, we need to hold the update
+ }
+
+ setupOnResume = false;
+ }
if(pendingStopID!=null){
+
+ Log.d(DEBUG_TAG, "Re-requesting arrivals for pending stop "+pendingStopID);
requestArrivalsForStopID(pendingStopID);
pendingStopID = null;
}
mListener.readyGUIfor(FragmentKind.MAIN_SCREEN_FRAGMENT);
fragmentHelper.setBlockAllActivities(false);
+
}
@Override
@@ -442,8 +487,14 @@
* @param v View QRButton clicked
*/
public void onQRButtonClick(View v) {
- IntentIntegrator integrator = new IntentIntegrator(getActivity());
- integrator.initiateScan();
+
+ BarcodeScanOptions scanOptions = new BarcodeScanOptions();
+ Intent intent = scanOptions.createScanIntent();
+ if(!BarcodeScanUtils.checkTargetPackageExists(getContext(), intent)){
+ BarcodeScanUtils.showDownloadDialog(null, this);
+ }else {
+ barcodeLauncher.launch(scanOptions);
+ }
}
public void onHideHint(View v) {
@@ -589,11 +640,11 @@
fragment = NearbyStopsFragment.newInstance(NearbyStopsFragment.TYPE_STOPS);
FragmentTransaction ft = fragMan.beginTransaction();
- //if (oldFrag != null)
- // ft.remove(oldFrag);
ft.replace(R.id.resultFrame, fragment, NearbyStopsFragment.FRAGMENT_TAG);
+ if (getActivity()!=null && !getActivity().isFinishing() &&!instanceStateSaved)
ft.commit();
+ else Log.e(DEBUG_TAG, "Not showing nearby fragment because we saved instanceState");
}
}
@@ -655,7 +706,7 @@
if (!isResumed()){
//defer request
pendingStopID = ID;
- Log.d(DEBUG_TAG, "Deferring update for stop "+ID);
+ Log.d(DEBUG_TAG, "Deferring update for stop "+ID+ " saved: "+pendingStopID);
return;
}
final boolean delayedRequest = !(pendingStopID==null);
diff --git a/src/it/reyboz/bustorino/fragments/MapFragment.java b/src/it/reyboz/bustorino/fragments/MapFragment.java
--- a/src/it/reyboz/bustorino/fragments/MapFragment.java
+++ b/src/it/reyboz/bustorino/fragments/MapFragment.java
@@ -33,7 +33,6 @@
import android.widget.ImageButton;
import android.widget.Toast;
-import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
@@ -190,8 +189,8 @@
// add ability to zoom with 2 fingers
map.setMultiTouchControls(true);
- btCenterMap = root.findViewById(R.id.ic_center_map);
- btFollowMe = root.findViewById(R.id.ic_follow_me);
+ btCenterMap = root.findViewById(R.id.icon_center_map);
+ btFollowMe = root.findViewById(R.id.icon_follow);
//setup FolderOverlay
stopsFolderOverlay = new FolderOverlay();
diff --git a/src/it/reyboz/bustorino/middleware/BarcodeScanContract.java b/src/it/reyboz/bustorino/middleware/BarcodeScanContract.java
new file mode 100644
--- /dev/null
+++ b/src/it/reyboz/bustorino/middleware/BarcodeScanContract.java
@@ -0,0 +1,33 @@
+/*
+ * Based on ZXing Android Embedded, Copyright 2021 ZXing Android Embedded authors.
+
+ */
+
+package it.reyboz.bustorino.middleware;
+
+import android.content.Context;
+import android.content.Intent;
+
+import androidx.activity.result.contract.ActivityResultContract;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.google.zxing.integration.android.IntentIntegrator;
+import com.google.zxing.integration.android.IntentResult;
+
+public class BarcodeScanContract extends ActivityResultContract<BarcodeScanOptions, IntentResult> {
+
+ @NonNull
+ @Override
+ public Intent createIntent(@NonNull Context context, BarcodeScanOptions input) {
+ return input.createScanIntent();
+ }
+
+
+ @Override
+ public IntentResult parseResult(int resultCode, @Nullable Intent intent) {
+ return IntentIntegrator.parseActivityResult(IntentIntegrator.REQUEST_CODE, resultCode, intent);
+ }
+
+
+}
diff --git a/src/it/reyboz/bustorino/middleware/BarcodeScanOptions.java b/src/it/reyboz/bustorino/middleware/BarcodeScanOptions.java
new file mode 100644
--- /dev/null
+++ b/src/it/reyboz/bustorino/middleware/BarcodeScanOptions.java
@@ -0,0 +1,172 @@
+
+/*
+ * Based on ZXing Android Embedded, Copyright 2021 ZXing Android Embedded authors.
+
+ */
+package it.reyboz.bustorino.middleware;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class BarcodeScanOptions {
+
+ public static final String BS_PACKAGE = "com.google.zxing.client.android";
+
+ // supported barcode formats
+
+ // Product Codes
+ public static final String UPC_A = "UPC_A";
+ public static final String UPC_E = "UPC_E";
+ public static final String EAN_8 = "EAN_8";
+ public static final String EAN_13 = "EAN_13";
+ public static final String RSS_14 = "RSS_14";
+
+ // Other 1D
+ public static final String CODE_39 = "CODE_39";
+ public static final String CODE_93 = "CODE_93";
+ public static final String CODE_128 = "CODE_128";
+ public static final String ITF = "ITF";
+
+ public static final String RSS_EXPANDED = "RSS_EXPANDED";
+
+ // 2D
+ public static final String QR_CODE = "QR_CODE";
+ public static final String DATA_MATRIX = "DATA_MATRIX";
+ public static final String PDF_417 = "PDF_417";
+
+
+ public static final Collection<String> PRODUCT_CODE_TYPES = list(UPC_A, UPC_E, EAN_8, EAN_13, RSS_14);
+ public static final Collection<String> ONE_D_CODE_TYPES =
+ list(UPC_A, UPC_E, EAN_8, EAN_13, RSS_14, CODE_39, CODE_93, CODE_128,
+ ITF, RSS_14, RSS_EXPANDED);
+
+ public static final Collection<String> ALL_CODE_TYPES = null;
+
+ private final Map<String, Object> moreExtras = new HashMap<>(3);
+
+ private Collection<String> desiredBarcodeFormats;
+
+
+ private int cameraId = 0;
+
+ public BarcodeScanOptions() {
+
+ }
+
+ public Map<String, ?> getMoreExtras() {
+ return moreExtras;
+ }
+
+ public final BarcodeScanOptions addExtra(String key, Object value) {
+ moreExtras.put(key, value);
+ return this;
+ }
+
+ public final BarcodeScanOptions setCameraID(int cameraID){
+ this.cameraId = cameraID;
+ return this;
+ }
+
+ /**
+ * Set the desired barcode formats to scan.
+ *
+ * @param desiredBarcodeFormats names of {@code BarcodeFormat}s to scan for
+ * @return this
+ */
+ public BarcodeScanOptions setDesiredBarcodeFormats(Collection<String> desiredBarcodeFormats) {
+ this.desiredBarcodeFormats = desiredBarcodeFormats;
+ return this;
+ }
+
+ /**
+ * Set the desired barcode formats to scan.
+ *
+ * @param desiredBarcodeFormats names of {@code BarcodeFormat}s to scan for
+ * @return this
+ */
+ public BarcodeScanOptions setDesiredBarcodeFormats(String... desiredBarcodeFormats) {
+ this.desiredBarcodeFormats = Arrays.asList(desiredBarcodeFormats);
+ return this;
+ }
+
+
+ /**
+ * Create an scan intent with the specified options.
+ *
+ * @return the intent
+ */
+ public Intent createScanIntent() {
+ Intent intentScan = new Intent(BS_PACKAGE + ".SCAN");
+ intentScan.addCategory(Intent.CATEGORY_DEFAULT);
+
+ // check which types of codes to scan for
+ if (desiredBarcodeFormats != null) {
+ // set the desired barcode types
+ StringBuilder joinedByComma = new StringBuilder();
+ for (String format : desiredBarcodeFormats) {
+ if (joinedByComma.length() > 0) {
+ joinedByComma.append(',');
+ }
+ joinedByComma.append(format);
+ }
+ intentScan.putExtra("SCAN_FORMATS", joinedByComma.toString());
+ }
+
+ // check requested camera ID
+ if (cameraId >= 0) {
+ intentScan.putExtra("SCAN_CAMERA_ID", cameraId);
+ }
+
+ intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ intentScan.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+ attachMoreExtras(intentScan);
+ return intentScan;
+ }
+
+ private static List<String> list(String... values) {
+ return Collections.unmodifiableList(Arrays.asList(values));
+ }
+
+ private void attachMoreExtras(Intent intent) {
+ for (Map.Entry<String, Object> entry : moreExtras.entrySet()) {
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ // Kind of hacky
+ if (value instanceof Integer) {
+ intent.putExtra(key, (Integer) value);
+ } else if (value instanceof Long) {
+ intent.putExtra(key, (Long) value);
+ } else if (value instanceof Boolean) {
+ intent.putExtra(key, (Boolean) value);
+ } else if (value instanceof Double) {
+ intent.putExtra(key, (Double) value);
+ } else if (value instanceof Float) {
+ intent.putExtra(key, (Float) value);
+ } else if (value instanceof Bundle) {
+ intent.putExtra(key, (Bundle) value);
+ } else if (value instanceof int[]) {
+ intent.putExtra(key, (int[]) value);
+ } else if (value instanceof long[]) {
+ intent.putExtra(key, (long[]) value);
+ } else if (value instanceof boolean[]) {
+ intent.putExtra(key, (boolean[]) value);
+ } else if (value instanceof double[]) {
+ intent.putExtra(key, (double[]) value);
+ } else if (value instanceof float[]) {
+ intent.putExtra(key, (float[]) value);
+ } else if (value instanceof String[]) {
+ intent.putExtra(key, (String[]) value);
+ } else {
+ intent.putExtra(key, value.toString());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/it/reyboz/bustorino/middleware/BarcodeScanUtils.java b/src/it/reyboz/bustorino/middleware/BarcodeScanUtils.java
new file mode 100644
--- /dev/null
+++ b/src/it/reyboz/bustorino/middleware/BarcodeScanUtils.java
@@ -0,0 +1,62 @@
+package it.reyboz.bustorino.middleware;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import java.util.List;
+
+import it.reyboz.bustorino.R;
+
+public class BarcodeScanUtils {
+
+
+ public static boolean checkTargetPackageExists(Context context,Intent intent) {
+ PackageManager pm = context.getPackageManager();
+ List<ResolveInfo> availableApps = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ if (availableApps != null) {
+ return !availableApps.isEmpty();
+ }
+ return false;
+ }
+
+ public static AlertDialog showDownloadDialog(@Nullable Activity activity,@Nullable final Fragment fragment) {
+ if (activity == null){
+ if (fragment==null) throw new IllegalArgumentException("Cannot put both activity and fragment null");
+ activity = fragment.getActivity();
+ }
+ AlertDialog.Builder downloadDialog = new AlertDialog.Builder(activity);
+ downloadDialog.setTitle(R.string.title_barcode_scanner_install);
+ downloadDialog.setMessage(R.string.message_install_barcode_scanner);
+ final Activity finalActivity = activity;
+ downloadDialog.setPositiveButton(R.string.yes, (dialogInterface, i) -> {
+ final String packageName = BarcodeScanOptions.BS_PACKAGE;
+ Uri uri = Uri.parse("market://details?id=" + packageName);
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ try {
+ if (fragment == null) {
+ finalActivity.startActivity(intent);
+ } else {
+ fragment.startActivity(intent);
+ }
+ } catch (ActivityNotFoundException anfe) {
+ // Hmm, market is not installed
+ Log.w("BusTO-BarcodeScanUtils", "Google Play is not installed; cannot install " + packageName);
+ }
+ });
+ downloadDialog.setNegativeButton(R.string.no, null);
+ downloadDialog.setCancelable(true);
+ return downloadDialog.show();
+ }
+}
diff --git a/src/it/reyboz/bustorino/middleware/GeneralActivity.java b/src/it/reyboz/bustorino/middleware/GeneralActivity.java
--- a/src/it/reyboz/bustorino/middleware/GeneralActivity.java
+++ b/src/it/reyboz/bustorino/middleware/GeneralActivity.java
@@ -1,3 +1,20 @@
+/*
+ BusTO - Arrival times for Turin public transport.
+ Copyright (C) 2021 Fabio Mazza
+
+ 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 <http://www.gnu.org/licenses/>.
+ */
package it.reyboz.bustorino.middleware;
import android.Manifest;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Oct 23, 17:20 (7 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
641383
Default Alt Text
D92.1729696839.diff (50 KB)
Attached To
Mode
D92: Get stop by QR Code again!
Attached
Detach File
Event Timeline
Log In to Comment