Page MenuHomeGitPull.it

D92.1729696839.diff
No OneTemporary

Size
50 KB
Referenced Files
None
Subscribers
None

D92.1729696839.diff

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

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)

Event Timeline