diff --git a/app/src/main/java/it/reyboz/bustorino/data/GtfsAlertDBDownloadWorker.kt b/app/src/main/java/it/reyboz/bustorino/data/GtfsAlertDBDownloadWorker.kt --- a/app/src/main/java/it/reyboz/bustorino/data/GtfsAlertDBDownloadWorker.kt +++ b/app/src/main/java/it/reyboz/bustorino/data/GtfsAlertDBDownloadWorker.kt @@ -3,12 +3,15 @@ import android.app.NotificationManager import android.content.Context import android.util.Log +import androidx.lifecycle.LiveData import androidx.work.BackoffPolicy import androidx.work.CoroutineWorker import androidx.work.Data import androidx.work.ForegroundInfo import androidx.work.OneTimeWorkRequest import androidx.work.OutOfQuotaPolicy +import androidx.work.WorkInfo +import androidx.work.WorkManager import androidx.work.WorkerParameters import com.android.volley.Response import com.android.volley.VolleyError @@ -18,6 +21,7 @@ import it.reyboz.bustorino.backend.NetworkVolleyManager import it.reyboz.bustorino.backend.Notifications import it.reyboz.bustorino.backend.gtfs.GtfsRtAlertsRequest +import it.reyboz.bustorino.data.DBUpdateWorker.Companion.WORK_NAME import it.reyboz.bustorino.data.GtfsMaintenanceWorker.Companion.OPERATION_TYPE import it.reyboz.bustorino.data.gtfs.GtfsAlertsActivePeriods import it.reyboz.bustorino.data.gtfs.GtfsAlertsTranslation @@ -48,26 +52,26 @@ val req = GtfsRtAlertsRequest(object : Response.ErrorListener { override fun onErrorResponse(err: VolleyError) { - Log.e(DEBUG_TAG, "Error getting alerts: ${err.message}", err) + Log.e(DEBUG_TAG, "Error getting alerts, message: ${err.message}", err) } }, future) volleyManager.requestQueue.add(req) try { - resuList = future.get(10, TimeUnit.SECONDS) + resuList = future.get(15, TimeUnit.SECONDS) if (resuList.isNotEmpty()){ Log.d(DEBUG_TAG, "Have no alerts, attempt $attempts") notOK = false } } catch (e: InterruptedException) { - e.printStackTrace() - Log.e(DEBUG_TAG, e.message, e) + //e.printStackTrace() + Log.w(DEBUG_TAG, "Interrupted: ", e) } catch (e: ExecutionException) { - e.printStackTrace() - Log.e(DEBUG_TAG, e.message, e) + //e.printStackTrace() + Log.w(DEBUG_TAG, e.message, e) } catch (e: TimeoutException) { - e.printStackTrace() - Log.e(DEBUG_TAG, e.message, e) + //e.printStackTrace() + Log.w(DEBUG_TAG, "Timeout for download", e) } attempts++ @@ -109,12 +113,20 @@ private const val NOTIFICATION_ID = 271899102 private const val DEBUG_TAG = "BusTO-GTFSRTAlertsDown" + @JvmStatic fun makeOneTimeRequest(tag: String): OneTimeWorkRequest { //val data = Data.Builder().putString(OPERATION_TYPE, type).build() return OneTimeWorkRequest.Builder(GtfsAlertDBDownloadWorker::class.java) .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) + .setBackoffCriteria(BackoffPolicy.LINEAR, 30, TimeUnit.SECONDS) .addTag(tag) .build() } + + @JvmStatic + fun getWorkInfoLiveData(context: Context): LiveData> { + val workManager = WorkManager.getInstance(context) + return workManager.getWorkInfosForUniqueWorkLiveData(WORK_NAME) + } } } \ No newline at end of file diff --git a/app/src/main/java/it/reyboz/bustorino/data/gtfs/GtfsAlertsDBConverter.kt b/app/src/main/java/it/reyboz/bustorino/data/gtfs/GtfsAlertsDBConverter.kt --- a/app/src/main/java/it/reyboz/bustorino/data/gtfs/GtfsAlertsDBConverter.kt +++ b/app/src/main/java/it/reyboz/bustorino/data/gtfs/GtfsAlertsDBConverter.kt @@ -108,7 +108,7 @@ //agencyId = if (e.hasAgencyId()) e.agencyId else null, routeId = if (e.hasRouteId()) "gtt:${e.routeId}" else null, routeType = if (e.hasRouteType()) e.routeType else null, - stopId = if (e.hasStopId()) e.stopId else null, + stopId = if (e.hasStopId()) "gtt:${e.stopId}" else null, tripId = tripId, tripRouteId = tripRouteId, directionId = directionId diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/AlertsDialogFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/AlertsDialogFragment.kt --- a/app/src/main/java/it/reyboz/bustorino/fragments/AlertsDialogFragment.kt +++ b/app/src/main/java/it/reyboz/bustorino/fragments/AlertsDialogFragment.kt @@ -27,7 +27,7 @@ import kotlin.collections.HashMap -class AlertsDialogFragment(private val gtfsLineShow: String) : DialogFragment() { +class AlertsDialogFragment(private val gtfsLineShow: String, private val stopToShow: String) : DialogFragment() { private lateinit var titleTextView: TextView private lateinit var messageTextView: TextView @@ -38,7 +38,7 @@ override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - Log.d(DEBUG_TAG, "created DialogFragment for line ${gtfsLineShow}") + Log.d(DEBUG_TAG, "created DialogFragment for line ${gtfsLineShow} and/or stop ${stopToShow}") } override fun onCreateView( @@ -49,13 +49,24 @@ val root = inflater.inflate(R.layout.fragment_dialog_alerts_line, container, false) titleTextView = root.findViewById(R.id.titleTextView) - titleTextView.setText(getString(R.string.alert_line_fill,GtfsUtils.lineNameDisplayFromGtfsID(gtfsLineShow))) + val text = if (gtfsLineShow.isNotEmpty()) + getString(R.string.alert_line_fill,GtfsUtils.lineNameDisplayFromGtfsID(gtfsLineShow)) + else if(stopToShow.isNotEmpty()){ + getString(R.string.alert_stop_fill,stopToShow) + } else{ + throw Exception("Either text or line has to be filled") + } + titleTextView.setText(text) recyclerView = root.findViewById(R.id.alertsRecyclerView) recyclerView.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false) messageTextView = root.findViewById(R.id.alertMessageTextView) statusCardView = root.findViewById(R.id.statusCard) - alertsViewModel.alertsByRouteLiveData.observe(viewLifecycleOwner){ alerts -> - showAlerts(alerts) + if(gtfsLineShow.isNotEmpty()) + alertsViewModel.alertsByRouteLiveData.observe(viewLifecycleOwner){ alerts -> + showAlerts(alerts) + } + else if(stopToShow.isNotEmpty()){ + alertsViewModel.alertsByStopLiveData.observe(viewLifecycleOwner){ alerts -> showAlerts(alerts) } } val btnClose = root.findViewById(R.id.btnClose) @@ -133,11 +144,14 @@ * @return A new instance of fragment LineAlertsDialogFragment. */ @JvmStatic - fun newInstance(gtfsLine: String) = - AlertsDialogFragment(gtfsLine) + fun newInstanceForLine(gtfsLine: String) = + AlertsDialogFragment(gtfsLine, "") + @JvmStatic + fun newInstanceForStop(stop: String) = + AlertsDialogFragment("", stop) private const val GTFS_LINE_ARG = "gtfsLine" private const val DEBUG_TAG = "BusTO-AlertsDialog" } } \ No newline at end of file diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/AlertsFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/AlertsFragment.kt --- a/app/src/main/java/it/reyboz/bustorino/fragments/AlertsFragment.kt +++ b/app/src/main/java/it/reyboz/bustorino/fragments/AlertsFragment.kt @@ -30,6 +30,7 @@ private val alertsViewModel: ServiceAlertsViewModel by activityViewModels() private lateinit var textView: TextView + private lateinit var statusTextView: TextView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) arguments?.let { @@ -45,18 +46,39 @@ // Inflate the layout for this fragment val root = inflater.inflate(R.layout.fragment_alerts, container, false) textView = root.findViewById(R.id.simpleTextView) + statusTextView = root.findViewById(R.id.statusTextView) alertsViewModel.allAlertsLiveData.observe(viewLifecycleOwner, { alerts -> - val sb = StringBuilder() - val unixTimestamp = (System.currentTimeMillis() / 1000) - for (x in alerts) { - sb.append(x.longPrint()) - sb.append("----- Alert active: ").append(x.isActive(unixTimestamp)).append("\n\n") + if(alerts==null){ + return@observe } + if(alerts.isEmpty()){ + textView.text = "No Alerts to show" + } else { + val sb = StringBuilder() + val unixTimestamp = (System.currentTimeMillis() / 1000) + for (x in alerts) { + sb.append(x.longPrint()) + sb.append("----- Alert active: ").append(x.isActive(unixTimestamp)).append("\n\n") + } - textView.text = sb.toString() + textView.text = sb.toString() + } }) + alertsViewModel.getDownloadStatusLiveData(requireContext()).observe(viewLifecycleOwner, { workinfos -> + val sb = StringBuilder() + var c = 1 + if(workinfos!=null && workinfos.isNotEmpty()){ + for (worki in workinfos){ + sb.append("$c - state: ${worki.state}, attempt ${worki.runAttemptCount}").append("\n") + c++ + } + } + statusTextView.text = sb.toString() + }) + + alertsViewModel.setStopFilter("472") /*alertsViewModel.alertsForStop.observe(viewLifecycleOwner){ diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt --- a/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt +++ b/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt @@ -25,6 +25,8 @@ import android.view.View import android.view.ViewGroup import android.widget.* +import androidx.cardview.widget.CardView +import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.loader.app.LoaderManager import androidx.loader.content.CursorLoader @@ -47,6 +49,7 @@ import it.reyboz.bustorino.middleware.AsyncStopFavoriteAction import it.reyboz.bustorino.util.LinesNameSorter import it.reyboz.bustorino.viewmodels.ArrivalsViewModel +import it.reyboz.bustorino.viewmodels.ServiceAlertsViewModel import java.util.* @@ -79,6 +82,7 @@ private lateinit var howDoesItWorkTextView: TextView private lateinit var hideHintButton: Button + private lateinit var alertsCardView : CardView //private NestedScrollView theScrollView; protected lateinit var noArrivalsRecyclerView: RecyclerView @@ -89,6 +93,7 @@ //private View canaryEndView; private var fetchers: List = ArrayList() private val arrivalsViewModel : ArrivalsViewModel by viewModels() + private val alertsViewModel: ServiceAlertsViewModel by activityViewModels() private var reloadOnResume = true @@ -174,6 +179,7 @@ resultsLayout = root.findViewById(R.id.resultsLayout) loadingMessageTextView = root.findViewById(R.id.loadingMessageTextView) progressBar = root.findViewById(R.id.circularProgressBar) + alertsCardView = root.findViewById(R.id.alertsCardView) hideHintButton.setOnClickListener { v: View? -> this.onHideHint(v) } @@ -319,6 +325,18 @@ else -> showFetcherMessage(R.string.internal_error, src) } } + + + alertsViewModel.alertsByStopLiveData.observe(viewLifecycleOwner, { alerts -> + if(alerts!=null && alerts.isNotEmpty()){ + alertsCardView.visibility = View.VISIBLE + alertsCardView.setOnClickListener { + AlertsDialogFragment.newInstanceForStop(stopID).show(parentFragmentManager, "AlertsDialogStop$stopID") + } + } else{ + alertsCardView.visibility = View.GONE + } + }) return root } @@ -480,7 +498,16 @@ * @param p the full Palina */ fun updateFragmentData(p: Palina?) { - if (p != null) lastUpdatedPalina = p + if (p != null) { + lastUpdatedPalina = p + //set the gtfsID for the alerts + if(p.gtfsID==null){ + Log.w(DEBUG_TAG, "The palina given has no gtfs ID") + } else{ + alertsViewModel.setStopFilter(p.gtfsID!!) + } + } + if (!isAdded) { //defer update at next show diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt --- a/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt +++ b/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt @@ -385,7 +385,7 @@ lineInfoButton.visibility = View.GONE } lineInfoButton.setOnClickListener { - AlertsDialogFragment(lineID).show(parentFragmentManager, "Alerts-Line$lineID") + AlertsDialogFragment.newInstanceForLine(lineID).show(parentFragmentManager, "Alerts-Line$lineID") } /* diff --git a/app/src/main/java/it/reyboz/bustorino/viewmodels/ServiceAlertsViewModel.kt b/app/src/main/java/it/reyboz/bustorino/viewmodels/ServiceAlertsViewModel.kt --- a/app/src/main/java/it/reyboz/bustorino/viewmodels/ServiceAlertsViewModel.kt +++ b/app/src/main/java/it/reyboz/bustorino/viewmodels/ServiceAlertsViewModel.kt @@ -1,17 +1,21 @@ package it.reyboz.bustorino.viewmodels import android.app.Application +import android.content.Context import android.util.Log import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.map import androidx.lifecycle.switchMap import androidx.lifecycle.viewModelScope import androidx.room.concurrent.AtomicBoolean import androidx.work.ExistingWorkPolicy +import androidx.work.WorkInfo import androidx.work.WorkManager import com.google.transit.realtime.GtfsRealtime.Alert import it.reyboz.bustorino.backend.NetworkVolleyManager +import it.reyboz.bustorino.data.DBUpdateWorker.Companion.WORK_NAME import it.reyboz.bustorino.data.GtfsAlertDBDownloadWorker import it.reyboz.bustorino.data.GtfsRepository import it.reyboz.bustorino.data.gtfs.GtfsDatabase @@ -94,7 +98,7 @@ currentTime > lastTimeRunningDownload.value!! + MINUTES_CHECK*60*1000){ //actually enqueue request Log.d(DEBUG_TAG, "Launching request to download alerts") - val req = GtfsAlertDBDownloadWorker.makeOneTimeRequest("alertsrn") + val req = GtfsAlertDBDownloadWorker.makeOneTimeRequest(WORK_TAG) workManager.enqueueUniqueWork("AlertsDownloadsRun", ExistingWorkPolicy.KEEP, req) lastTimeRunningDownload.postValue(System.currentTimeMillis()) } @@ -112,7 +116,10 @@ downloadWorkIfTimePassed() } - + fun getDownloadStatusLiveData(context: Context): LiveData>{ + val workManager = WorkManager.getInstance(context) + return workManager.getWorkInfosByTagLiveData(WORK_TAG) + } private fun filterAlertsForStop(stopId: String, alerts: ArrayList) : ArrayList{ @@ -174,6 +181,7 @@ companion object{ private const val DEBUG_TAG = "BusTO-GTFSRTAlerts" + public const val WORK_TAG = "AlertsDownloadWorker" } } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_alerts.xml b/app/src/main/res/layout/fragment_alerts.xml --- a/app/src/main/res/layout/fragment_alerts.xml +++ b/app/src/main/res/layout/fragment_alerts.xml @@ -7,15 +7,23 @@ android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".fragments.AlertsFragment"> - - + + android:layout_height="0dp" + android:layout_margin="10dp" + > + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + + + + + + @color/metro_red @color/orange_icons_10light @color/grey_400 + @color/orange_500 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -381,6 +381,7 @@ Updated: %1$s Alerts for line %1$s: + Alerts for stop %1$s: No alerts in your language, showing in %1$s Italian English