diff --git a/src/main/java/org/mtransit/android/commons/SqlUtils.java b/src/main/java/org/mtransit/android/commons/SqlUtils.java index 1ca6f129..8b75db2c 100644 --- a/src/main/java/org/mtransit/android/commons/SqlUtils.java +++ b/src/main/java/org/mtransit/android/commons/SqlUtils.java @@ -162,6 +162,11 @@ public static String getWhereNotInString(@NonNull String tableColumn, @Nullable return SQLUtils.getWhereInString(tableColumn, values, true); } + @NonNull + public static String getWhereColumnIsNull(@NonNull String tableColumn) { + return SQLUtils.getWhereColumnIsNull(tableColumn); + } + @NonNull public static String escapeString(@NonNull String string) { return SQLUtils.escapeString(string); diff --git a/src/main/java/org/mtransit/android/commons/data/ServiceUpdate.java b/src/main/java/org/mtransit/android/commons/data/ServiceUpdate.java index 0a9b97f3..cad35417 100644 --- a/src/main/java/org/mtransit/android/commons/data/ServiceUpdate.java +++ b/src/main/java/org/mtransit/android/commons/data/ServiceUpdate.java @@ -42,6 +42,8 @@ public String getLogTag() { private final Integer id; // internal DB ID (useful to delete) OR NULL @NonNull private String targetUUID; + @Nullable + private final String targetTripId; private final long lastUpdateInMs; private final long maxValidityInMs; private final String text; @@ -57,6 +59,7 @@ public String getLogTag() { public ServiceUpdate( @Nullable Integer optId, @NonNull String targetUUID, + @Nullable String targetTripId, long lastUpdateInMs, long maxValidityInMs, @NonNull String text, @@ -69,6 +72,7 @@ public ServiceUpdate( ) { this.id = optId; this.targetUUID = targetUUID; + this.targetTripId = targetTripId; this.lastUpdateInMs = lastUpdateInMs; this.maxValidityInMs = maxValidityInMs; this.text = text; @@ -89,6 +93,11 @@ public String getTargetUUID() { return targetUUID; } + @Nullable + public String getTargetTripId() { + return targetTripId; + } + public boolean isSeverityWarning() { return isSeverityWarning(this.severity); } @@ -199,7 +208,9 @@ public String toString() { ',' + // "oId:" + this.originalId + // ',' + // - "target:" + this.targetUUID + // + "tUUID:" + this.targetUUID + // + ',' + // + "tTrip:" + this.targetTripId + // ',' + // "lang:" + this.language + // ',' + // @@ -224,19 +235,20 @@ public long getLastUpdateInMs() { @NonNull public static ServiceUpdate fromCursor(@NonNull Cursor cursor) { - int idIdx = cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_ID); - Integer id = cursor.isNull(idIdx) ? null : cursor.getInt(idIdx); - String targetUUID = cursor.getString(cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_TARGET_UUID)); - long lastUpdateInMs = cursor.getLong(cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_LAST_UPDATE)); - long maxValidityInMs = cursor.getLong(cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_MAX_VALIDITY_IN_MS)); - int severity = cursor.getInt(cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_SEVERITY)); - String text = cursor.getString(cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_TEXT)); - String htmlText = cursor.getString(cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_TEXT_HTML)); - String language = cursor.getString(cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_LANGUAGE)); - String originalId = CursorExtKt.optString(cursor, ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_ORIGINAL_ID, null); - String sourceLabel = cursor.getString(cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_SOURCE_LABEL)); - String sourceId = cursor.getString(cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_SOURCE_ID)); - return new ServiceUpdate(id, targetUUID, lastUpdateInMs, maxValidityInMs, text, htmlText, severity, sourceId, sourceLabel, originalId, language); + final int idIdx = cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_ID); + final Integer id = cursor.isNull(idIdx) ? null : cursor.getInt(idIdx); + final String targetUUID = cursor.getString(cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_TARGET_UUID)); + final String targetTripId = CursorExtKt.optString(cursor, ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_TARGET_TRIP_ID, null); + final long lastUpdateInMs = cursor.getLong(cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_LAST_UPDATE)); + final long maxValidityInMs = cursor.getLong(cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_MAX_VALIDITY_IN_MS)); + final int severity = cursor.getInt(cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_SEVERITY)); + final String text = cursor.getString(cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_TEXT)); + final String htmlText = cursor.getString(cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_TEXT_HTML)); + final String language = cursor.getString(cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_LANGUAGE)); + final String originalId = CursorExtKt.optString(cursor, ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_ORIGINAL_ID, null); + final String sourceLabel = cursor.getString(cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_SOURCE_LABEL)); + final String sourceId = cursor.getString(cursor.getColumnIndexOrThrow(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_SOURCE_ID)); + return new ServiceUpdate(id, targetUUID, targetTripId, lastUpdateInMs, maxValidityInMs, text, htmlText, severity, sourceId, sourceLabel, originalId, language); } /** @@ -247,6 +259,7 @@ public Object[] getCursorRow() { return new Object[]{ id, targetUUID, + targetTripId, lastUpdateInMs, maxValidityInMs, severity, @@ -266,6 +279,7 @@ public ContentValues toContentValues() { contentValues.put(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_ID, this.id); } // ELSE AUTO INCREMENT contentValues.put(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_TARGET_UUID, this.targetUUID); + contentValues.put(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_TARGET_TRIP_ID, this.targetTripId); contentValues.put(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_LAST_UPDATE, this.lastUpdateInMs); contentValues.put(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_MAX_VALIDITY_IN_MS, this.maxValidityInMs); contentValues.put(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_SEVERITY, this.severity); diff --git a/src/main/java/org/mtransit/android/commons/data/ServiceUpdateKtx.kt b/src/main/java/org/mtransit/android/commons/data/ServiceUpdateKtx.kt index a913b660..08aa185f 100644 --- a/src/main/java/org/mtransit/android/commons/data/ServiceUpdateKtx.kt +++ b/src/main/java/org/mtransit/android/commons/data/ServiceUpdateKtx.kt @@ -24,8 +24,8 @@ fun Iterable?.isSeverityWarningInfo(): Pair { fun Iterable.distinctByOriginalId() = this.distinctBy { it.originalId ?: it.id } // keep 1st occurrence from sorted list (in *Manager) -fun ServiceUpdateProviderContract.makeServiceUpdateNoneList(targetable: Targetable, sourceId: String): ArrayList = - ArrayList().apply { +fun ServiceUpdateProviderContract.makeServiceUpdateNoneList(targetable: Targetable, sourceId: String) = + buildList { add(makeServiceUpdateNone(targetable.uuid, sourceId)) } @@ -33,6 +33,7 @@ fun ServiceUpdateProviderContract.makeServiceUpdateNone(targetUUID: String, sour ServiceUpdate( null, targetUUID, + null, TimeUtils.currentTimeMillis(), getServiceUpdateMaxValidityInMs(), StringUtils.EMPTY, diff --git a/src/main/java/org/mtransit/android/commons/provider/GTFSRealTimeProvider.java b/src/main/java/org/mtransit/android/commons/provider/GTFSRealTimeProvider.java index 3537230d..9cc8d9ab 100644 --- a/src/main/java/org/mtransit/android/commons/provider/GTFSRealTimeProvider.java +++ b/src/main/java/org/mtransit/android/commons/provider/GTFSRealTimeProvider.java @@ -1,7 +1,5 @@ package org.mtransit.android.commons.provider; -import static org.mtransit.android.commons.data.ServiceUpdateKtxKt.makeServiceUpdateNoneList; - import android.annotation.SuppressLint; import android.content.ContentValues; import android.content.Context; @@ -35,12 +33,8 @@ import org.mtransit.android.commons.data.Direction; import org.mtransit.android.commons.data.POI; import org.mtransit.android.commons.data.Route; -import org.mtransit.android.commons.data.RouteDirection; -import org.mtransit.android.commons.data.RouteDirectionStop; import org.mtransit.android.commons.data.ServiceUpdate; -import org.mtransit.android.commons.data.ServiceUpdateKtxKt; import org.mtransit.android.commons.data.Stop; -import org.mtransit.android.commons.data.Targetable; import org.mtransit.android.commons.provider.agency.AgencyUtils; import org.mtransit.android.commons.provider.common.MTContentProvider; import org.mtransit.android.commons.provider.common.MTSQLiteOpenHelper; @@ -49,7 +43,9 @@ import org.mtransit.android.commons.provider.gtfs.GtfsRealTimeStorage; import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt; import org.mtransit.android.commons.provider.gtfs.alert.GTFSRTAlertsManager; +import org.mtransit.android.commons.provider.serviceupdate.GTFSRealTimeServiceAlertsProvider; import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateCleaner; +import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateDbHelper; import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateProvider; import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateProviderContract; import org.mtransit.android.commons.provider.vehiclelocations.GTFSRealTimeVehiclePositionsProvider; @@ -59,6 +55,7 @@ import org.mtransit.android.commons.provider.vehiclelocations.model.VehicleLocation; import org.mtransit.commons.Cleaner; import org.mtransit.commons.CollectionUtils; +import org.mtransit.commons.FeatureFlags; import org.mtransit.commons.GTFSCommons; import org.mtransit.commons.SourceUtils; @@ -69,8 +66,6 @@ import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -587,172 +582,53 @@ public String getServiceUpdateDbTableName() { } @Override - public void cacheServiceUpdates(@NonNull ArrayList newServiceUpdates) { + public void cacheServiceUpdates(@NonNull List newServiceUpdates) { ServiceUpdateProvider.cacheServiceUpdatesS(this, newServiceUpdates); } @Nullable @Override - public ArrayList getCachedServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { - if ((serviceUpdateFilter.getPoi() instanceof RouteDirectionStop)) { - return getCachedServiceUpdates((RouteDirectionStop) serviceUpdateFilter.getPoi()); - } else if ((serviceUpdateFilter.getRouteDirection() != null)) { - return getCachedServiceUpdates(serviceUpdateFilter.getRouteDirection()); - } else if ((serviceUpdateFilter.getRoute() != null)) { - return getCachedServiceUpdates(serviceUpdateFilter.getRoute()); - } else { - MTLog.w(this, "getCachedServiceUpdates() > no service update (poi null or not RDS or no route)"); - return null; - } - } - - @NonNull - private ArrayList getCachedServiceUpdates(@NonNull RouteDirectionStop rds) { - final Context context = requireContextCompat(); - //noinspection UnnecessaryLocalVariable - final ArrayList cachedServiceUpdates = getCachedServiceUpdates(context, getProviderTargetUUIDs(context, rds)); - // if (org.mtransit.commons.Constants.DEBUG) { - // MTLog.d(this, "getCachedServiceUpdates() > %s service updates for %s.", cachedServiceUpdates.size(), rds.getUUID()); - // for (ServiceUpdate serviceUpdate : cachedServiceUpdates) { - // MTLog.d(this, "getCachedServiceUpdates() > - %s", serviceUpdate); - // } - // } - return cachedServiceUpdates; - } - - @NonNull - private ArrayList getCachedServiceUpdates(@NonNull RouteDirection rd) { - final Context context = requireContextCompat(); - //noinspection UnnecessaryLocalVariable - final ArrayList cachedServiceUpdates = getCachedServiceUpdates(context, getProviderTargetUUIDs(context, rd)); - // if (org.mtransit.commons.Constants.DEBUG) { - // MTLog.d(this, "getCachedServiceUpdates() > %s service updates for %s.", cachedServiceUpdates.size(), rd.getUUID()); + public List getCachedServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { + final List cachedServiceUpdates = GTFSRealTimeServiceAlertsProvider.getCached(this, serviceUpdateFilter); + GTFSRealTimeServiceAlertsProvider.enhanceServiceUpdate(this, cachedServiceUpdates); + // if (org.mtransit.android.commons.Constants.DEBUG) { + // MTLog.d(this, "getCachedServiceUpdates() > %s service updates for %s.", cachedServiceUpdates == null ? null : cachedServiceUpdates.size(), serviceUpdateFilter.getTargetUUID()); + // if (cachedServiceUpdates != null) { // for (ServiceUpdate serviceUpdate : cachedServiceUpdates) { // MTLog.d(this, "getCachedServiceUpdates() > - %s", serviceUpdate); // } // } - return cachedServiceUpdates; - } - - @NonNull - private ArrayList getCachedServiceUpdates(@NonNull Route route) { - final Context context = requireContextCompat(); - //noinspection UnnecessaryLocalVariable - final ArrayList cachedServiceUpdates = getCachedServiceUpdates(context, getProviderTargetUUIDs(context, route)); - // if (org.mtransit.commons.Constants.DEBUG) { - // MTLog.d(this, "getCachedServiceUpdates() > %s service updates for %s.", cachedServiceUpdates.size(), route.getUUID()); - // for (ServiceUpdate serviceUpdate : cachedServiceUpdates) { - // MTLog.d(this, "getCachedServiceUpdates() > - %s", serviceUpdate); - // } // } return cachedServiceUpdates; } - @NonNull - private ArrayList getCachedServiceUpdates(@NonNull Context context, - @NonNull Map targetUUIDs) { - final ArrayList serviceUpdates = new ArrayList<>(); - CollectionUtils.addAllN(serviceUpdates, ServiceUpdateProvider.getCachedServiceUpdatesS(this, targetUUIDs.keySet())); - enhanceServiceUpdate(context, serviceUpdates, targetUUIDs); - return serviceUpdates; - } - - @NonNull - private Map getProviderTargetUUIDs(@NonNull Context context, @NonNull RouteDirectionStop rds) { - final HashMap targetUUIDs = new HashMap<>(); - targetUUIDs.put(getAgencyTagTargetUUID(getAgencyTag(context)), rds.getAuthority()); - CollectionUtils.putNotNull(targetUUIDs, getAgencyRouteTypeTagTargetUUID(getAgencyTag(context), getRouteTypeTag(rds)), rds.getAuthority()); - targetUUIDs.put(getAgencyRouteTagTargetUUID(getAgencyTag(context), getRouteTag(rds)), rds.getRoute().getUUID()); - CollectionUtils.putNotNull(targetUUIDs, - getAgencyRouteDirectionTagTargetUUID(getAgencyTag(context), getRouteTag(rds), getDirectionTag(rds)), rds.getRouteDirectionUUID()); - CollectionUtils.putNotNull(targetUUIDs, - getAgencyRouteDirectionStopTagTargetUUID(getAgencyTag(context), getRouteTag(rds), getDirectionTag(rds), getStopTag(rds)), rds.getUUID()); - targetUUIDs.put(getAgencyStopTagTargetUUID(getAgencyTag(context), getStopTag(rds)), rds.getUUID()); - targetUUIDs.put(getAgencyRouteStopTagTargetUUID(getAgencyTag(context), getRouteTag(rds), getStopTag(rds)), rds.getUUID()); - return targetUUIDs; - } - - @NonNull - private Map getProviderTargetUUIDs(@NonNull Context context, @NonNull RouteDirection rd) { - final HashMap targetUUIDs = new HashMap<>(); - targetUUIDs.put(getAgencyTagTargetUUID(getAgencyTag(context)), rd.getAuthority()); - CollectionUtils.putNotNull(targetUUIDs, getAgencyRouteTypeTagTargetUUID(getAgencyTag(context), getRouteTypeTag(rd)), rd.getAuthority()); - targetUUIDs.put(getAgencyRouteTagTargetUUID(getAgencyTag(context), getRouteTag(rd)), rd.getRoute().getUUID()); - CollectionUtils.putNotNull(targetUUIDs, - getAgencyRouteDirectionTagTargetUUID(getAgencyTag(context), getRouteTag(rd), getDirectionTag(rd)), rd.getUUID()); - return targetUUIDs; - } - - @NonNull - private Map getProviderTargetUUIDs(@NonNull Context context, @NonNull Route route) { - final HashMap targetUUIDs = new HashMap<>(); - targetUUIDs.put(getAgencyTagTargetUUID(getAgencyTag(context)), route.getAuthority()); - targetUUIDs.put(getAgencyRouteTagTargetUUID(getAgencyTag(context), getRouteTag(route)), route.getUUID()); - return targetUUIDs; - } - @NonNull public String getAgencyTag(@NonNull Context context) { return getRDS_AGENCY_ID(context); } - @NonNull - private String getRouteTag(@NonNull RouteDirectionStop rds) { - return getRouteTag(rds.getRoute()); - } - - @NonNull - private String getRouteTag(@NonNull RouteDirection rd) { - return getRouteTag(rd.getRoute()); - } - @NonNull public String getRouteTag(@NonNull Route route) { return String.valueOf(route.getOriginalIdHash()); } - private int getRouteTypeTag(@NonNull RouteDirectionStop rds) { - Integer originalRouteType = getRouteTypeTag(rds.getRoute()); - return originalRouteType != null ? originalRouteType : rds.getDataSourceTypeId(); - } - - @Nullable - private Integer getRouteTypeTag(@NonNull RouteDirection routeDirection) { - return getRouteTypeTag(routeDirection.getRoute()); - } - @Nullable - private Integer getRouteTypeTag(@NonNull Route route) { + public Integer getRouteTypeTag(@NonNull Route route) { return route.getType(); } - @Nullable - private Integer getDirectionTag(@NonNull RouteDirectionStop rds) { - return getDirectionTag(rds.getDirection()); - } - - @Nullable - private Integer getDirectionTag(@NonNull RouteDirection rd) { - return getDirectionTag(rd.getDirection()); - } - @Nullable public Integer getDirectionTag(@NonNull Direction direction) { return direction.getOriginalDirectionIdOrNull(); } @NonNull - private String getStopTag(@NonNull RouteDirectionStop rds) { - return getStopTag(rds.getStop()); - } - - @NonNull - private String getStopTag(@NonNull Stop stop) { + public String getStopTag(@NonNull Stop stop) { return String.valueOf(stop.getOriginalIdHash()); } @NonNull - protected static String getAgencyStopTagTargetUUID(@NonNull String agencyTag, @NonNull String stopTag) { + public static String getAgencyStopTagTargetUUID(@NonNull String agencyTag, @NonNull String stopTag) { return POI.POIUtils.getUUID(agencyTag, "si" + stopTag); } @@ -762,12 +638,12 @@ public static String getAgencyRouteTagTargetUUID(@NonNull String agencyTag, @Non } @NonNull - protected static String getAgencyRouteStopTagTargetUUID(@NonNull String agencyTag, @NonNull String routeTag, @NonNull String stopTag) { + public static String getAgencyRouteStopTagTargetUUID(@NonNull String agencyTag, @NonNull String routeTag, @NonNull String stopTag) { return POI.POIUtils.getUUID(agencyTag, "ri" + routeTag, "si" + stopTag); } @Nullable - protected static String getAgencyRouteTypeTagTargetUUID(@NonNull String agencyTag, @Nullable Integer routeType) { + public static String getAgencyRouteTypeTagTargetUUID(@NonNull String agencyTag, @Nullable Integer routeType) { if (routeType == null) return null; return POI.POIUtils.getUUID(agencyTag, "t" + routeType); } @@ -779,7 +655,7 @@ public static String getAgencyRouteDirectionTagTargetUUID(@NonNull String agency } @Nullable - protected static String getAgencyRouteDirectionStopTagTargetUUID(@NonNull String agencyTag, @NonNull String routeTag, @Nullable Integer directionTag, @NonNull String stopTag) { + public static String getAgencyRouteDirectionStopTagTargetUUID(@NonNull String agencyTag, @NonNull String routeTag, @Nullable Integer directionTag, @NonNull String stopTag) { if (directionTag == null) return null; return POI.POIUtils.getUUID(agencyTag, "ri" + routeTag, "d" + directionTag, "si" + stopTag); } @@ -789,71 +665,16 @@ public static String getAgencyTagTargetUUID(@NonNull String agencyTag) { return POI.POIUtils.getUUID(agencyTag); } - @Nullable @Override - public ArrayList getNewServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { + public @Nullable List getNewServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { this.providedAgencyUrlToken = SecureStringUtils.dec(serviceUpdateFilter.getProvidedEncryptKey(KeysIds.GTFS_REAL_TIME_URL_TOKEN)); this.providedAgencyUrlSecret = SecureStringUtils.dec(serviceUpdateFilter.getProvidedEncryptKey(KeysIds.GTFS_REAL_TIME_URL_SECRET)); - if ((serviceUpdateFilter.getPoi() instanceof RouteDirectionStop)) { - return getNewServiceUpdates((RouteDirectionStop) serviceUpdateFilter.getPoi(), serviceUpdateFilter.isInFocusOrDefault()); - } else if ((serviceUpdateFilter.getRouteDirection() != null)) { - return getNewServiceUpdates(serviceUpdateFilter.getRouteDirection(), serviceUpdateFilter.isInFocusOrDefault()); - } else if ((serviceUpdateFilter.getRoute() != null)) { - return getNewServiceUpdates(serviceUpdateFilter.getRoute(), serviceUpdateFilter.isInFocusOrDefault()); - } else { - MTLog.w(this, "getNewServiceUpdates() > no service update (poi null or not RDS or no route)"); - return null; - } - } - - private ArrayList getNewServiceUpdates(@NonNull RouteDirectionStop rds, boolean inFocus) { - final Context context = requireContextCompat(); - updateAgencyServiceUpdateDataIfRequired(context, inFocus); - ArrayList cachedServiceUpdates = getCachedServiceUpdates(rds); - return getServiceUpdatesOrNone(context, rds, cachedServiceUpdates); - } - - private ArrayList getNewServiceUpdates(@NonNull RouteDirection rd, boolean inFocus) { - final Context context = requireContextCompat(); - updateAgencyServiceUpdateDataIfRequired(context, inFocus); - ArrayList cachedServiceUpdates = getCachedServiceUpdates(rd); - return getServiceUpdatesOrNone(context, rd, cachedServiceUpdates); - } - - private ArrayList getNewServiceUpdates(@NonNull Route route, boolean inFocus) { - final Context context = requireContextCompat(); - updateAgencyServiceUpdateDataIfRequired(context, inFocus); - ArrayList cachedServiceUpdates = getCachedServiceUpdates(route); - return getServiceUpdatesOrNone(context, route, cachedServiceUpdates); - } - - private ArrayList getServiceUpdatesOrNone(Context context, Targetable target, ArrayList cachedServiceUpdates) { - if (CollectionUtils.getSize(cachedServiceUpdates) == 0) { - cachedServiceUpdates = makeServiceUpdateNoneList(this, target, AGENCY_SOURCE_ID); - enhanceServiceUpdate(context, cachedServiceUpdates, Collections.emptyMap()); // convert to stop service update - } - return cachedServiceUpdates; + return GTFSRealTimeServiceAlertsProvider.getNew(this, serviceUpdateFilter); } - private void enhanceServiceUpdate(@NonNull Context context, - Collection serviceUpdates, - @NonNull Map targetUUIDs // different UUID from provider target UUID - ) { - try { - if (CollectionUtils.getSize(serviceUpdates) > 0) { - for (ServiceUpdate serviceUpdate : serviceUpdates) { - ServiceUpdateKtxKt.syncTargetUUID(serviceUpdate, targetUUIDs); - serviceUpdate.setTextHTML(enhanceHtmlDateTime(context, serviceUpdate.getTextHTML())); - } - } - } catch (Exception e) { - MTLog.w(this, e, "Error while trying to enhance route direction service update for stop!"); - } - } - - private static final String AGENCY_SOURCE_ID = "gtfs_real_time_service_alerts"; + public static final String AGENCY_SOURCE_ID = "gtfs_real_time_service_alerts"; - private void updateAgencyServiceUpdateDataIfRequired(@NonNull Context context, boolean inFocus) { + public void updateAgencyServiceUpdateDataIfRequired(@NonNull Context context, boolean inFocus) { final long lastUpdateInMs = GtfsRealTimeStorage.getServiceUpdateLastUpdateMs(context, 0L); final Integer lastUpdateCode = getServiceUpdateLastUpdateCode(); if (lastUpdateCode != null && lastUpdateCode != HttpURLConnection.HTTP_OK) { @@ -889,7 +710,7 @@ private void updateAllAgencyServiceUpdateDataFromWWW(@NonNull Context context, b deleteAllAgencyServiceUpdateData(); deleteAllDone = true; } - final ArrayList newServiceUpdates = loadAgencyServiceUpdateDataFromWWW(context); + final List newServiceUpdates = loadAgencyServiceUpdateDataFromWWW(context); if (newServiceUpdates != null) { // empty is OK if (!deleteAllDone) { deleteAllAgencyServiceUpdateData(); @@ -933,7 +754,7 @@ public OkHttpClient getOkHttpClient(@NonNull Context context) { } @Nullable - private ArrayList loadAgencyServiceUpdateDataFromWWW(@NonNull Context context) { + private List loadAgencyServiceUpdateDataFromWWW(@NonNull Context context) { try { final Request urlRequest = GTFSRealTimeProviderExtKt.makeRequest(this, context, @@ -947,7 +768,7 @@ private ArrayList loadAgencyServiceUpdateDataFromWWW(@NonNull Con switch (response.code()) { case HttpURLConnection.HTTP_OK: final long newLastUpdateInMs = TimeUtils.currentTimeMillis(); - final ArrayList serviceUpdates = new ArrayList<>(); + final List serviceUpdates = new ArrayList<>(); final String sourceLabel = SourceUtils.getSourceLabel( // always use source from official API getAgencyServiceAlertsUrlString(context, "T") ); @@ -961,7 +782,7 @@ private ArrayList loadAgencyServiceUpdateDataFromWWW(@NonNull Con if (Constants.DEBUG) { MTLog.d(this, "loadAgencyServiceUpdateDataFromWWW() > GTFS alert[%s]: %s.", feedEntityId, GtfsRealtimeExt.toStringExt(gAlert)); } - HashSet alertsServiceUpdates = processAlerts(context, sourceLabel, feedEntityId, newLastUpdateInMs, gAlert, ignoreDirection); + final Set alertsServiceUpdates = processAlerts(context, sourceLabel, feedEntityId, newLastUpdateInMs, gAlert, ignoreDirection); if (alertsServiceUpdates != null && !alertsServiceUpdates.isEmpty()) { serviceUpdates.addAll(alertsServiceUpdates); } @@ -1035,10 +856,9 @@ private HashSet processAlerts( } // TODO use? GtfsRealtime.Alert.Cause gCause = gAlert.getCause(); GtfsRealtime.Alert.Effect gEffect = gAlert.getEffect(); - HashSet targetUUIDs = new HashSet<>(); + HashMap targetUUIDAndTripId = new HashMap<>(); ArrayMap targetUUIDSeverities = new ArrayMap<>(); final String providerAgencyId = getRDS_AGENCY_ID(context); - final String agencyTag = getAgencyTag(context); for (GtfsRealtime.EntitySelector gInformedEntity : gInformedEntityList) { if (gInformedEntity.hasAgencyId() && !providerAgencyId.isEmpty() @@ -1046,15 +866,16 @@ private HashSet processAlerts( MTLog.w(this, "processAlerts() > Alert targets another agency: %s", gInformedEntity.getAgencyId()); continue; } - final String targetUUID = parseProviderTargetUUID(context, agencyTag, gInformedEntity, ignoreDirection); + final String targetUUID = GTFSRealTimeServiceAlertsProvider.parseProviderTargetUUID(this, gInformedEntity, ignoreDirection); if (targetUUID == null || targetUUID.isEmpty()) { continue; } - targetUUIDs.add(targetUUID); + final String targetTripId = !FeatureFlags.F_USE_TRIP_IS_FOR_SERVICE_UPDATES ? null : GTFSRealTimeServiceAlertsProvider.parseTargetTripId(this, gInformedEntity); + targetUUIDAndTripId.put(targetUUID, targetTripId); final int severity = GTFSRTAlertsManager.parseSeverity(gInformedEntity, gEffect); targetUUIDSeverities.put(targetUUID, severity); } - if (CollectionUtils.getSize(targetUUIDs) == 0) { + if (targetUUIDAndTripId.isEmpty()) { MTLog.w(this, "processAlerts() > no target UUIDs!"); return null; } @@ -1068,23 +889,25 @@ private HashSet processAlerts( setServiceUpdateLanguages(languages); HashSet serviceUpdates = new HashSet<>(); long serviceUpdateMaxValidityInMs = getServiceUpdateMaxValidityInMs(); - for (String targetUUID : targetUUIDs) { - Integer severity = targetUUIDSeverities.get(targetUUID); + for (Map.Entry entry : targetUUIDAndTripId.entrySet()) { + final String targetUUID = entry.getKey(); + final String targetTripId = entry.getValue(); + final Integer severity = targetUUIDSeverities.get(targetUUID); for (String language : languages) { - ServiceUpdate newServiceUpdate = - generateNewServiceUpdate( - context, - sourceLabel, - feedEntityId, - newLastUpdateInMs, - headerTexts, - descriptionTexts, - urlTexts, - serviceUpdateMaxValidityInMs, - targetUUID, - severity == null ? ServiceUpdate.SEVERITY_INFO_UNKNOWN : severity, - language - ); + final ServiceUpdate newServiceUpdate = generateNewServiceUpdate( + context, + sourceLabel, + feedEntityId, + newLastUpdateInMs, + headerTexts, + descriptionTexts, + urlTexts, + serviceUpdateMaxValidityInMs, + targetUUID, + targetTripId, + severity == null ? ServiceUpdate.SEVERITY_INFO_UNKNOWN : severity, + language + ); serviceUpdates.add(newServiceUpdate); } } @@ -1145,11 +968,12 @@ private ServiceUpdate generateNewServiceUpdate( @NonNull String sourceLabel, @Nullable String feedEntityId, long newLastUpdateInMs, - ArrayMap headerTexts, - ArrayMap descriptionTexts, - ArrayMap urlTexts, + Map headerTexts, + Map descriptionTexts, + Map urlTexts, long serviceUpdateMaxValidityInMs, - String targetUUID, + @NonNull String targetUUID, + @Nullable String targetTripId, int severity, String language ) { @@ -1168,6 +992,7 @@ private ServiceUpdate generateNewServiceUpdate( return new ServiceUpdate( null, targetUUID, + targetTripId, newLastUpdateInMs, serviceUpdateMaxValidityInMs, ServiceUpdateCleaner.makeText(header, description), @@ -1253,7 +1078,8 @@ private ThreadSafeDateFormatter getTimeParser(@NonNull Context context) { return timeParser; } - private String enhanceHtmlDateTime(@NonNull Context context, @Nullable String html) throws ParseException { + @Nullable + public String enhanceHtmlDateTime(@NonNull Context context, @Nullable String html) throws ParseException { if (TextUtils.isEmpty(html)) { return html; } @@ -1364,7 +1190,7 @@ public Pattern getTripIdCleanupPattern(@NonNull Context context) { private boolean stopIdCleanupPatternSet = false; @Nullable - private Pattern getStopIdCleanupPattern(@NonNull Context context) { + public Pattern getStopIdCleanupPattern(@NonNull Context context) { if (this.stopIdCleanupPattern == null && !stopIdCleanupPatternSet) { this.stopIdCleanupPattern = GTFSCommons.makeIdCleanupPattern(getSTOP_ID_CLEANUP_REGEX(context)); this.stopIdCleanupPatternSet = true; @@ -1372,51 +1198,6 @@ private Pattern getStopIdCleanupPattern(@NonNull Context context) { return this.stopIdCleanupPattern; } - @Nullable - private String parseProviderTargetUUID(@NonNull Context context, String agencyTag, @NonNull GtfsRealtime.EntitySelector gEntitySelector, boolean ignoreDirection) { - if (gEntitySelector.hasRouteId()) { - if (gEntitySelector.hasDirectionId() && !ignoreDirection) { - if (gEntitySelector.hasStopId()) { - return getAgencyRouteDirectionStopTagTargetUUID(agencyTag, - GtfsRealtimeExt.getRouteIdHash(gEntitySelector, getRouteIdCleanupPattern(context)), - gEntitySelector.getDirectionId(), - GtfsRealtimeExt.getStopIdHash(gEntitySelector, getStopIdCleanupPattern(context)) - ); - } else { // no stop - return getAgencyRouteDirectionTagTargetUUID(agencyTag, - GtfsRealtimeExt.getRouteIdHash(gEntitySelector, getRouteIdCleanupPattern(context)), - gEntitySelector.getDirectionId() - ); - } - } else { // no direction - if (gEntitySelector.hasStopId()) { - return getAgencyRouteStopTagTargetUUID(agencyTag, - GtfsRealtimeExt.getRouteIdHash(gEntitySelector, getRouteIdCleanupPattern(context)), - GtfsRealtimeExt.getStopIdHash(gEntitySelector, getStopIdCleanupPattern(context))); - } - } - return getAgencyRouteTagTargetUUID(agencyTag, - GtfsRealtimeExt.getRouteIdHash(gEntitySelector, getRouteIdCleanupPattern(context))); - } else if (gEntitySelector.hasStopId()) { - return getAgencyStopTagTargetUUID(agencyTag, - GtfsRealtimeExt.getStopIdHash(gEntitySelector, getStopIdCleanupPattern(context))); - } else if (gEntitySelector.hasRouteType()) { - return getAgencyRouteTypeTagTargetUUID(agencyTag, - gEntitySelector.getRouteType()); - } else if (gEntitySelector.hasAgencyId()) { - return getAgencyTagTargetUUID(agencyTag); - } else if (gEntitySelector.hasTrip()) { - final String tripIdHash = GtfsRealtimeExt.getTripIdHash(gEntitySelector, getTripIdCleanupPattern(context)); - MTLog.w(this, "parseTargetUUID() > unsupported TRIP entity selector: %s (%s) (IGNORED)", - GtfsRealtimeExt.toStringExt(gEntitySelector.getTrip()), - tripIdHash - ); - return null; - } - MTLog.w(this, "parseTargetUUID() > unexpected entity selector: %s (IGNORED)", GtfsRealtimeExt.toStringExt(gEntitySelector)); - return null; - } - @NonNull private String parseLanguage(@Nullable String gLanguage) { if (gLanguage == null || gLanguage.isEmpty()) { @@ -1656,15 +1437,17 @@ public String getLogTag() { static final String T_GTFS_REAL_TIME_VEHICLE_LOCATION = VehicleLocationDbHelper.T_VEHICLE_LOCATION; - private static final String T_GTFS_REAL_TIME_VEHICLE_LOCATION_SQL_CREATE = VehicleLocationDbHelper.getSqlCreateBuilder( - T_GTFS_REAL_TIME_VEHICLE_LOCATION).build(); + private static final String T_GTFS_REAL_TIME_VEHICLE_LOCATION_SQL_CREATE = VehicleLocationDbHelper + .getSqlCreateBuilder(T_GTFS_REAL_TIME_VEHICLE_LOCATION) + .build(); private static final String T_GTFS_REAL_TIME_VEHICLE_LOCATION_SQL_DROP = SqlUtils.getSQLDropIfExistsQuery(T_GTFS_REAL_TIME_VEHICLE_LOCATION); - static final String T_GTFS_REAL_TIME_SERVICE_UPDATE = ServiceUpdateProvider.ServiceUpdateDbHelper.T_SERVICE_UPDATE; + static final String T_GTFS_REAL_TIME_SERVICE_UPDATE = ServiceUpdateDbHelper.T_SERVICE_UPDATE; - private static final String T_GTFS_REAL_TIME_SERVICE_UPDATE_SQL_CREATE = ServiceUpdateProvider.ServiceUpdateDbHelper.getSqlCreateBuilder( - T_GTFS_REAL_TIME_SERVICE_UPDATE).build(); + private static final String T_GTFS_REAL_TIME_SERVICE_UPDATE_SQL_CREATE = ServiceUpdateDbHelper + .getSqlCreateBuilder(T_GTFS_REAL_TIME_SERVICE_UPDATE) + .build(); private static final String T_GTFS_REAL_TIME_SERVICE_UPDATE_SQL_DROP = SqlUtils.getSQLDropIfExistsQuery(T_GTFS_REAL_TIME_SERVICE_UPDATE); @@ -1680,6 +1463,7 @@ public static int getDbVersion(@NonNull Context context) { dbVersion++; // add "vehicle_location" table dbVersion++; // add "vehicle_location.report_timestamp" column dbVersion++; // change "vehicle_location.[bearing|speed] unit to Int + dbVersion++; // add "service_update.trip_id" column } return dbVersion; } diff --git a/src/main/java/org/mtransit/android/commons/provider/NextBusProvider.java b/src/main/java/org/mtransit/android/commons/provider/NextBusProvider.java index 20d8dea2..4b512c99 100644 --- a/src/main/java/org/mtransit/android/commons/provider/NextBusProvider.java +++ b/src/main/java/org/mtransit/android/commons/provider/NextBusProvider.java @@ -42,8 +42,10 @@ import org.mtransit.android.commons.provider.nextbus.NextBusStorage; import org.mtransit.android.commons.provider.nextbus.api.NextBusApi; import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateCleaner; +import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateDbHelper; import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateProvider; import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateProviderContract; +import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateProviderExtKt; import org.mtransit.android.commons.provider.status.StatusProvider; import org.mtransit.android.commons.provider.status.StatusProviderContract; import org.mtransit.android.commons.provider.vehiclelocations.NextBusVehicleLocationsProvider; @@ -603,13 +605,13 @@ public String getServiceUpdateDbTableName() { } @Override - public void cacheServiceUpdates(@NonNull ArrayList newServiceUpdates) { + public void cacheServiceUpdates(@NonNull List newServiceUpdates) { ServiceUpdateProvider.cacheServiceUpdatesS(this, newServiceUpdates); } @Nullable @Override - public ArrayList getCachedServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { + public List getCachedServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { final Context context = requireContextCompat(); if ((serviceUpdateFilter.getPoi() instanceof RouteDirectionStop)) { return getCachedServiceUpdates(context, (RouteDirectionStop) serviceUpdateFilter.getPoi()); @@ -623,18 +625,18 @@ public ArrayList getCachedServiceUpdates(@NonNull ServiceUpdatePr } } - private ArrayList getCachedServiceUpdates(@NonNull Context context, @NonNull RouteDirectionStop rds) { + private List getCachedServiceUpdates(@NonNull Context context, @NonNull RouteDirectionStop rds) { final Map targetUUIDs = getServiceUpdateTargetUUIDs(context, rds); - ArrayList cachedServiceUpdates = ServiceUpdateProvider.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); + List cachedServiceUpdates = ServiceUpdateProviderExtKt.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); enhanceRDServiceUpdateForStop(cachedServiceUpdates, targetUUIDs); return cachedServiceUpdates; } - private ArrayList getCachedServiceUpdates(@NonNull Context context, @NonNull RouteDirection rd) { + private List getCachedServiceUpdates(@NonNull Context context, @NonNull RouteDirection rd) { final Map targetUUIDs = getServiceUpdateTargetUUIDs(context, rd); - ArrayList cachedServiceUpdates = ServiceUpdateProvider.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); + List cachedServiceUpdates = ServiceUpdateProviderExtKt.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); enhanceRDServiceUpdateForStop(cachedServiceUpdates, targetUUIDs); - // if (org.mtransit.commons.Constants.DEBUG) { + // if (org.mtransit.android.commons.Constants.DEBUG) { // MTLog.d(this, "getCachedServiceUpdates(%s) > %s", rd.getUUID(), cachedServiceUpdates == null ? null : cachedServiceUpdates.size()); // if (cachedServiceUpdates != null) { // for (ServiceUpdate serviceUpdate : cachedServiceUpdates) { @@ -645,11 +647,11 @@ private ArrayList getCachedServiceUpdates(@NonNull Context contex return cachedServiceUpdates; } - private ArrayList getCachedServiceUpdates(@NonNull Context context, @NonNull Route route) { + private List getCachedServiceUpdates(@NonNull Context context, @NonNull Route route) { final Map targetUUIDs = getServiceUpdateTargetUUIDs(context, route); - ArrayList cachedServiceUpdates = ServiceUpdateProvider.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); + List cachedServiceUpdates = ServiceUpdateProviderExtKt.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); enhanceRDServiceUpdateForStop(cachedServiceUpdates, targetUUIDs); - // if (org.mtransit.commons.Constants.DEBUG) { + // if (org.mtransit.android.commons.Constants.DEBUG) { // MTLog.d(this, "getCachedServiceUpdates(%s) > %s", route.getUUID(), cachedServiceUpdates == null ? null : cachedServiceUpdates.size()); // if (cachedServiceUpdates != null) { // for (ServiceUpdate serviceUpdate : cachedServiceUpdates) { @@ -660,7 +662,7 @@ private ArrayList getCachedServiceUpdates(@NonNull Context contex return cachedServiceUpdates; } - private void enhanceRDServiceUpdateForStop(@Nullable ArrayList serviceUpdates, + private void enhanceRDServiceUpdateForStop(@Nullable List serviceUpdates, @NonNull Map targetUUIDs // different UUID from provider target UUID ) { try { @@ -817,7 +819,7 @@ public boolean deleteCachedServiceUpdate(@NonNull String targetUUID, @NonNull St @Nullable @Override - public ArrayList getNewServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { + public List getNewServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { final Context context = requireContextCompat(); if ((serviceUpdateFilter.getPoi() instanceof RouteDirectionStop)) { return getNewServiceUpdates(context, (RouteDirectionStop) serviceUpdateFilter.getPoi(), serviceUpdateFilter.isInFocusOrDefault()); @@ -831,9 +833,9 @@ public ArrayList getNewServiceUpdates(@NonNull ServiceUpdateProvi } } - private ArrayList getNewServiceUpdates(@NonNull Context context, @NonNull RouteDirectionStop rds, boolean inFocus) { + private List getNewServiceUpdates(@NonNull Context context, @NonNull RouteDirectionStop rds, boolean inFocus) { updateAgencyServiceUpdateDataIfRequired(requireContextCompat(), inFocus); - ArrayList cachedServiceUpdates = getCachedServiceUpdates(context, rds); + List cachedServiceUpdates = getCachedServiceUpdates(context, rds); if (CollectionUtils.getSize(cachedServiceUpdates) == 0) { cachedServiceUpdates = makeServiceUpdateNoneList(this, rds, AGENCY_SOURCE_ID); enhanceRDServiceUpdateForStop(cachedServiceUpdates, Collections.emptyMap()); @@ -841,9 +843,9 @@ private ArrayList getNewServiceUpdates(@NonNull Context context, return cachedServiceUpdates; } - private ArrayList getNewServiceUpdates(@NonNull Context context, @NonNull RouteDirection rd, boolean inFocus) { + private List getNewServiceUpdates(@NonNull Context context, @NonNull RouteDirection rd, boolean inFocus) { updateAgencyServiceUpdateDataIfRequired(requireContextCompat(), inFocus); - ArrayList cachedServiceUpdates = getCachedServiceUpdates(context, rd); + List cachedServiceUpdates = getCachedServiceUpdates(context, rd); if (CollectionUtils.getSize(cachedServiceUpdates) == 0) { cachedServiceUpdates = makeServiceUpdateNoneList(this, rd, AGENCY_SOURCE_ID); enhanceRDServiceUpdateForStop(cachedServiceUpdates, Collections.emptyMap()); @@ -851,9 +853,9 @@ private ArrayList getNewServiceUpdates(@NonNull Context context, return cachedServiceUpdates; } - private ArrayList getNewServiceUpdates(@NonNull Context context, @NonNull Route route, boolean inFocus) { + private List getNewServiceUpdates(@NonNull Context context, @NonNull Route route, boolean inFocus) { updateAgencyServiceUpdateDataIfRequired(requireContextCompat(), inFocus); - ArrayList cachedServiceUpdates = getCachedServiceUpdates(context, route); + List cachedServiceUpdates = getCachedServiceUpdates(context, route); if (CollectionUtils.getSize(cachedServiceUpdates) == 0) { cachedServiceUpdates = makeServiceUpdateNoneList(this, route, AGENCY_SOURCE_ID); enhanceRDServiceUpdateForStop(cachedServiceUpdates, Collections.emptyMap()); @@ -895,7 +897,7 @@ private void updateAllAgencyServiceUpdateDataFromWWW(@NonNull Context context, b deleteAllAgencyServiceUpdateData(); deleteAllDone = true; } - ArrayList newServiceUpdates = loadAgencyServiceUpdateDataFromWWW(context); + List newServiceUpdates = loadAgencyServiceUpdateDataFromWWW(context); if (newServiceUpdates != null) { // empty is OK long nowInMs = TimeUtils.currentTimeMillis(); if (!deleteAllDone) { @@ -927,7 +929,7 @@ private static String getAgencyUrlString(@NonNull Context context) { } @Nullable - private ArrayList loadAgencyServiceUpdateDataFromWWW(@NonNull Context context) { + private List loadAgencyServiceUpdateDataFromWWW(@NonNull Context context) { try { final String urlString = getAgencyUrlString(context); MTLog.i(this, "Loading from '%s'...", urlString); @@ -953,7 +955,7 @@ private ArrayList loadAgencyServiceUpdateDataFromWWW(@NonNull Con ); xr.setContentHandler(handler); xr.parse(new InputSource(response.body().byteStream())); - final ArrayList serviceUpdates = handler.getServiceUpdates(); + final List serviceUpdates = handler.getServiceUpdates(); MTLog.i(this, "Found %d service updates.", serviceUpdates.size()); return serviceUpdates; default: @@ -1610,7 +1612,7 @@ public String getLogTag() { private final long serviceUpdateMaxValidityInMs; @NonNull - private final ArrayList serviceUpdates = new ArrayList<>(); + private final List serviceUpdates = new ArrayList<>(); private final String agencyTag; @@ -1672,7 +1674,7 @@ public String getLogTag() { } @NonNull - ArrayList getServiceUpdates() { + List getServiceUpdates() { return this.serviceUpdates; } @@ -1869,6 +1871,7 @@ private void addServiceUpdates(@NonNull String targetUUID, int severity, @Nullab && !textMessageIdTargetUUIDCurrentMessageUUIDs.contains(targetUUID)) { this.serviceUpdates.add(new ServiceUpdate(null, targetUUID, + null, this.newLastUpdateInMs, this.serviceUpdateMaxValidityInMs, ServiceUpdateCleaner.makeText(title, this.currentTextSb.toString()), @@ -1895,6 +1898,7 @@ private void addServiceUpdates(@NonNull String targetUUID, int severity, @Nullab && !textSecondaryMessageIdTargetUUIDMessageUUIDs.contains(targetUUID)) { this.serviceUpdates.add(new ServiceUpdate(null, targetUUID, + null, this.newLastUpdateInMs, this.serviceUpdateMaxValidityInMs, ServiceUpdateCleaner.makeText(title, this.currentTextSecondaryLanguageSb.toString()), @@ -1966,9 +1970,9 @@ public String getLogTag() { private static final String T_NEXT_BUS_VEHICLE_LOCATION_SQL_DROP = SqlUtils.getSQLDropIfExistsQuery(T_NEXT_BUS_VEHICLE_LOCATION); - static final String T_NEXT_BUS_SERVICE_UPDATE = ServiceUpdateProvider.ServiceUpdateDbHelper.T_SERVICE_UPDATE; + static final String T_NEXT_BUS_SERVICE_UPDATE = ServiceUpdateDbHelper.T_SERVICE_UPDATE; - private static final String T_NEXT_BUS_SERVICE_UPDATE_SQL_CREATE = ServiceUpdateProvider.ServiceUpdateDbHelper.getSqlCreateBuilder( + private static final String T_NEXT_BUS_SERVICE_UPDATE_SQL_CREATE = ServiceUpdateDbHelper.getSqlCreateBuilder( T_NEXT_BUS_SERVICE_UPDATE).build(); private static final String T_NEXT_BUS_SERVICE_UPDATE_SQL_DROP = SqlUtils.getSQLDropIfExistsQuery(T_NEXT_BUS_SERVICE_UPDATE); @@ -1989,6 +1993,7 @@ public static int getDbVersion(@NonNull Context context) { dbVersion = context.getResources().getInteger(R.integer.next_bus_db_version); dbVersion++; // add "service_update.original_id" column dbVersion++; // add "vehicle_location" table + dbVersion++; // add "service_update.trip_id" column } return dbVersion; } diff --git a/src/main/java/org/mtransit/android/commons/provider/OCTranspoProvider.java b/src/main/java/org/mtransit/android/commons/provider/OCTranspoProvider.java index 9e469081..9af6ab37 100644 --- a/src/main/java/org/mtransit/android/commons/provider/OCTranspoProvider.java +++ b/src/main/java/org/mtransit/android/commons/provider/OCTranspoProvider.java @@ -50,8 +50,10 @@ import org.mtransit.android.commons.provider.common.MTContentProvider; import org.mtransit.android.commons.provider.common.MTSQLiteOpenHelper; import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateCleaner; +import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateDbHelper; import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateProvider; import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateProviderContract; +import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateProviderExtKt; import org.mtransit.android.commons.provider.status.StatusProvider; import org.mtransit.android.commons.provider.status.StatusProviderContract; import org.mtransit.commons.CleanUtils; @@ -396,7 +398,7 @@ protected Collection parseAgencyJSONArrivalsResults(@NonNull Context @NonNull RouteDirectionStop rds, @Nullable String sourceLabel, long lastUpdateInMs, - String localeTimeZoneId) { + @NonNull String localeTimeZoneId) { try { ArrayList result = new ArrayList<>(); final String tripHeading = rds.getDirection().getHeading(context); @@ -567,13 +569,13 @@ public String getServiceUpdateDbTableName() { } @Override - public void cacheServiceUpdates(@NonNull ArrayList newServiceUpdates) { + public void cacheServiceUpdates(@NonNull List newServiceUpdates) { ServiceUpdateProvider.cacheServiceUpdatesS(this, newServiceUpdates); } @Nullable @Override - public ArrayList getCachedServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { + public List getCachedServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { if ((serviceUpdateFilter.getPoi() instanceof RouteDirectionStop)) { return getCachedServiceUpdates((RouteDirectionStop) serviceUpdateFilter.getPoi()); } else if ((serviceUpdateFilter.getRouteDirection() != null)) { @@ -586,28 +588,28 @@ public ArrayList getCachedServiceUpdates(@NonNull ServiceUpdatePr } } - private ArrayList getCachedServiceUpdates(@NonNull RouteDirectionStop rds) { + private List getCachedServiceUpdates(@NonNull RouteDirectionStop rds) { final Map targetUUIDs = getTargetUUIDs(rds); - ArrayList serviceUpdates = ServiceUpdateProvider.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); + List serviceUpdates = ServiceUpdateProviderExtKt.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); enhanceRDServiceUpdateForStop(serviceUpdates, rds.getStop(), targetUUIDs); return serviceUpdates; } - private ArrayList getCachedServiceUpdates(@NonNull RouteDirection rd) { + private List getCachedServiceUpdates(@NonNull RouteDirection rd) { final Map targetUUIDs = getTargetUUIDs(rd); - ArrayList serviceUpdates = ServiceUpdateProvider.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); + List serviceUpdates = ServiceUpdateProviderExtKt.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); enhanceRDServiceUpdateForStop(serviceUpdates, null, targetUUIDs); return serviceUpdates; } - private ArrayList getCachedServiceUpdates(@NonNull Route route) { + private List getCachedServiceUpdates(@NonNull Route route) { final Map targetUUIDs = getTargetUUIDs(route); - ArrayList serviceUpdates = ServiceUpdateProvider.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); + List serviceUpdates = ServiceUpdateProviderExtKt.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); enhanceRDServiceUpdateForStop(serviceUpdates, null, targetUUIDs); return serviceUpdates; } - private void enhanceRDServiceUpdateForStop(ArrayList serviceUpdates, + private void enhanceRDServiceUpdateForStop(List serviceUpdates, @Nullable Stop stop, @NonNull Map targetUUIDs // route trip service update targets stop ) { @@ -705,7 +707,7 @@ private int deleteAllAgencyServiceUpdateData() { @Nullable @Override - public ArrayList getNewServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { + public List getNewServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { if ((serviceUpdateFilter.getPoi() instanceof RouteDirectionStop)) { return getNewServiceUpdates((RouteDirectionStop) serviceUpdateFilter.getPoi(), serviceUpdateFilter.isInFocusOrDefault()); } else if ((serviceUpdateFilter.getRouteDirection() != null)) { @@ -718,9 +720,9 @@ public ArrayList getNewServiceUpdates(@NonNull ServiceUpdateProvi } } - private ArrayList getNewServiceUpdates(@NonNull RouteDirectionStop rds, boolean inFocus) { + private List getNewServiceUpdates(@NonNull RouteDirectionStop rds, boolean inFocus) { updateAgencyServiceUpdateDataIfRequired(requireContextCompat(), rds.getAuthority(), inFocus); - ArrayList cachedServiceUpdates = getCachedServiceUpdates(rds); + List cachedServiceUpdates = getCachedServiceUpdates(rds); if (CollectionUtils.getSize(cachedServiceUpdates) == 0) { cachedServiceUpdates = makeServiceUpdateNoneList(this, rds, AGENCY_SOURCE_ID); enhanceRDServiceUpdateForStop(cachedServiceUpdates, rds.getStop(), Collections.emptyMap()); @@ -728,9 +730,9 @@ private ArrayList getNewServiceUpdates(@NonNull RouteDirectionSto return cachedServiceUpdates; } - private ArrayList getNewServiceUpdates(@NonNull RouteDirection rd, boolean inFocus) { + private List getNewServiceUpdates(@NonNull RouteDirection rd, boolean inFocus) { updateAgencyServiceUpdateDataIfRequired(requireContextCompat(), rd.getAuthority(), inFocus); - ArrayList cachedServiceUpdates = getCachedServiceUpdates(rd); + List cachedServiceUpdates = getCachedServiceUpdates(rd); if (CollectionUtils.getSize(cachedServiceUpdates) == 0) { cachedServiceUpdates = makeServiceUpdateNoneList(this, rd, AGENCY_SOURCE_ID); enhanceRDServiceUpdateForStop(cachedServiceUpdates, null, Collections.emptyMap()); @@ -738,9 +740,9 @@ private ArrayList getNewServiceUpdates(@NonNull RouteDirection rd return cachedServiceUpdates; } - private ArrayList getNewServiceUpdates(@NonNull Route route, boolean inFocus) { + private List getNewServiceUpdates(@NonNull Route route, boolean inFocus) { updateAgencyServiceUpdateDataIfRequired(requireContextCompat(), route.getAuthority(), inFocus); - ArrayList cachedServiceUpdates = getCachedServiceUpdates(route); + List cachedServiceUpdates = getCachedServiceUpdates(route); if (CollectionUtils.getSize(cachedServiceUpdates) == 0) { cachedServiceUpdates = makeServiceUpdateNoneList(this, route, AGENCY_SOURCE_ID); enhanceRDServiceUpdateForStop(cachedServiceUpdates, null, Collections.emptyMap()); @@ -788,7 +790,7 @@ private void updateAllAgencyServiceUpdateDataFromWWW(@NonNull Context context, S deleteAllAgencyServiceUpdateData(); deleteAllDone = true; } - ArrayList newServiceUpdates = loadAgencyServiceUpdateDataFromWWW(context, targetAuthority); + List newServiceUpdates = loadAgencyServiceUpdateDataFromWWW(context, targetAuthority); if (newServiceUpdates != null) { // empty is OK long nowInMs = TimeUtils.currentTimeMillis(); if (!deleteAllDone) { @@ -812,7 +814,7 @@ private static String getAgencyUrlString(@NonNull String language) { ; } - private ArrayList loadAgencyServiceUpdateDataFromWWW(@NonNull Context context, @SuppressWarnings("unused") String targetAuthority) { + private List loadAgencyServiceUpdateDataFromWWW(@NonNull Context context, @SuppressWarnings("unused") String targetAuthority) { try { final String language = LocaleUtils.isFR() ? Locale.FRENCH.getLanguage() : Locale.ENGLISH.getLanguage(); final String urlString = getAgencyUrlString(language); @@ -841,7 +843,7 @@ private ArrayList loadAgencyServiceUpdateDataFromWWW(@NonNull Con ); xr.setContentHandler(handler); xr.parse(new InputSource(response.body().byteStream())); - final ArrayList newServiceUpdates = handler.getServiceUpdates(); + final List newServiceUpdates = handler.getServiceUpdates(); MTLog.i(this, "Found %d service updates.", newServiceUpdates.size()); if (Constants.DEBUG) { for (ServiceUpdate serviceUpdate : newServiceUpdates) { @@ -922,6 +924,12 @@ public UriMatcher getURI_MATCHER() { return getURIMATCHER(requireContextCompat()); } + @NonNull + @Override + public String getAuthority() { + return getAUTHORITY(requireContextCompat()); + } + @NonNull @Override public Uri getAuthorityUri() { @@ -1024,7 +1032,7 @@ public String getLogTag() { private final StringBuilder currentDescriptionSb = new StringBuilder(); @NonNull - private final ArrayList serviceUpdates = new ArrayList<>(); + private final List serviceUpdates = new ArrayList<>(); private final URL fromURL; private final String targetAuthority; @@ -1049,7 +1057,7 @@ public String getLogTag() { } @NonNull - ArrayList getServiceUpdates() { + List getServiceUpdates() { return this.serviceUpdates; } @@ -1147,6 +1155,7 @@ public void endElement(String uri, String localName, String qName) throws SAXExc this.serviceUpdates.add( new ServiceUpdate(null, OCTranspoProvider.getAgencyTargetUUID(this.targetAuthority), + null, this.newLastUpdateInMs, this.serviceUpdateMaxValidityInMs, text, @@ -1160,6 +1169,7 @@ public void endElement(String uri, String localName, String qName) throws SAXExc for (String routeShortName : routeShortNames) { this.serviceUpdates.add(new ServiceUpdate(null, OCTranspoProvider.getAgencyRouteShortNameTargetUUID(this.targetAuthority, routeShortName), + null, this.newLastUpdateInMs, this.serviceUpdateMaxValidityInMs, text, @@ -1496,10 +1506,10 @@ public String getLogTag() { private static final String T_LIVE_NEXT_BUS_ARRIVAL_DATA_FEED_STATUS_SQL_DROP = // SqlUtils.getSQLDropIfExistsQuery(T_LIVE_NEXT_BUS_ARRIVAL_DATA_FEED_STATUS); - static final String T_OC_TRANSPO_SERVICE_UPDATE = ServiceUpdateProvider.ServiceUpdateDbHelper.T_SERVICE_UPDATE; + static final String T_OC_TRANSPO_SERVICE_UPDATE = ServiceUpdateDbHelper.T_SERVICE_UPDATE; private static final String T_OC_TRANSPO_SERVICE_UPDATE_SQL_CREATE = // - ServiceUpdateProvider.ServiceUpdateDbHelper.getSqlCreateBuilder(T_OC_TRANSPO_SERVICE_UPDATE).build(); + ServiceUpdateDbHelper.getSqlCreateBuilder(T_OC_TRANSPO_SERVICE_UPDATE).build(); private static final String T_OC_TRANSPO_SERVICE_UPDATE_SQL_DROP = SqlUtils.getSQLDropIfExistsQuery(T_OC_TRANSPO_SERVICE_UPDATE); @@ -1512,6 +1522,7 @@ public static int getDbVersion(@NonNull Context context) { if (dbVersion < 0) { dbVersion = context.getResources().getInteger(R.integer.oc_transpo_db_version); dbVersion++; // add "service_update.original_id" column + dbVersion++; // add "service_update.trip_id" column } return dbVersion; } diff --git a/src/main/java/org/mtransit/android/commons/provider/RTCQuebecProvider.java b/src/main/java/org/mtransit/android/commons/provider/RTCQuebecProvider.java index 93e4b608..d21fd0e2 100644 --- a/src/main/java/org/mtransit/android/commons/provider/RTCQuebecProvider.java +++ b/src/main/java/org/mtransit/android/commons/provider/RTCQuebecProvider.java @@ -44,8 +44,10 @@ import org.mtransit.android.commons.provider.common.MTSQLiteOpenHelper; import org.mtransit.android.commons.provider.news.NewsTextFormatter; import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateCleaner; +import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateDbHelper; import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateProvider; import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateProviderContract; +import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateProviderExtKt; import org.mtransit.android.commons.provider.status.StatusProvider; import org.mtransit.android.commons.provider.status.StatusProviderContract; import org.mtransit.commons.Cleaner; @@ -232,7 +234,7 @@ public int getStatusType() { } @Override - public void cacheServiceUpdates(@NonNull ArrayList newServiceUpdates) { + public void cacheServiceUpdates(@NonNull List newServiceUpdates) { ServiceUpdateProvider.cacheServiceUpdatesS(this, newServiceUpdates); } @@ -243,7 +245,7 @@ public void cacheStatus(@NonNull POIStatus newStatusToCache) { @Nullable @Override - public ArrayList getCachedServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { + public List getCachedServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { if ((serviceUpdateFilter.getPoi() instanceof RouteDirectionStop)) { return getCachedServiceUpdates((RouteDirectionStop) serviceUpdateFilter.getPoi()); } else if ((serviceUpdateFilter.getRouteDirection() != null)) { @@ -257,30 +259,30 @@ public ArrayList getCachedServiceUpdates(@NonNull ServiceUpdatePr } @Nullable - private ArrayList getCachedServiceUpdates(@NonNull RouteDirectionStop rds) { + private List getCachedServiceUpdates(@NonNull RouteDirectionStop rds) { final Map targetUUIDs = getServiceUpdateTargetUUID(rds); - ArrayList serviceUpdates = ServiceUpdateProvider.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); + List serviceUpdates = ServiceUpdateProviderExtKt.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); enhanceServiceUpdate(serviceUpdates, rds.getRoute(), rds.getStop(), targetUUIDs); return serviceUpdates; } @Nullable - private ArrayList getCachedServiceUpdates(@NonNull RouteDirection rd) { + private List getCachedServiceUpdates(@NonNull RouteDirection rd) { final Map targetUUIDs = getServiceUpdateTargetUUID(rd); - ArrayList serviceUpdates = ServiceUpdateProvider.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); + List serviceUpdates = ServiceUpdateProviderExtKt.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); enhanceServiceUpdate(serviceUpdates, rd.getRoute(), null, targetUUIDs); return serviceUpdates; } @Nullable - private ArrayList getCachedServiceUpdates(@NonNull Route route) { + private List getCachedServiceUpdates(@NonNull Route route) { final Map targetUUIDs = getServiceUpdateTargetUUID(route); - ArrayList serviceUpdates = ServiceUpdateProvider.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); + List serviceUpdates = ServiceUpdateProviderExtKt.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); enhanceServiceUpdate(serviceUpdates, route, null, targetUUIDs); return serviceUpdates; } - private void enhanceServiceUpdate(ArrayList serviceUpdates, + private void enhanceServiceUpdate(List serviceUpdates, @Nullable Route route, @Nullable Stop stop, @NonNull Map targetUUIDs // different UUID from provider target UUID @@ -552,7 +554,7 @@ private int deleteAllAgencyServiceUpdateData() { @Nullable @Override - public ArrayList getNewServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { + public List getNewServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { if ((serviceUpdateFilter.getPoi() instanceof RouteDirectionStop)) { return getNewServiceUpdates((RouteDirectionStop) serviceUpdateFilter.getPoi(), serviceUpdateFilter.isInFocusOrDefault()); } else if ((serviceUpdateFilter.getRouteDirection() != null)) { @@ -566,21 +568,21 @@ public ArrayList getNewServiceUpdates(@NonNull ServiceUpdateProvi } @Nullable - private ArrayList getNewServiceUpdates(@NonNull RouteDirectionStop rds, boolean inFocus) { + private List getNewServiceUpdates(@NonNull RouteDirectionStop rds, boolean inFocus) { //noinspection deprecation // TODO fix & re-enable updateAgencyServiceUpdateDataIfRequired(requireContextCompat(), inFocus); return getCachedServiceUpdates(rds); } @Nullable - private ArrayList getNewServiceUpdates(@NonNull RouteDirection routeDirection, boolean inFocus) { + private List getNewServiceUpdates(@NonNull RouteDirection routeDirection, boolean inFocus) { //noinspection deprecation // TODO fix & re-enable updateAgencyServiceUpdateDataIfRequired(requireContextCompat(), inFocus); return getCachedServiceUpdates(routeDirection); } @Nullable - private ArrayList getNewServiceUpdates(@NonNull Route route, boolean inFocus) { + private List getNewServiceUpdates(@NonNull Route route, boolean inFocus) { //noinspection deprecation // TODO fix & re-enable updateAgencyServiceUpdateDataIfRequired(requireContextCompat(), inFocus); return getCachedServiceUpdates(route); @@ -628,7 +630,7 @@ private void updateAllAgencyServiceUpdateDataFromWWW(@NonNull Context context, b deleteAllAgencyServiceUpdateData(); deleteAllDone = true; } - ArrayList newServiceUpdates = loadAgencyServiceUpdateDataFromWWW(context); + List newServiceUpdates = loadAgencyServiceUpdateDataFromWWW(context); if (newServiceUpdates != null) { // empty is OK long nowInMs = TimeUtils.currentTimeMillis(); if (!deleteAllDone) { @@ -661,7 +663,7 @@ private OkHttpClient getOkHttpClient(@NonNull Context context) { @Deprecated @Nullable - private ArrayList loadAgencyServiceUpdateDataFromWWW(@NonNull Context context) { + private List loadAgencyServiceUpdateDataFromWWW(@NonNull Context context) { try { String urlString = AGENCY_URL; MTLog.i(this, "Loading from '%s'...", urlString); @@ -1038,6 +1040,12 @@ public UriMatcher getURI_MATCHER() { return getURIMATCHER(requireContextCompat()); } + @NonNull + @Override + public String getAuthority() { + return getAUTHORITY(requireContextCompat()); + } + @NonNull @Override public Uri getAuthorityUri() { @@ -1143,7 +1151,7 @@ public String getLogTag() { private final StringBuilder currentContentSb = new StringBuilder(); private final StringBuilder currentGUIDSb = new StringBuilder(); - private final ArrayList serviceUpdates = new ArrayList<>(); + private final List serviceUpdates = new ArrayList<>(); private final String targetAuthority; @NonNull @@ -1158,7 +1166,7 @@ public String getLogTag() { this.serviceUpdateMaxValidityInMs = serviceUpdateMaxValidityInMs; } - ArrayList getServiceUpdates() { + List getServiceUpdates() { return this.serviceUpdates; } @@ -1281,6 +1289,7 @@ public void endElement(String uri, String localName, String qName) throws SAXExc ServiceUpdate serviceUpdate = new ServiceUpdate( id, targetUUID, + null, this.newLastUpdateInMs, this.serviceUpdateMaxValidityInMs, textSb.toString(), @@ -1495,9 +1504,9 @@ public String getLogTag() { */ static final String PREF_KEY_AGENCY_SERVICE_UPDATE_LAST_UPDATE_MS = "pRTCQuebecServiceUpdatesLastUpdate"; - static final String T_RTC_SERVICE_UPDATE = ServiceUpdateProvider.ServiceUpdateDbHelper.T_SERVICE_UPDATE; + static final String T_RTC_SERVICE_UPDATE = ServiceUpdateDbHelper.T_SERVICE_UPDATE; - private static final String T_RTC_SERVICE_UPDATE_SQL_CREATE = ServiceUpdateProvider.ServiceUpdateDbHelper.getSqlCreateBuilder(T_RTC_SERVICE_UPDATE) + private static final String T_RTC_SERVICE_UPDATE_SQL_CREATE = ServiceUpdateDbHelper.getSqlCreateBuilder(T_RTC_SERVICE_UPDATE) .build(); private static final String T_RTC_SERVICE_UPDATE_SQL_DROP = SqlUtils.getSQLDropIfExistsQuery(T_RTC_SERVICE_UPDATE); @@ -1517,6 +1526,7 @@ static int getDbVersion(@NonNull Context context) { if (dbVersion < 0) { dbVersion = context.getResources().getInteger(R.integer.rtc_quebec_db_version); dbVersion++; // add "service_update.original_id" column + dbVersion++; // add "service_update.trip_id" column } return dbVersion; } diff --git a/src/main/java/org/mtransit/android/commons/provider/StmInfoApiProvider.java b/src/main/java/org/mtransit/android/commons/provider/StmInfoApiProvider.java index f4c041b1..cd3440d6 100644 --- a/src/main/java/org/mtransit/android/commons/provider/StmInfoApiProvider.java +++ b/src/main/java/org/mtransit/android/commons/provider/StmInfoApiProvider.java @@ -54,8 +54,10 @@ import org.mtransit.android.commons.provider.common.MTSQLiteOpenHelper; import org.mtransit.android.commons.provider.gtfs.GTFSRDSProvider; import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateCleaner; +import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateDbHelper; import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateProvider; import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateProviderContract; +import org.mtransit.android.commons.provider.serviceupdate.ServiceUpdateProviderExtKt; import org.mtransit.android.commons.provider.status.StatusProvider; import org.mtransit.android.commons.provider.status.StatusProviderContract; import org.mtransit.commons.Cleaner; @@ -221,7 +223,7 @@ public void cacheStatus(@NonNull POIStatus newStatusToCache) { } @Override - public void cacheServiceUpdates(@Nullable ArrayList newServiceUpdates) { + public void cacheServiceUpdates(@Nullable List newServiceUpdates) { ServiceUpdateProvider.cacheServiceUpdatesS(this, newServiceUpdates); } @@ -255,7 +257,7 @@ public POIStatus getCachedStatus(@NonNull StatusProviderContract.Filter statusFi @Nullable @Override - public ArrayList getCachedServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { + public List getCachedServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { final Context context = requireContextCompat(); if ((serviceUpdateFilter.getPoi() instanceof RouteDirectionStop)) { return getCachedServiceUpdates(context, (RouteDirectionStop) serviceUpdateFilter.getPoi()); @@ -270,18 +272,18 @@ public ArrayList getCachedServiceUpdates(@NonNull ServiceUpdatePr } @NonNull - private ArrayList getCachedServiceUpdates(@NonNull Context context, @NonNull RouteDirectionStop rds) { + private List getCachedServiceUpdates(@NonNull Context context, @NonNull RouteDirectionStop rds) { if (STORE_EMPTY_SERVICE_MESSAGE) { - final ArrayList stopOnlyUpdates = ServiceUpdateProvider.getCachedServiceUpdatesS(this, getStopServiceUpdateTargetUUID(context, rds)); + final List stopOnlyUpdates = ServiceUpdateProviderExtKt.getCachedServiceUpdatesS(this, getStopServiceUpdateTargetUUID(context, rds)); if (stopOnlyUpdates == null || stopOnlyUpdates.isEmpty()) { return new ArrayList<>(); // need to get NEW service update from WWW for this STOP } } - final ArrayList cachedServiceUpdates = new ArrayList<>(); + final List cachedServiceUpdates = new ArrayList<>(); final Map targetUUIDs = getProviderTargetUUIDs(context, rds); - CollectionUtils.addAllN(cachedServiceUpdates, ServiceUpdateProvider.getCachedServiceUpdatesS(this, targetUUIDs.keySet())); + CollectionUtils.addAllN(cachedServiceUpdates, ServiceUpdateProviderExtKt.getCachedServiceUpdatesS(this, targetUUIDs.keySet())); enhanceRDServiceUpdatesForStop(context, cachedServiceUpdates, targetUUIDs, rds.getStop(), rds.getUUID()); - // if (org.mtransit.commons.Constants.DEBUG) { + // if (org.mtransit.android.commons.Constants.DEBUG) { // MTLog.d(this, "getCachedServiceUpdates() > %s service updates for %s.", cachedServiceUpdates.size(), rds.getUUID()); // for (ServiceUpdate serviceUpdate : cachedServiceUpdates) { // MTLog.d(this, "getCachedServiceUpdates() > - %s", serviceUpdate); @@ -291,15 +293,15 @@ private ArrayList getCachedServiceUpdates(@NonNull Context contex } @NonNull - private ArrayList getCachedServiceUpdates(@NonNull Context context, @NonNull RouteDirection rd) { - final ArrayList cachedServiceUpdates = new ArrayList<>(); + private List getCachedServiceUpdates(@NonNull Context context, @NonNull RouteDirection rd) { + final List cachedServiceUpdates = new ArrayList<>(); final Map targetUUIDs = getProviderTargetUUIDs(context, rd); - final ArrayList routeCachedServiceUpdatesS = ServiceUpdateProvider.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); + final List routeCachedServiceUpdatesS = ServiceUpdateProviderExtKt.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); if (routeCachedServiceUpdatesS != null) { cachedServiceUpdates.addAll(routeCachedServiceUpdatesS); } enhanceRDServiceUpdatesForStop(context, cachedServiceUpdates, targetUUIDs, null, null); - // if (org.mtransit.commons.Constants.DEBUG) { + // if (org.mtransit.android.commons.Constants.DEBUG) { // MTLog.d(this, "getCachedServiceUpdates() > %s service updates for %s.", cachedServiceUpdates.size(), rd.getUUID()); // for (ServiceUpdate serviceUpdate : cachedServiceUpdates) { // MTLog.d(this, "getCachedServiceUpdates() > - %s", serviceUpdate); @@ -309,7 +311,7 @@ private ArrayList getCachedServiceUpdates(@NonNull Context contex } private void enhanceRDServiceUpdatesForStop(@NonNull Context context, - ArrayList serviceUpdates, + List serviceUpdates, Map targetUUIDs, // different UUID from provider target UUID @Nullable Stop stop, @Nullable String stopTargetUUID @@ -564,7 +566,7 @@ public POIStatus getNewStatus(@NonNull StatusProviderContract.Filter statusFilte @Nullable @Override - public ArrayList getNewServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { + public List getNewServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { final Context context = requireContextCompat(); if ((serviceUpdateFilter.getPoi() instanceof RouteDirectionStop)) { return getNewServiceUpdates(context, (RouteDirectionStop) serviceUpdateFilter.getPoi()); @@ -579,7 +581,7 @@ public ArrayList getNewServiceUpdates(@NonNull ServiceUpdateProvi } @Nullable - private ArrayList getNewServiceUpdates(@NonNull Context context, @NonNull RouteDirectionStop rds) { + private List getNewServiceUpdates(@NonNull Context context, @NonNull RouteDirectionStop rds) { if (rds.getDirection().getHeadsignValue().isEmpty() || rds.getRoute().getShortName().isEmpty()) { MTLog.d(this, "getNewServiceUpdates() > skip (stop w/o code OR route w/o short name: %s)", rds); @@ -592,7 +594,7 @@ private ArrayList getNewServiceUpdates(@NonNull Context context, @SuppressWarnings("SameReturnValue") @Nullable - private ArrayList getNewServiceUpdates(@SuppressWarnings("unused") @NonNull Context context, @NonNull RouteDirection rd) { + private List getNewServiceUpdates(@SuppressWarnings("unused") @NonNull Context context, @NonNull RouteDirection rd) { if (rd.getDirection().getHeadsignValue().isEmpty() || rd.getRoute().getShortName().isEmpty()) { MTLog.d(this, "getNewServiceUpdates() > skip (stop w/o code OR route w/o short name: %s)", rd); @@ -690,7 +692,7 @@ private void loadRealTimeStatusFromWWW(@NonNull Context context, } } if (hasServiceUpdateFilter && STORE_EMPTY_SERVICE_MESSAGE) { // IF loading service update AND storing empty service update - final ArrayList cachedStopServiceUpdates = ServiceUpdateProvider.getCachedServiceUpdatesS(this, getStopServiceUpdateTargetUUID(context, rds)); + final List cachedStopServiceUpdates = ServiceUpdateProviderExtKt.getCachedServiceUpdatesS(this, getStopServiceUpdateTargetUUID(context, rds)); if (cachedStopServiceUpdates != null && !cachedStopServiceUpdates.isEmpty()) { // DO check service update MTLog.d(this, "loadRealTimeStatusFromWWW() > SKIP (service update already in cache for %s)", uuid); return; @@ -732,14 +734,14 @@ private void loadRealTimeStatusFromWWW(@NonNull Context context, @NonNull RouteD } } MTLog.i(this, "Found %d schedule statuses for '%s'.", (statuses == null ? 0 : statuses.size()), rds.toStringShort()); - // if (org.mtransit.commons.Constants.DEBUG) { + // if (org.mtransit.android.commons.Constants.DEBUG) { // if (statuses != null) { // for (POIStatus status : statuses) { // MTLog.d(this, "- %s", status.toString()); // } // } // } - final ArrayList serviceUpdates = parseAgencyJSONArrivalsServiceUpdates( + final List serviceUpdates = parseAgencyJSONArrivalsServiceUpdates( context, jArrivals.getMessages(), rds, @@ -748,7 +750,7 @@ private void loadRealTimeStatusFromWWW(@NonNull Context context, @NonNull RouteD newLastUpdateInMs ); MTLog.i(this, "Found %d service updates for '%s'.", serviceUpdates == null ? null : serviceUpdates.size(), rds.toStringShort()); - // if (org.mtransit.commons.Constants.DEBUG) { + // if (org.mtransit.android.commons.Constants.DEBUG) { // if (serviceUpdates != null) { // for (ServiceUpdate serviceUpdate : serviceUpdates) { // MTLog.d(this, "- %s", serviceUpdate.toString()); @@ -776,15 +778,17 @@ private void loadRealTimeStatusFromWWW(@NonNull Context context, @NonNull RouteD } @Nullable - private ArrayList parseAgencyJSONArrivalsServiceUpdates(@NonNull Context context, - @NonNull JArrivals.JMessages jMessages, - @NonNull RouteDirectionStop rds, - @NonNull String sourceLabel, - @NonNull String language, - long newLastUpdateInMs) { + private List parseAgencyJSONArrivalsServiceUpdates( + @NonNull Context context, + @NonNull JArrivals.JMessages jMessages, + @NonNull RouteDirectionStop rds, + @NonNull String sourceLabel, + @NonNull String language, + long newLastUpdateInMs + ) { try { final long maxValidityInMs = getServiceUpdateMaxValidityInMs(); - final ArrayList serviceUpdates = new ArrayList<>(); + final List serviceUpdates = new ArrayList<>(); final String rdTargetUUID = getRouteDirectionServiceUpdateTargetUUID(context, rds.getRoute(), rds.getDirection()); final String rdsTargetUUID = getStopServiceUpdateTargetUUID(context, rds); int rdsServiceUpdateAdded = 0; @@ -799,6 +803,7 @@ private ArrayList parseAgencyJSONArrivalsServiceUpdates(@NonNull serviceUpdates.add(new ServiceUpdate( null, rdTargetUUID, + null, newLastUpdateInMs, maxValidityInMs, ServiceUpdateCleaner.makeText( @@ -829,6 +834,7 @@ private ArrayList parseAgencyJSONArrivalsServiceUpdates(@NonNull serviceUpdates.add(new ServiceUpdate( null, rdsTargetUUID, + null, newLastUpdateInMs, maxValidityInMs, ServiceUpdateCleaner.makeText( @@ -920,7 +926,7 @@ private void loadRealTimeServiceUpdateFromWWW(@NonNull Context context, RouteDir MTLog.d(this, "loadRealTimeServiceUpdateFromWWW() > jsonString: %s.", jsonString); JMessages jMessages = parseAgencyJSONMessages(jsonString); List jResults = jMessages.getResults(); - ArrayList serviceUpdates = parseAgencyJSONMessageResults( + List serviceUpdates = parseAgencyJSONMessageResults( jResults, rds, sourceLabel, language, newLastUpdateInMs); MTLog.i(this, "Found %d service updates.", serviceUpdates == null ? null : serviceUpdates.size()); @@ -944,7 +950,7 @@ private void loadRealTimeServiceUpdateFromWWW(@NonNull Context context, RouteDir } } - private synchronized void deleteOldAndCacheNewServiceUpdates(ArrayList serviceUpdates) { // SYNC because may have multiple concurrent same route call + private synchronized void deleteOldAndCacheNewServiceUpdates(List serviceUpdates) { // SYNC because may have multiple concurrent same route call if (serviceUpdates != null) { for (ServiceUpdate serviceUpdate : serviceUpdates) { deleteCachedServiceUpdate(serviceUpdate.getTargetUUID(), SERVICE_UPDATE_SOURCE_ID); @@ -995,13 +1001,15 @@ private JMessages parseAgencyJSONMessages(String jsonString) { @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated @Nullable - protected ArrayList parseAgencyJSONMessageResults(@NonNull List jResults, - @NonNull RouteDirectionStop rds, - @NonNull String sourceLabel, - @NonNull String language, - long newLastUpdateInMs) { + protected List parseAgencyJSONMessageResults( + @NonNull List jResults, + @NonNull RouteDirectionStop rds, + @NonNull String sourceLabel, + @NonNull String language, + long newLastUpdateInMs + ) { try { - ArrayList serviceUpdates = new ArrayList<>(); + List serviceUpdates = new ArrayList<>(); long maxValidityInMs = getServiceUpdateMaxValidityInMs(); int index = 0; for (JMessages.JResult jResult : jResults) { @@ -1048,6 +1056,7 @@ protected ArrayList parseAgencyJSONMessageResults(@NonNull List newServiceUpdates) { + public void cacheServiceUpdates(@NonNull List newServiceUpdates) { ServiceUpdateProvider.cacheServiceUpdatesS(this, newServiceUpdates); } @Nullable @Override - public ArrayList getCachedServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { + public List getCachedServiceUpdates(@NonNull Filter serviceUpdateFilter) { if ((serviceUpdateFilter.getPoi() instanceof RouteDirectionStop)) { return getCachedServiceUpdates((RouteDirectionStop) serviceUpdateFilter.getPoi()); } else if ((serviceUpdateFilter.getRouteDirection() != null)) { @@ -199,25 +202,25 @@ public ArrayList getCachedServiceUpdates(@NonNull ServiceUpdatePr } @Nullable - private ArrayList getCachedServiceUpdates(@NonNull RouteDirectionStop rds) { + private List getCachedServiceUpdates(@NonNull RouteDirectionStop rds) { final Map targetUUIDs = getAgencyTargetUUID(rds); - ArrayList routeDirectionServiceUpdates = ServiceUpdateProvider.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); + List routeDirectionServiceUpdates = ServiceUpdateProviderExtKt.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); enhanceRDServiceUpdateForStop(routeDirectionServiceUpdates, rds.getRoute(), targetUUIDs); return routeDirectionServiceUpdates; } @Nullable - private ArrayList getCachedServiceUpdates(@NonNull RouteDirection rd) { + private List getCachedServiceUpdates(@NonNull RouteDirection rd) { final Map targetUUIDs = getAgencyTargetUUID(rd); - ArrayList routeDirectionServiceUpdates = ServiceUpdateProvider.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); + List routeDirectionServiceUpdates = ServiceUpdateProviderExtKt.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); enhanceRDServiceUpdateForStop(routeDirectionServiceUpdates, rd.getRoute(), targetUUIDs); return routeDirectionServiceUpdates; } @Nullable - private ArrayList getCachedServiceUpdates(@NonNull Route route) { + private List getCachedServiceUpdates(@NonNull Route route) { final Map targetUUIDs = getAgencyTargetUUID(route); - ArrayList routeDirectionServiceUpdates = ServiceUpdateProvider.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); + List routeDirectionServiceUpdates = ServiceUpdateProviderExtKt.getCachedServiceUpdatesS(this, targetUUIDs.keySet()); enhanceRDServiceUpdateForStop(routeDirectionServiceUpdates, route, targetUUIDs); return routeDirectionServiceUpdates; } @@ -310,7 +313,7 @@ private int deleteAllAgencyServiceUpdateData() { @Nullable @Override - public ArrayList getNewServiceUpdates(@NonNull ServiceUpdateProviderContract.Filter serviceUpdateFilter) { + public List getNewServiceUpdates(@NonNull Filter serviceUpdateFilter) { if ((serviceUpdateFilter.getPoi() instanceof RouteDirectionStop)) { return getNewServiceUpdates((RouteDirectionStop) serviceUpdateFilter.getPoi(), serviceUpdateFilter.isInFocusOrDefault()); } else if ((serviceUpdateFilter.getRouteDirection() != null)) { @@ -324,9 +327,9 @@ public ArrayList getNewServiceUpdates(@NonNull ServiceUpdateProvi } @Nullable - private ArrayList getNewServiceUpdates(@NonNull RouteDirectionStop rds, boolean inFocus) { + private List getNewServiceUpdates(@NonNull RouteDirectionStop rds, boolean inFocus) { updateAgencyServiceUpdateDataIfRequired(requireContextCompat(), rds.getAuthority(), inFocus); - ArrayList cachedServiceUpdates = getCachedServiceUpdates(rds); + List cachedServiceUpdates = getCachedServiceUpdates(rds); if (CollectionUtils.getSize(cachedServiceUpdates) == 0) { cachedServiceUpdates = makeServiceUpdateNoneList(this, rds, AGENCY_SOURCE_ID); enhanceRDServiceUpdateForStop(cachedServiceUpdates, rds.getRoute(), Collections.emptyMap()); // convert to stop service update @@ -335,9 +338,9 @@ private ArrayList getNewServiceUpdates(@NonNull RouteDirectionSto } @Nullable - private ArrayList getNewServiceUpdates(@NonNull RouteDirection rd, boolean inFocus) { + private List getNewServiceUpdates(@NonNull RouteDirection rd, boolean inFocus) { updateAgencyServiceUpdateDataIfRequired(requireContextCompat(), rd.getAuthority(), inFocus); - ArrayList cachedServiceUpdates = getCachedServiceUpdates(rd); + List cachedServiceUpdates = getCachedServiceUpdates(rd); if (CollectionUtils.getSize(cachedServiceUpdates) == 0) { cachedServiceUpdates = makeServiceUpdateNoneList(this, rd, AGENCY_SOURCE_ID); enhanceRDServiceUpdateForStop(cachedServiceUpdates, rd.getRoute(), Collections.emptyMap()); // convert to stop service update @@ -346,9 +349,9 @@ private ArrayList getNewServiceUpdates(@NonNull RouteDirection rd } @Nullable - private ArrayList getNewServiceUpdates(@NonNull Route route, boolean inFocus) { + private List getNewServiceUpdates(@NonNull Route route, boolean inFocus) { updateAgencyServiceUpdateDataIfRequired(requireContextCompat(), route.getAuthority(), inFocus); - ArrayList cachedServiceUpdates = getCachedServiceUpdates(route); + List cachedServiceUpdates = getCachedServiceUpdates(route); if (CollectionUtils.getSize(cachedServiceUpdates) == 0) { cachedServiceUpdates = makeServiceUpdateNoneList(this, route, AGENCY_SOURCE_ID); enhanceRDServiceUpdateForStop(cachedServiceUpdates, route, Collections.emptyMap()); // convert to stop service update @@ -396,7 +399,7 @@ private void updateAllAgencyServiceUpdateDataFromWWW(@NonNull Context context, S deleteAllAgencyServiceUpdateData(); deleteAllDone = true; } - ArrayList newServiceUpdates = loadAgencyServiceUpdateDataFromWWW(context, targetAuthority); + List newServiceUpdates = loadAgencyServiceUpdateDataFromWWW(context, targetAuthority); if (newServiceUpdates != null) { // empty is OK long nowInMs = TimeUtils.currentTimeMillis(); if (!deleteAllDone) { @@ -418,7 +421,7 @@ private OkHttpClient getOkHttpClient(@NonNull Context context) { } @Nullable - private ArrayList loadAgencyServiceUpdateDataFromWWW(@NonNull Context context, String targetAuthority) { + private List loadAgencyServiceUpdateDataFromWWW(@NonNull Context context, String targetAuthority) { try { final String language = LocaleUtils.isFR() ? Locale.FRENCH.getLanguage() : Locale.ENGLISH.getLanguage(); final String urlString = getAgencyUrlString(language); @@ -461,9 +464,9 @@ private ArrayList loadAgencyServiceUpdateDataFromWWW(@NonNull Con private static final String JSON_METRO = "metro"; @Nullable - private ArrayList parseAgencyJson(String jsonString, @NonNull String sourceLabel, @NonNull String language, long nowInMs, String targetAuthority) { + private List parseAgencyJson(String jsonString, @NonNull String sourceLabel, @NonNull String language, long nowInMs, String targetAuthority) { try { - ArrayList result = new ArrayList<>(); + List result = new ArrayList<>(); JSONObject json = jsonString == null ? null : new JSONObject(jsonString); if (json != null && json.has(JSON_METRO)) { JSONObject jMetro = json.getJSONObject(JSON_METRO); @@ -510,6 +513,7 @@ private ServiceUpdate parseAgencyJsonText(JSONObject jMetroObject, String target final String textHtml = enhanceHtml(jMetroDataText, null, severity); return new ServiceUpdate(null, targetUUID, + null, nowInMs, maxValidityInMs, jMetroDataText, @@ -815,6 +819,12 @@ public UriMatcher getURI_MATCHER() { return getURI_MATCHER(requireContextCompat()); } + @NonNull + @Override + public String getAuthority() { + return getAUTHORITY(requireContextCompat()); + } + @NonNull @Override public Uri getAuthorityUri() { @@ -877,7 +887,7 @@ public Uri insertMT(@NonNull Uri uri, @Nullable ContentValues values) { return null; } - public static class StmInfoSubwayDbHelper extends ServiceUpdateProvider.ServiceUpdateDbHelper { + public static class StmInfoSubwayDbHelper extends ServiceUpdateDbHelper { private static final String LOG_TAG = StmInfoSubwayDbHelper.class.getSimpleName(); @@ -897,9 +907,9 @@ public String getLogTag() { */ static final String PREF_KEY_AGENCY_LAST_UPDATE_MS = "pStmInfoSubwayEtatsDuServiceLastUpdate"; - static final String T_STM_INFO_SERVICE_UPDATE = ServiceUpdateProvider.ServiceUpdateDbHelper.T_SERVICE_UPDATE; + static final String T_STM_INFO_SERVICE_UPDATE = ServiceUpdateDbHelper.T_SERVICE_UPDATE; - private static final String T_STM_INFO_SERVICE_UPDATE_SQL_CREATE = ServiceUpdateProvider.ServiceUpdateDbHelper.getSqlCreateBuilder( + private static final String T_STM_INFO_SERVICE_UPDATE_SQL_CREATE = ServiceUpdateDbHelper.getSqlCreateBuilder( T_STM_INFO_SERVICE_UPDATE).build(); private static final String T_STM_INFO_SERVICE_UPDATE_SQL_DROP = SqlUtils.getSQLDropIfExistsQuery(T_STM_INFO_SERVICE_UPDATE); @@ -913,6 +923,7 @@ public static int getDbVersion(@NonNull Context context) { if (dbVersion < 0) { dbVersion = context.getResources().getInteger(R.integer.stm_info_db_version); dbVersion++; // add "service_update.original_id" column + dbVersion++; // add "service_update.trip_id" column } return dbVersion; } diff --git a/src/main/java/org/mtransit/android/commons/provider/gtfs/GTFSRDSProvider.java b/src/main/java/org/mtransit/android/commons/provider/gtfs/GTFSRDSProvider.java index 05356b97..c5e21a8c 100644 --- a/src/main/java/org/mtransit/android/commons/provider/gtfs/GTFSRDSProvider.java +++ b/src/main/java/org/mtransit/android/commons/provider/gtfs/GTFSRDSProvider.java @@ -405,7 +405,7 @@ public static Map> findTripRouteAndDirectionIds(@NonNul private static final String ROUTE_DIRECTION_STOP_SORT_ORDER = SqlUtils.mergeSortOrder(ROUTE_SORT_ORDER, DIRECTION_SORT_ORDER, STOP_SORT_ORDER); private static final String ROUTE_DIRECTION_SORT_ORDER = SqlUtils.mergeSortOrder(ROUTE_SORT_ORDER, DIRECTION_SORT_ORDER); private static final String DIRECTION_STOP_SORT_ORDER = SqlUtils.mergeSortOrder(DIRECTION_SORT_ORDER, STOP_SORT_ORDER); - private static final String TRIP_SORT_ORDER = SqlUtils.getSortOrderAscending(SqlUtils.getTableColumn(GTFSProviderDbHelper.T_TRIP, GTFSProviderDbHelper.T_TRIP_K_TRIP_ID_OR_INT)); + public static final String TRIP_SORT_ORDER = SqlUtils.getSortOrderAscending(SqlUtils.getTableColumn(GTFSProviderDbHelper.T_TRIP, GTFSProviderDbHelper.T_TRIP_K_TRIP_ID_OR_INT)); @Nullable public static String getSortOrderS(@NonNull GTFSProvider provider, @NonNull Uri uri) { diff --git a/src/main/java/org/mtransit/android/commons/provider/gtfs/GTFSRDSProviderExt.kt b/src/main/java/org/mtransit/android/commons/provider/gtfs/GTFSRDSProviderExt.kt new file mode 100644 index 00000000..767a62eb --- /dev/null +++ b/src/main/java/org/mtransit/android/commons/provider/gtfs/GTFSRDSProviderExt.kt @@ -0,0 +1,53 @@ +package org.mtransit.android.commons.provider.gtfs + +import android.content.Context +import android.net.Uri +import org.mtransit.android.commons.MTLog +import org.mtransit.android.commons.SqlUtils +import org.mtransit.android.commons.UriUtils +import org.mtransit.android.commons.data.Trip +import org.mtransit.android.commons.provider.GTFSProviderContract + +fun Context.getTripIds(authority: String, routeId: Long, directionId: Long? = null) = + getTrips(authority, routeId, directionId)?.map { it.tripId } + +fun Context.getTrips( + authority: String, + routeId: Long, + directionId: Long? = null, +): List? = try { + contentResolver.query( + Uri.withAppendedPath( + UriUtils.newContentUri(authority), + GTFSProviderContract.TRIP_PATH + ), + GTFSProviderContract.PROJECTION_TRIP, + buildString { + append( + SqlUtils.getWhereEquals( + GTFSProviderContract.TripColumns.T_TRIP_K_ROUTE_ID, + routeId + ) + ) + directionId?.let { + append(SqlUtils.AND) + append(SqlUtils.getWhereEquals(GTFSProviderContract.TripColumns.T_TRIP_K_DIRECTION_ID, it)) + } + }, + null, + GTFSRDSProvider.TRIP_SORT_ORDER, + ).use { cursor -> + buildList { + if (cursor != null && cursor.count > 0) { + if (cursor.moveToFirst()) { + do { + add(Trip.fromCursor(cursor)) + } while (cursor.moveToNext()) + } + } + } + } +} catch (e: Exception) { + MTLog.w(this, e, "Error!") + null +} diff --git a/src/main/java/org/mtransit/android/commons/provider/gtfs/GTFSRealTimeProviderExt.kt b/src/main/java/org/mtransit/android/commons/provider/gtfs/GTFSRealTimeProviderExt.kt index dd5f78f0..3bfd38b0 100644 --- a/src/main/java/org/mtransit/android/commons/provider/gtfs/GTFSRealTimeProviderExt.kt +++ b/src/main/java/org/mtransit/android/commons/provider/gtfs/GTFSRealTimeProviderExt.kt @@ -3,21 +3,91 @@ package org.mtransit.android.commons.provider.gtfs import android.content.Context import okhttp3.Request import org.mtransit.android.commons.MTLog +import org.mtransit.android.commons.data.Direction +import org.mtransit.android.commons.data.Route +import org.mtransit.android.commons.data.RouteDirection +import org.mtransit.android.commons.data.RouteDirectionStop +import org.mtransit.android.commons.data.Stop import org.mtransit.android.commons.provider.GTFSRealTimeProvider +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.MT_HASH_SECRET_AND_DATE +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAGENCY_URL_HEADER_NAMES +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAGENCY_URL_HEADER_VALUES +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAGENCY_URL_TOKEN +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAgencyRouteDirectionStopTagTargetUUID +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAgencyRouteDirectionTagTargetUUID +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAgencyRouteStopTagTargetUUID +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAgencyRouteTagTargetUUID +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAgencyRouteTypeTagTargetUUID +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAgencyStopTagTargetUUID +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAgencyTagTargetUUID +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.isUSE_URL_HASH_SECRET_AND_DATE import java.net.URL +val GTFSRealTimeProvider.routeIdCleanupPattern get() = getRouteIdCleanupPattern(requireContextCompat()) +val GTFSRealTimeProvider.tripIdCleanupPattern get() = getTripIdCleanupPattern(requireContextCompat()) +val GTFSRealTimeProvider.stopIdCleanupPattern get() = getStopIdCleanupPattern(requireContextCompat()) + +val GTFSRealTimeProvider.agencyTag get() = getAgencyTag(requireContextCompat()) + +fun Stop.getStopTag(provider: GTFSRealTimeProvider) = provider.getStopTag(this) + +fun Route.getRouteTypeTag(provider: GTFSRealTimeProvider) = provider.getRouteTypeTag(this) +fun Route.getRouteTag(provider: GTFSRealTimeProvider) = provider.getRouteTag(this) +fun Direction.getDirectionTag(provider: GTFSRealTimeProvider) = provider.getDirectionTag(this) + +fun RouteDirection.getRouteTypeTag(provider: GTFSRealTimeProvider) = this.route.getRouteTypeTag(provider) +fun RouteDirection.getRouteTag(provider: GTFSRealTimeProvider) = this.route.getRouteTag(provider) +fun RouteDirection.getDirectionTag(provider: GTFSRealTimeProvider) = this.direction.getDirectionTag(provider) + +fun RouteDirectionStop.getRouteTypeTag(provider: GTFSRealTimeProvider) = this.route.getRouteTypeTag(provider) ?: this.dataSourceTypeId +fun RouteDirectionStop.getRouteTag(provider: GTFSRealTimeProvider) = this.route.getRouteTag(provider) +fun RouteDirectionStop.getDirectionTag(provider: GTFSRealTimeProvider) = this.direction.getDirectionTag(provider) +fun RouteDirectionStop.getStopTag(provider: GTFSRealTimeProvider) = this.stop.getStopTag(provider) + +fun RouteDirectionStop.getTargetUUIDs( + provider: GTFSRealTimeProvider, + includeAgencyTag: Boolean = false, + includeRouteType: Boolean = false, + includeStopTags: Boolean = false +) = buildMap { + if (includeAgencyTag) put(getAgencyTagTargetUUID(provider.agencyTag), authority) + if (includeRouteType) getAgencyRouteTypeTagTargetUUID(provider.agencyTag, getRouteTypeTag(provider))?.let { put(it, authority) } + put(getAgencyRouteTagTargetUUID(provider.agencyTag, getRouteTag(provider)), route.uuid) + getAgencyRouteDirectionTagTargetUUID(provider.agencyTag, getRouteTag(provider), getDirectionTag(provider))?.let { put(it, routeDirectionUUID) } + if (includeStopTags) { + getAgencyRouteDirectionStopTagTargetUUID(provider.agencyTag, getRouteTag(provider), getDirectionTag(provider), getStopTag(provider))?.let { + put(it, uuid) + } + put(getAgencyStopTagTargetUUID(provider.agencyTag, getStopTag(provider)), uuid) + put(getAgencyRouteStopTagTargetUUID(provider.agencyTag, getRouteTag(provider), getStopTag(provider)), uuid) + } +} + +fun RouteDirection.getTargetUUIDs(provider: GTFSRealTimeProvider, includeAgencyTag: Boolean = false, includeRouteType: Boolean = false) = buildMap { + if (includeAgencyTag) put(getAgencyTagTargetUUID(provider.agencyTag), authority) + if (includeRouteType) getAgencyRouteTypeTagTargetUUID(provider.agencyTag, getRouteTypeTag(provider))?.let { put(it, authority) } + put(getAgencyRouteTagTargetUUID(provider.agencyTag, getRouteTag(provider)), route.uuid) + getAgencyRouteDirectionTagTargetUUID(provider.agencyTag, getRouteTag(provider), getDirectionTag(provider))?.let { put(it, uuid) } +} + +fun Route.getTargetUUIDs(provider: GTFSRealTimeProvider, includeAgencyTag: Boolean = false, includeRouteType: Boolean = false) = buildMap { + if (includeAgencyTag) put(getAgencyTagTargetUUID(provider.agencyTag), authority) + if (includeRouteType) getAgencyRouteTypeTagTargetUUID(provider.agencyTag, getRouteTypeTag(provider))?.let { put(it, authority) } + put(getAgencyRouteTagTargetUUID(provider.agencyTag, getRouteTag(provider)), uuid) +} + fun GTFSRealTimeProvider.makeRequest(context: Context, urlCachedString: String = "", getUrlString: (token: String) -> String): Request? { if (urlCachedString.isNotBlank()) { MTLog.i(this, "Loading from cached API (length: %d) '***'...", urlCachedString.length) return Request.Builder().url(URL(urlCachedString)).build() } - val token = GTFSRealTimeProvider.getAGENCY_URL_TOKEN(context) // use local token 1st for new/updated API URL & tokens + val token = getAGENCY_URL_TOKEN(context) // use local token 1st for new/updated API URL & tokens .takeIf { it.isNotBlank() } ?: this.providedAgencyUrlToken ?: "" // compat w/ API w/o token var urlString = getUrlString(token) - if (GTFSRealTimeProvider.isUSE_URL_HASH_SECRET_AND_DATE(context)) { + if (isUSE_URL_HASH_SECRET_AND_DATE(context)) { getHashSecretAndDate(context)?.let { hash -> - urlString = urlString.replace(GTFSRealTimeProvider.MT_HASH_SECRET_AND_DATE.toRegex(), hash.trim()) + urlString = urlString.replace(MT_HASH_SECRET_AND_DATE.toRegex(), hash.trim()) } } if (urlString.isBlank()) { @@ -30,8 +100,8 @@ fun GTFSRealTimeProvider.makeRequest(context: Context, urlCachedString: String = return Request.Builder() .url(url) .apply { - val agencyUrlHeaderNames = GTFSRealTimeProvider.getAGENCY_URL_HEADER_NAMES(context) - val agencyUrlHeaderValues = GTFSRealTimeProvider.getAGENCY_URL_HEADER_VALUES(context) + val agencyUrlHeaderNames = getAGENCY_URL_HEADER_NAMES(context) + val agencyUrlHeaderValues = getAGENCY_URL_HEADER_VALUES(context) if (agencyUrlHeaderNames.size != agencyUrlHeaderValues.size) return@apply for (i in agencyUrlHeaderNames.indices) { addHeader(agencyUrlHeaderNames[i], agencyUrlHeaderValues[i]) diff --git a/src/main/java/org/mtransit/android/commons/provider/gtfs/GtfsRealtimeExt.kt b/src/main/java/org/mtransit/android/commons/provider/gtfs/GtfsRealtimeExt.kt index 4d562b43..99ac21bb 100644 --- a/src/main/java/org/mtransit/android/commons/provider/gtfs/GtfsRealtimeExt.kt +++ b/src/main/java/org/mtransit/android/commons/provider/gtfs/GtfsRealtimeExt.kt @@ -250,6 +250,13 @@ object GtfsRealtimeExt { append("}") } + val GtfsRealtime.EntitySelector.optAgencyId get() = if (hasAgencyId()) agencyId else null + val GtfsRealtime.EntitySelector.optRouteId get() = if (hasRouteId()) routeId else this.optTrip?.optRouteId + val GtfsRealtime.EntitySelector.optDirectionId get() = if (hasDirectionId()) directionId else this.optTrip?.optDirectionId + val GtfsRealtime.EntitySelector.optStopId get() = if (hasStopId()) stopId else null + val GtfsRealtime.EntitySelector.optRouteType get() = if (hasRouteType()) routeType else null + val GtfsRealtime.EntitySelector.optTrip get() = if (hasTrip()) this.trip else null + @JvmStatic @JvmOverloads fun GtfsRealtime.TripDescriptor.toStringExt(short: Boolean = false) = buildString { @@ -266,6 +273,8 @@ object GtfsRealtimeExt { } val GtfsRealtime.TripDescriptor.optTripId get() = if (hasTripId()) tripId else null + val GtfsRealtime.TripDescriptor.optRouteId get() = if (hasRouteId()) routeId else null + val GtfsRealtime.TripDescriptor.optDirectionId get() = if (hasDirectionId()) directionId else null @JvmStatic @JvmOverloads diff --git a/src/main/java/org/mtransit/android/commons/provider/serviceupdate/GTFSRealTimeServiceAlertsProvider.kt b/src/main/java/org/mtransit/android/commons/provider/serviceupdate/GTFSRealTimeServiceAlertsProvider.kt new file mode 100644 index 00000000..4bc71a73 --- /dev/null +++ b/src/main/java/org/mtransit/android/commons/provider/serviceupdate/GTFSRealTimeServiceAlertsProvider.kt @@ -0,0 +1,103 @@ +package org.mtransit.android.commons.provider.serviceupdate + +import com.google.transit.realtime.GtfsRealtime +import org.mtransit.android.commons.MTLog +import org.mtransit.android.commons.data.RouteDirectionStop +import org.mtransit.android.commons.data.ServiceUpdate +import org.mtransit.android.commons.data.makeServiceUpdateNoneList +import org.mtransit.android.commons.provider.GTFSRealTimeProvider +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.AGENCY_SOURCE_ID +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAgencyRouteDirectionStopTagTargetUUID +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAgencyRouteDirectionTagTargetUUID +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAgencyRouteStopTagTargetUUID +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAgencyRouteTagTargetUUID +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAgencyRouteTypeTagTargetUUID +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAgencyStopTagTargetUUID +import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAgencyTagTargetUUID +import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.optAgencyId +import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.optDirectionId +import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.optRouteId +import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.optRouteType +import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.optStopId +import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.optTrip +import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.optTripId +import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.originalIdToHash +import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.originalIdToId +import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.toStringExt +import org.mtransit.android.commons.provider.gtfs.agencyTag +import org.mtransit.android.commons.provider.gtfs.getTargetUUIDs +import org.mtransit.android.commons.provider.gtfs.getTripIds +import org.mtransit.android.commons.provider.gtfs.routeIdCleanupPattern +import org.mtransit.android.commons.provider.gtfs.stopIdCleanupPattern +import org.mtransit.android.commons.provider.gtfs.tripIdCleanupPattern + +object GTFSRealTimeServiceAlertsProvider { + + @JvmStatic + fun GTFSRealTimeProvider.getCached(filter: ServiceUpdateProviderContract.Filter) = + ((filter.poi as? RouteDirectionStop)?.getTargetUUIDs(this, includeAgencyTag = true, includeRouteType = true, includeStopTags = true) + ?: filter.routeDirection?.getTargetUUIDs(this, includeAgencyTag = true, includeRouteType = true) + ?: filter.route?.getTargetUUIDs(this, includeAgencyTag = true, includeRouteType = true)) + ?.let { targetUUIDs -> + val tripIds = filter.targetAuthority?.let { targetAuthority -> + filter.routeId?.let { routeId -> + context?.getTripIds(targetAuthority, routeId, filter.directionId) + } + } + targetUUIDs to tripIds // trip IDs not required for GTFS Alerts + }?.let { (targetUUIDs, tripIds) -> + getCached(targetUUIDs, tripIds) + } + + fun GTFSRealTimeProvider.getCached(targetUUIDs: Map, tripIds: List?) = buildList { + getCachedServiceUpdatesS(targetUUIDs.keys, tripIds)?.let { + addAll(it) + } + }.map { it.apply { targetUUID = targetUUIDs[it.targetUUID] ?: it.targetUUID } } + + @JvmStatic + fun GTFSRealTimeProvider.getNew(filter: ServiceUpdateProviderContract.Filter): List? { + updateAgencyServiceUpdateDataIfRequired(requireContextCompat(), filter.isInFocusOrDefault) + return getCached(filter) + ?: filter.target?.let { enhanceServiceUpdate(makeServiceUpdateNoneList(it, AGENCY_SOURCE_ID)) } + } + + @JvmStatic + fun GTFSRealTimeProvider.parseTargetTripId(gEntitySelector: GtfsRealtime.EntitySelector) = + gEntitySelector.optTrip?.optTripId?.originalIdToId(tripIdCleanupPattern) + + @JvmStatic + fun GTFSRealTimeProvider.parseProviderTargetUUID(gEntitySelector: GtfsRealtime.EntitySelector, ignoreDirection: Boolean): String? { + gEntitySelector.optRouteId?.originalIdToHash(routeIdCleanupPattern)?.let { routeId -> + gEntitySelector.optDirectionId?.takeIf { !ignoreDirection }?.let { directionId -> + gEntitySelector.optStopId?.originalIdToHash(stopIdCleanupPattern)?.let { stopId -> + return getAgencyRouteDirectionStopTagTargetUUID(agencyTag, routeId, directionId, stopId) + } // no stop + return getAgencyRouteDirectionTagTargetUUID(agencyTag, routeId, directionId) + } // no direction + gEntitySelector.optStopId?.originalIdToHash(stopIdCleanupPattern)?.let { stopId -> + return getAgencyRouteStopTagTargetUUID(agencyTag, routeId, stopId) + } + return getAgencyRouteTagTargetUUID(agencyTag, routeId) + } + gEntitySelector.optStopId?.originalIdToHash(stopIdCleanupPattern)?.let { stopId -> + return getAgencyStopTagTargetUUID(agencyTag, stopId) + } + gEntitySelector.optRouteType?.let { routeType -> + return getAgencyRouteTypeTagTargetUUID(agencyTag, routeType) + } + gEntitySelector.optAgencyId?.let { _ -> + return getAgencyTagTargetUUID(agencyTag) + } + MTLog.w(this, "parseTargetUUID() > unexpected entity selector: %s (IGNORED)", gEntitySelector.toStringExt()) + return null + } + + @JvmStatic + fun GTFSRealTimeProvider.enhanceServiceUpdate(cachedServiceUpdates: List?) = + cachedServiceUpdates?.map { serviceUpdate -> + serviceUpdate.apply { + setTextHTML(enhanceHtmlDateTime(requireContextCompat(), serviceUpdate.textHTML)) + } + } +} diff --git a/src/main/java/org/mtransit/android/commons/provider/serviceupdate/ServiceUpdateDbHelper.kt b/src/main/java/org/mtransit/android/commons/provider/serviceupdate/ServiceUpdateDbHelper.kt new file mode 100644 index 00000000..6cca551c --- /dev/null +++ b/src/main/java/org/mtransit/android/commons/provider/serviceupdate/ServiceUpdateDbHelper.kt @@ -0,0 +1,59 @@ +package org.mtransit.android.commons.provider.serviceupdate + +import android.content.Context +import android.database.sqlite.SQLiteDatabase +import android.provider.BaseColumns +import org.mtransit.android.commons.SqlUtils +import org.mtransit.android.commons.provider.common.MTSQLiteOpenHelper +import org.mtransit.commons.sql.SQLCreateBuilder + +abstract class ServiceUpdateDbHelper( + context: Context?, + name: String?, + factory: SQLiteDatabase.CursorFactory?, + dbVersion: Int, +) : MTSQLiteOpenHelper(context, name, factory, dbVersion) { + + companion object { + const val T_SERVICE_UPDATE = "service_update" + + const val T_SERVICE_UPDATE_K_ID: String = BaseColumns._ID + const val T_SERVICE_UPDATE_K_TARGET_UUID = "target" + const val T_SERVICE_UPDATE_K_TARGET_TRIP_ID = "trip_id" + const val T_SERVICE_UPDATE_K_LAST_UPDATE = "last_update" + const val T_SERVICE_UPDATE_K_MAX_VALIDITY_IN_MS = "max_validity" + const val T_SERVICE_UPDATE_K_SEVERITY = "severity" + const val T_SERVICE_UPDATE_K_TEXT = "text" + const val T_SERVICE_UPDATE_K_TEXT_HTML = "text_html" + const val T_SERVICE_UPDATE_K_LANGUAGE = "lang" + const val T_SERVICE_UPDATE_K_SOURCE_LABEL = "source_label" + const val T_SERVICE_UPDATE_K_ORIGINAL_ID = "original_id" + const val T_SERVICE_UPDATE_K_SOURCE_ID = "source_id" + + @Suppress("unused") + val T_SERVICE_UPDATE_SQL_CREATE = getSqlCreateBuilder(T_SERVICE_UPDATE).build() + + @Suppress("unused") + val T_SERVICE_UPDATE_SQL_DROP = SqlUtils.getSQLDropIfExistsQuery(T_SERVICE_UPDATE) + + @Suppress("unused") + fun getFkColumnName(columnName: String) = "fk_$columnName" + + @JvmStatic + fun getSqlCreateBuilder(table: String) = SQLCreateBuilder.getNew(table) + .appendColumn(T_SERVICE_UPDATE_K_ID, SqlUtils.INT_PK_AUTO) + .appendColumn(T_SERVICE_UPDATE_K_TARGET_UUID, SqlUtils.TXT) + .appendColumn(T_SERVICE_UPDATE_K_TARGET_TRIP_ID, SqlUtils.TXT) + .appendColumn(T_SERVICE_UPDATE_K_LAST_UPDATE, SqlUtils.INT) + .appendColumn(T_SERVICE_UPDATE_K_MAX_VALIDITY_IN_MS, SqlUtils.INT) + .appendColumn(T_SERVICE_UPDATE_K_SEVERITY, SqlUtils.INT) + .appendColumn(T_SERVICE_UPDATE_K_TEXT, SqlUtils.TXT) + .appendColumn(T_SERVICE_UPDATE_K_TEXT_HTML, SqlUtils.TXT) + .appendColumn(T_SERVICE_UPDATE_K_LANGUAGE, SqlUtils.TXT) + .appendColumn(T_SERVICE_UPDATE_K_ORIGINAL_ID, SqlUtils.TXT) + .appendColumn(T_SERVICE_UPDATE_K_SOURCE_LABEL, SqlUtils.TXT) + .appendColumn(T_SERVICE_UPDATE_K_SOURCE_ID, SqlUtils.TXT) + } + + abstract val dbName: String +} diff --git a/src/main/java/org/mtransit/android/commons/provider/serviceupdate/ServiceUpdateProvider.java b/src/main/java/org/mtransit/android/commons/provider/serviceupdate/ServiceUpdateProvider.java index 20024ba6..84118395 100644 --- a/src/main/java/org/mtransit/android/commons/provider/serviceupdate/ServiceUpdateProvider.java +++ b/src/main/java/org/mtransit/android/commons/provider/serviceupdate/ServiceUpdateProvider.java @@ -1,14 +1,10 @@ package org.mtransit.android.commons.provider.serviceupdate; -import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.MatrixCursor; import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteDatabase.CursorFactory; -import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; -import android.provider.BaseColumns; import android.text.TextUtils; import androidx.annotation.NonNull; @@ -22,13 +18,10 @@ import org.mtransit.android.commons.data.ServiceUpdate; import org.mtransit.android.commons.provider.common.ContentProviderConstants; import org.mtransit.android.commons.provider.common.MTContentProvider; -import org.mtransit.android.commons.provider.common.MTSQLiteOpenHelper; import org.mtransit.commons.CollectionUtils; -import org.mtransit.commons.sql.SQLCreateBuilder; -import java.util.ArrayList; -import java.util.Collection; import java.util.Iterator; +import java.util.List; public abstract class ServiceUpdateProvider extends MTContentProvider implements ServiceUpdateProviderContract { @@ -49,6 +42,7 @@ public static void append(@NonNull UriMatcher uriMatcher, @NonNull String author public static final ArrayMap SERVICE_UPDATE_PROJECTION_MAP = SqlUtils.ProjectionMapBuilder.getNew() .appendTableColumn(ServiceUpdateDbHelper.T_SERVICE_UPDATE, ServiceUpdateDbHelper.T_SERVICE_UPDATE_K_ID, ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_ID) // .appendTableColumn(ServiceUpdateDbHelper.T_SERVICE_UPDATE, ServiceUpdateDbHelper.T_SERVICE_UPDATE_K_TARGET_UUID, ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_TARGET_UUID) // + .appendTableColumn(ServiceUpdateDbHelper.T_SERVICE_UPDATE, ServiceUpdateDbHelper.T_SERVICE_UPDATE_K_TARGET_TRIP_ID, ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_TARGET_TRIP_ID) // .appendTableColumn(ServiceUpdateDbHelper.T_SERVICE_UPDATE, ServiceUpdateDbHelper.T_SERVICE_UPDATE_K_LAST_UPDATE, ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_LAST_UPDATE) // .appendTableColumn(ServiceUpdateDbHelper.T_SERVICE_UPDATE, ServiceUpdateDbHelper.T_SERVICE_UPDATE_K_MAX_VALIDITY_IN_MS, ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_MAX_VALIDITY_IN_MS) // .appendTableColumn(ServiceUpdateDbHelper.T_SERVICE_UPDATE, ServiceUpdateDbHelper.T_SERVICE_UPDATE_K_SEVERITY, ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_SEVERITY) // @@ -90,8 +84,8 @@ private static Cursor getServiceUpdates(ServiceUpdateProviderContract provider, MTLog.w(LOG_TAG, "Error while parsing service update filter! (%s)", selection); return getServiceUpdateCursor(null); } - long nowInMs = TimeUtils.currentTimeMillis(); - ArrayList cachedServiceUpdates = provider.getCachedServiceUpdates(serviceUpdateFilter); + final long nowInMs = TimeUtils.currentTimeMillis(); + final List cachedServiceUpdates = provider.getCachedServiceUpdates(serviceUpdateFilter); boolean purgeNecessary = false; if (cachedServiceUpdates != null) { Iterator it = cachedServiceUpdates.iterator(); @@ -142,19 +136,19 @@ private static Cursor getServiceUpdates(ServiceUpdateProviderContract provider, } } if (loadNewServiceUpdates) { - final ArrayList newServiceUpdates = provider.getNewServiceUpdates(serviceUpdateFilter); + final List newServiceUpdates = provider.getNewServiceUpdates(serviceUpdateFilter); if (CollectionUtils.getSize(newServiceUpdates) != 0) { return getServiceUpdateCursor(newServiceUpdates); } } if (CollectionUtils.getSize(cachedServiceUpdates) == 0) { - MTLog.w(LOG_TAG, "getServiceUpdates() > no cache & no data from provider for %s!", serviceUpdateFilter.getUUID()); + MTLog.w(LOG_TAG, "getServiceUpdates() > no cache & no data from provider for %s!", serviceUpdateFilter.getTargetUUID()); } return getServiceUpdateCursor(cachedServiceUpdates); } @NonNull - public static Cursor getServiceUpdateCursor(@Nullable ArrayList serviceUpdates) { + private static Cursor getServiceUpdateCursor(@Nullable List serviceUpdates) { if (serviceUpdates == null) { return ContentProviderConstants.EMPTY_CURSOR; } @@ -165,7 +159,8 @@ public static Cursor getServiceUpdateCursor(@Nullable ArrayList s return matrixCursor; } - public static synchronized int cacheServiceUpdatesS(@NonNull ServiceUpdateProviderContract provider, @Nullable ArrayList newServiceUpdates) { + @SuppressWarnings("UnusedReturnValue") + public static synchronized int cacheServiceUpdatesS(@NonNull ServiceUpdateProviderContract provider, @Nullable List newServiceUpdates) { int affectedRows = 0; SQLiteDatabase db = null; try { @@ -189,6 +184,7 @@ public static synchronized int cacheServiceUpdatesS(@NonNull ServiceUpdateProvid return affectedRows; } + @SuppressWarnings("unused") public static void cacheServiceUpdateS(@NonNull ServiceUpdateProviderContract provider, @NonNull ServiceUpdate newServiceUpdate) { try { provider.getWriteDB() @@ -198,67 +194,8 @@ public static void cacheServiceUpdateS(@NonNull ServiceUpdateProviderContract pr } } - @Nullable - public static ArrayList getCachedServiceUpdatesS(@NonNull ServiceUpdateProviderContract provider, @NonNull Collection targetUUIDs) { - return getCachedServiceUpdatesS( - provider, - getServiceUpdateContentUri(provider), - SqlUtils.getWhereInString(Columns.T_SERVICE_UPDATE_K_TARGET_UUID, targetUUIDs) + // - SqlUtils.AND + // - SqlUtils.getWhereEqualsString(Columns.T_SERVICE_UPDATE_K_LANGUAGE, provider.getServiceUpdateLanguage()) - ); - } - - @Nullable - public static ArrayList getCachedServiceUpdatesS(@NonNull ServiceUpdateProviderContract provider, @NonNull String targetUUID) { - return getCachedServiceUpdatesS( - provider, - getServiceUpdateContentUri(provider), - SqlUtils.getWhereEqualsString(Columns.T_SERVICE_UPDATE_K_TARGET_UUID, targetUUID) + - SqlUtils.AND + - SqlUtils.getWhereEqualsString(Columns.T_SERVICE_UPDATE_K_LANGUAGE, provider.getServiceUpdateLanguage()) - ); - } - - @Nullable - private static ArrayList getCachedServiceUpdatesS( - @NonNull ServiceUpdateProviderContract provider, - @SuppressWarnings("unused") Uri uri, - String selection) { - ArrayList cache = new ArrayList<>(); - Cursor cursor = null; - try { - SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); - qb.setTables(provider.getServiceUpdateDbTableName()); - qb.setProjectionMap(SERVICE_UPDATE_PROJECTION_MAP); - cursor = qb.query(provider.getReadDB(), ServiceUpdateProviderContract.PROJECTION_SERVICE_UPDATE, selection, null, null, - null, null, null); - if (cursor != null && cursor.getCount() > 0) { - if (cursor.moveToFirst()) { - do { - cache.add(ServiceUpdate.fromCursor(cursor)); - } while (cursor.moveToNext()); - } - } - return cache; - } catch (Exception e) { - MTLog.w(LOG_TAG, e, "Error!"); - return null; - } finally { - SqlUtils.closeQuietly(cursor); - } - } - - @NonNull - public static Uri getServiceUpdateContentUri(@NonNull ServiceUpdateProviderContract provider) { - return Uri.withAppendedPath(provider.getAuthorityUri(), ServiceUpdateProviderContract.SERVICE_UPDATE_PATH); - } - public static boolean deleteCachedServiceUpdate(@NonNull ServiceUpdateProviderContract provider, @NonNull Integer serviceUpdateId) { - if (serviceUpdateId == null) { - return false; - } - String selection = SqlUtils.getWhereEquals(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_ID, serviceUpdateId); + final String selection = SqlUtils.getWhereEquals(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_ID, serviceUpdateId); int deletedRows = 0; try { deletedRows = provider.getWriteDB().delete(provider.getServiceUpdateDbTableName(), selection, null); @@ -297,53 +234,4 @@ public static boolean purgeUselessCachedServiceUpdates(@NonNull ServiceUpdatePro } return deletedRows > 0; } - - public static abstract class ServiceUpdateDbHelper extends MTSQLiteOpenHelper { - - public static final String T_SERVICE_UPDATE = "service_update"; - public static final String T_SERVICE_UPDATE_K_ID = BaseColumns._ID; - public static final String T_SERVICE_UPDATE_K_TARGET_UUID = "target"; - public static final String T_SERVICE_UPDATE_K_LAST_UPDATE = "last_update"; - public static final String T_SERVICE_UPDATE_K_MAX_VALIDITY_IN_MS = "max_validity"; - public static final String T_SERVICE_UPDATE_K_SEVERITY = "severity"; - public static final String T_SERVICE_UPDATE_K_TEXT = "text"; - public static final String T_SERVICE_UPDATE_K_TEXT_HTML = "text_html"; - public static final String T_SERVICE_UPDATE_K_LANGUAGE = "lang"; - public static final String T_SERVICE_UPDATE_K_SOURCE_LABEL = "source_label"; - public static final String T_SERVICE_UPDATE_K_ORIGINAL_ID = "original_id"; - public static final String T_SERVICE_UPDATE_K_SOURCE_ID = "source_id"; - - public static final String T_SERVICE_UPDATE_SQL_CREATE = getSqlCreateBuilder(T_SERVICE_UPDATE).build(); - - public static final String T_SERVICE_UPDATE_SQL_DROP = SqlUtils.getSQLDropIfExistsQuery(T_SERVICE_UPDATE); - - public ServiceUpdateDbHelper(@Nullable Context context, @Nullable String dbName, @Nullable CursorFactory factory, int dbVersion) { - super(context, dbName, factory, dbVersion); - } - - @NonNull - public abstract String getDbName(); - - @NonNull - public static String getFkColumnName(@NonNull String columnName) { - return "fk" + "_" + columnName; - } - - @NonNull - public static SQLCreateBuilder getSqlCreateBuilder(@NonNull String table) { - return SQLCreateBuilder.getNew(table) // - .appendColumn(T_SERVICE_UPDATE_K_ID, SqlUtils.INT_PK_AUTO) // - .appendColumn(T_SERVICE_UPDATE_K_TARGET_UUID, SqlUtils.TXT) // - .appendColumn(T_SERVICE_UPDATE_K_LAST_UPDATE, SqlUtils.INT) // - .appendColumn(T_SERVICE_UPDATE_K_MAX_VALIDITY_IN_MS, SqlUtils.INT) // - .appendColumn(T_SERVICE_UPDATE_K_SEVERITY, SqlUtils.INT) // - .appendColumn(T_SERVICE_UPDATE_K_TEXT, SqlUtils.TXT) // - .appendColumn(T_SERVICE_UPDATE_K_TEXT_HTML, SqlUtils.TXT) // - .appendColumn(T_SERVICE_UPDATE_K_LANGUAGE, SqlUtils.TXT) // - .appendColumn(T_SERVICE_UPDATE_K_ORIGINAL_ID, SqlUtils.TXT) // - .appendColumn(T_SERVICE_UPDATE_K_SOURCE_LABEL, SqlUtils.TXT) // - .appendColumn(T_SERVICE_UPDATE_K_SOURCE_ID, SqlUtils.TXT) // - ; - } - } } diff --git a/src/main/java/org/mtransit/android/commons/provider/serviceupdate/ServiceUpdateProviderContract.java b/src/main/java/org/mtransit/android/commons/provider/serviceupdate/ServiceUpdateProviderContract.java index cb89c3a9..e799d540 100644 --- a/src/main/java/org/mtransit/android/commons/provider/serviceupdate/ServiceUpdateProviderContract.java +++ b/src/main/java/org/mtransit/android/commons/provider/serviceupdate/ServiceUpdateProviderContract.java @@ -15,17 +15,22 @@ import org.mtransit.android.commons.data.POI; import org.mtransit.android.commons.data.Route; import org.mtransit.android.commons.data.RouteDirection; +import org.mtransit.android.commons.data.RouteDirectionStop; import org.mtransit.android.commons.data.ServiceUpdate; +import org.mtransit.android.commons.data.Targetable; import org.mtransit.android.commons.provider.common.ProviderContract; -import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; public interface ServiceUpdateProviderContract extends ProviderContract { String SERVICE_UPDATE_PATH = "service"; + @NonNull + String getAuthority(); + @NonNull Uri getAuthorityUri(); @@ -35,20 +40,24 @@ public interface ServiceUpdateProviderContract extends ProviderContract { long getMinDurationBetweenServiceUpdateRefreshInMs(boolean inFocus); - void cacheServiceUpdates(@NonNull ArrayList newServiceUpdates); + void cacheServiceUpdates(@NonNull List newServiceUpdates); @Nullable - ArrayList getCachedServiceUpdates(@NonNull Filter serviceUpdateFilter); + List getCachedServiceUpdates(@NonNull Filter serviceUpdateFilter); @Nullable - ArrayList getNewServiceUpdates(@NonNull Filter serviceUpdateFilter); + List getNewServiceUpdates(@NonNull Filter serviceUpdateFilter); + @SuppressWarnings("UnusedReturnValue") boolean deleteCachedServiceUpdate(@NonNull Integer serviceUpdateId); + @SuppressWarnings("UnusedReturnValue") boolean deleteCachedServiceUpdate(@NonNull String targetUUID, @NonNull String sourceId); + @SuppressWarnings("UnusedReturnValue") boolean purgeUselessCachedServiceUpdates(); + @NonNull String getServiceUpdateDbTableName(); @NonNull @@ -57,6 +66,7 @@ public interface ServiceUpdateProviderContract extends ProviderContract { String[] PROJECTION_SERVICE_UPDATE = new String[]{ Columns.T_SERVICE_UPDATE_K_ID, Columns.T_SERVICE_UPDATE_K_TARGET_UUID, + Columns.T_SERVICE_UPDATE_K_TARGET_TRIP_ID, Columns.T_SERVICE_UPDATE_K_LAST_UPDATE, Columns.T_SERVICE_UPDATE_K_MAX_VALIDITY_IN_MS, Columns.T_SERVICE_UPDATE_K_SEVERITY, @@ -71,6 +81,7 @@ public interface ServiceUpdateProviderContract extends ProviderContract { class Columns { public static final String T_SERVICE_UPDATE_K_ID = BaseColumns._ID; public static final String T_SERVICE_UPDATE_K_TARGET_UUID = "target"; + public static final String T_SERVICE_UPDATE_K_TARGET_TRIP_ID = "trip_id"; public static final String T_SERVICE_UPDATE_K_LAST_UPDATE = "last_update"; public static final String T_SERVICE_UPDATE_K_MAX_VALIDITY_IN_MS = "max_validity"; public static final String T_SERVICE_UPDATE_K_SEVERITY = "severity"; @@ -82,6 +93,7 @@ class Columns { public static final String T_SERVICE_UPDATE_K_SOURCE_ID = "source_id"; } + @SuppressWarnings("WeakerAccess") class Filter implements MTLog.Loggable { private static final String TAG = ServiceUpdateProviderContract.class.getSimpleName() + ">" + Filter.class.getSimpleName(); @@ -159,15 +171,61 @@ public String toString() { } @Nullable - public String getUUID() { + public Targetable getTarget() { + if (this.poi != null) { + return this.poi; + } + if (this.route != null) { + return this.route; + } + //noinspection RedundantIfStatement + if (this.routeDirection != null) { + return this.routeDirection; + } + return null; + } + + @Nullable + public String getTargetUUID() { + final Targetable target = getTarget(); + return target == null ? null : target.getUUID(); + } + + @Nullable + public String getTargetAuthority() { if (this.poi != null) { - return this.poi.getUUID(); + return this.poi.getAuthority(); } if (this.route != null) { - return this.route.getUUID(); + return this.route.getAuthority(); } if (this.routeDirection != null) { - return this.routeDirection.getUUID(); + return this.routeDirection.getAuthority(); + } + return null; + } + + @Nullable + public Long getRouteId() { + if (this.poi != null && this.poi instanceof RouteDirectionStop) { + return ((RouteDirectionStop) this.poi).getRoute().getId(); + } + if (this.route != null) { + return this.route.getId(); + } + if (this.routeDirection != null) { + return this.routeDirection.getRoute().getId(); + } + return null; + } + + @Nullable + public Long getDirectionId() { + if (this.poi != null && this.poi instanceof RouteDirectionStop) { + return ((RouteDirectionStop) this.poi).getDirection().getId(); + } + if (this.routeDirection != null) { + return this.routeDirection.getDirection().getId(); } return null; } @@ -187,6 +245,7 @@ public RouteDirection getRouteDirection() { return routeDirection; } + @SuppressWarnings("unused") public void setCacheOnly(@Nullable Boolean cacheOnly) { this.cacheOnly = cacheOnly; } @@ -195,11 +254,12 @@ public boolean isCacheOnlyOrDefault() { return this.cacheOnly == null ? CACHE_ONLY_DEFAULT : this.cacheOnly; } + @Nullable public Boolean getCacheOnlyOrNull() { return this.cacheOnly; } - public void setInFocus(Boolean inFocus) { + public void setInFocus(@Nullable Boolean inFocus) { this.inFocus = inFocus; } @@ -207,19 +267,23 @@ public boolean isInFocusOrDefault() { return this.inFocus == null ? IN_FOCUS_DEFAULT : this.inFocus; } + @Nullable public Boolean getInFocusOrNull() { return this.inFocus; } + @Nullable public Long getCacheValidityInMsOrNull() { return this.cacheValidityInMs; } + @SuppressWarnings("unused") public boolean hasCacheValidityInMs() { return this.cacheValidityInMs != null && this.cacheValidityInMs > 0; } - public void setCacheValidityInMs(Long cacheValidityInMs) { + @SuppressWarnings("unused") + public void setCacheValidityInMs(@Nullable Long cacheValidityInMs) { this.cacheValidityInMs = cacheValidityInMs; } @@ -229,6 +293,7 @@ public Filter setProvidedEncryptKeysMap(@Nullable Map providedEn return this; } + @SuppressWarnings("unused") public boolean hasProvidedEncryptKeysMap() { return this.providedEncryptKeysMap != null && !this.providedEncryptKeysMap.isEmpty(); } diff --git a/src/main/java/org/mtransit/android/commons/provider/serviceupdate/ServiceUpdateProviderExt.kt b/src/main/java/org/mtransit/android/commons/provider/serviceupdate/ServiceUpdateProviderExt.kt new file mode 100644 index 00000000..7a742e08 --- /dev/null +++ b/src/main/java/org/mtransit/android/commons/provider/serviceupdate/ServiceUpdateProviderExt.kt @@ -0,0 +1,76 @@ +package org.mtransit.android.commons.provider.serviceupdate + +import android.database.sqlite.SQLiteQueryBuilder +import android.net.Uri +import org.mtransit.android.commons.MTLog +import org.mtransit.android.commons.SqlUtils +import org.mtransit.android.commons.data.ServiceUpdate +import org.mtransit.commons.FeatureFlags + +private val LOG_TAG: String = ServiceUpdateProvider::class.java.simpleName + +@JvmOverloads +fun

P.getCachedServiceUpdatesS( + targetUUID: String, + tripIds: List? = null +) = getCachedServiceUpdatesS(listOf(targetUUID), tripIds) + +@JvmOverloads +fun

P.getCachedServiceUpdatesS( + targetUUIDs: Collection, + tripIds: List? = null +): List? { + return getCachedServiceUpdatesS( + this.contentUri, + buildString { + append(SqlUtils.getWhereInString(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_TARGET_UUID, targetUUIDs)) + append(SqlUtils.AND) + append(SqlUtils.getWhereEqualsString(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_LANGUAGE, serviceUpdateLanguage)) + if (FeatureFlags.F_USE_TRIP_IS_FOR_SERVICE_UPDATES) { + tripIds?.takeIf { it.isNotEmpty() }?.let { + append(SqlUtils.AND) + append( + SqlUtils.getWhereGroup( + SqlUtils.OR, + SqlUtils.getWhereInString(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_TARGET_TRIP_ID, it), + SqlUtils.getWhereColumnIsNull(ServiceUpdateProviderContract.Columns.T_SERVICE_UPDATE_K_TARGET_TRIP_ID), + ) + ) + } + } + } + ) +} + +private fun

P.getCachedServiceUpdatesS( + @Suppress("unused") uri: Uri?, + selection: String?, +): List? = + try { + SQLiteQueryBuilder() + .apply { + tables = dbTableName + projectionMap = ServiceUpdateProvider.SERVICE_UPDATE_PROJECTION_MAP + }.query( + getReadDB(), ServiceUpdateProviderContract.PROJECTION_SERVICE_UPDATE, selection, null, null, null, null, null + ).use { cursor -> + buildList { + if (cursor != null && cursor.count > 0) { + if (cursor.moveToFirst()) { + do { + add(ServiceUpdate.fromCursor(cursor)) + } while (cursor.moveToNext()) + } + } + } + } + } catch (e: Exception) { + MTLog.w(LOG_TAG, e, "Error!") + null + } + +private val ServiceUpdateProviderContract.contentUri: Uri + get() = Uri.withAppendedPath(this.authorityUri, ServiceUpdateProviderContract.SERVICE_UPDATE_PATH) + +private val ServiceUpdateProviderContract.dbTableName: String + get() = this.serviceUpdateDbTableName diff --git a/src/main/java/org/mtransit/android/commons/provider/vehiclelocations/GTFSRealTimeVehiclePositionsProvider.kt b/src/main/java/org/mtransit/android/commons/provider/vehiclelocations/GTFSRealTimeVehiclePositionsProvider.kt index d9c1f31e..50decd5a 100644 --- a/src/main/java/org/mtransit/android/commons/provider/vehiclelocations/GTFSRealTimeVehiclePositionsProvider.kt +++ b/src/main/java/org/mtransit/android/commons/provider/vehiclelocations/GTFSRealTimeVehiclePositionsProvider.kt @@ -6,9 +6,6 @@ import com.google.transit.realtime.GtfsRealtime.FeedMessage import org.mtransit.android.commons.Constants import org.mtransit.android.commons.MTLog import org.mtransit.android.commons.TimeUtils -import org.mtransit.android.commons.data.Direction -import org.mtransit.android.commons.data.Route -import org.mtransit.android.commons.data.RouteDirection import org.mtransit.android.commons.data.RouteDirectionStop import org.mtransit.android.commons.provider.GTFSRealTimeProvider import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAgencyRouteDirectionTagTargetUUID @@ -16,11 +13,13 @@ import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAgencyRoute import org.mtransit.android.commons.provider.GTFSRealTimeProvider.getAgencyTagTargetUUID import org.mtransit.android.commons.provider.gtfs.GtfsRealTimeStorage import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.optBearing +import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.optDirectionId import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.optId import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.optLabel import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.optLatitude import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.optLongitude import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.optPosition +import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.optRouteId import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.optSpeed import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.optTimestamp import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.optTrip @@ -31,7 +30,12 @@ import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.originalIdToId import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.sortVehicles import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.toStringExt import org.mtransit.android.commons.provider.gtfs.GtfsRealtimeExt.toVehicles +import org.mtransit.android.commons.provider.gtfs.agencyTag +import org.mtransit.android.commons.provider.gtfs.getTargetUUIDs +import org.mtransit.android.commons.provider.gtfs.getTripIds import org.mtransit.android.commons.provider.gtfs.makeRequest +import org.mtransit.android.commons.provider.gtfs.routeIdCleanupPattern +import org.mtransit.android.commons.provider.gtfs.tripIdCleanupPattern import org.mtransit.android.commons.provider.vehiclelocations.VehicleLocationProvider.Companion.getCachedVehicleLocationsS import org.mtransit.android.commons.provider.vehiclelocations.model.VehicleLocation import java.net.HttpURLConnection @@ -80,27 +84,18 @@ object GTFSRealTimeVehiclePositionsProvider { ?: filter.routeDirection?.getTargetUUIDs(this) ?: filter.route?.getTargetUUIDs(this)) ?.let { targetUUIDs -> - filter.tripIds + val tripIds = filter.targetAuthority?.let { targetAuthority -> + filter.routeId?.let { routeId -> + context?.getTripIds(targetAuthority, routeId, filter.directionId) + } + } + tripIds ?.takeIf { tripIds -> tripIds.isNotEmpty() } // trip IDs REQUIRED for GTFS Vehicle locations ?.let { tripIds -> targetUUIDs to tripIds } }?.let { (targetUUIDs, tripIds) -> getCached(targetUUIDs, tripIds) } - private fun RouteDirectionStop.getTargetUUIDs(provider: GTFSRealTimeProvider) = buildMap { - put(getAgencyRouteTagTargetUUID(provider.agencyTag, getRouteTag(provider)), route.uuid) - getAgencyRouteDirectionTagTargetUUID(provider.agencyTag, getRouteTag(provider), getDirectionTag(provider))?.let { put(it, routeDirectionUUID) } - } - - private fun RouteDirection.getTargetUUIDs(provider: GTFSRealTimeProvider) = buildMap { - put(getAgencyRouteTagTargetUUID(provider.agencyTag, getRouteTag(provider)), route.uuid) - getAgencyRouteDirectionTagTargetUUID(provider.agencyTag, getRouteTag(provider), getDirectionTag(provider))?.let { put(it, uuid) } - } - - private fun Route.getTargetUUIDs(provider: GTFSRealTimeProvider) = mapOf( - getAgencyRouteTagTargetUUID(provider.agencyTag, getRouteTag(provider)) to uuid, - ) - fun GTFSRealTimeProvider.getCached(targetUUIDs: Map, tripIds: List) = buildList { getCachedVehicleLocationsS(targetUUIDs.keys, tripIds)?.let { addAll(it) @@ -255,11 +250,14 @@ object GTFSRealTimeVehiclePositionsProvider { } private fun GTFSRealTimeProvider.parseProviderTargetUUID(gVehiclePosition: GtfsRealtime.VehiclePosition, ignoreDirection: Boolean): String? { - val tripDescriptor = gVehiclePosition.optTrip ?: return null - if (tripDescriptor.hasModifiedTrip() || tripDescriptor.hasStartTime() || tripDescriptor.hasStartDate()) { - MTLog.d(this, "parseTargetUUID() > unhandled values: ${tripDescriptor.toStringExt()}") + val gTripDescriptor = gVehiclePosition.optTrip ?: return null + if (gTripDescriptor.hasModifiedTrip()) { + MTLog.d(this, "parseTargetUUID() > unhandled modified trip: ${gTripDescriptor.toStringExt()}") + } + if (gTripDescriptor.hasStartTime() || gTripDescriptor.hasStartDate()) { + MTLog.d(this, "parseTargetUUID() > unhandled start date & time: ${gTripDescriptor.toStringExt()}") } - when (tripDescriptor.scheduleRelationship) { + when (gTripDescriptor.scheduleRelationship) { GtfsRealtime.TripDescriptor.ScheduleRelationship.SCHEDULED -> {} // handled GtfsRealtime.TripDescriptor.ScheduleRelationship.ADDED, GtfsRealtime.TripDescriptor.ScheduleRelationship.UNSCHEDULED, @@ -268,39 +266,14 @@ object GTFSRealTimeVehiclePositionsProvider { GtfsRealtime.TripDescriptor.ScheduleRelationship.DUPLICATED, GtfsRealtime.TripDescriptor.ScheduleRelationship.DELETED, GtfsRealtime.TripDescriptor.ScheduleRelationship.NEW, - -> MTLog.d(this, "parseTargetUUID() > unhandled schedule relationship: ${tripDescriptor.scheduleRelationship}") + -> MTLog.d(this, "parseTargetUUID() > unhandled schedule relationship: ${gTripDescriptor.scheduleRelationship}") } - return if (tripDescriptor.hasRouteId()) { - if (tripDescriptor.hasDirectionId() && !ignoreDirection) { - getAgencyRouteDirectionTagTargetUUID( - agencyTag, - tripDescriptor.routeId.originalIdToHash(routeIdCleanupPattern), - tripDescriptor.directionId, - ) - } else { - getAgencyRouteTagTargetUUID( - agencyTag, - tripDescriptor.routeId.originalIdToHash(routeIdCleanupPattern), - ) + gTripDescriptor.optRouteId?.originalIdToHash(routeIdCleanupPattern)?.let { routeId -> + gTripDescriptor.optDirectionId?.takeIf { !ignoreDirection }?.let { directionId -> + return getAgencyRouteDirectionTagTargetUUID(agencyTag, routeId, directionId) } - } else { - getAgencyTagTargetUUID( - agencyTag - ) + return getAgencyRouteTagTargetUUID(agencyTag, routeId) } + return getAgencyTagTargetUUID(agencyTag) } - - private val GTFSRealTimeProvider.routeIdCleanupPattern get() = getRouteIdCleanupPattern(requireContextCompat()) - private val GTFSRealTimeProvider.tripIdCleanupPattern get() = getTripIdCleanupPattern(requireContextCompat()) - - private val GTFSRealTimeProvider.agencyTag get() = getAgencyTag(requireContextCompat()) - - private fun Route.getRouteTag(provider: GTFSRealTimeProvider) = provider.getRouteTag(this) - private fun Direction.getDirectionTag(provider: GTFSRealTimeProvider) = provider.getDirectionTag(this) - - private fun RouteDirection.getRouteTag(provider: GTFSRealTimeProvider) = this.route.getRouteTag(provider) - private fun RouteDirection.getDirectionTag(provider: GTFSRealTimeProvider) = this.direction.getDirectionTag(provider) - - private fun RouteDirectionStop.getRouteTag(provider: GTFSRealTimeProvider) = this.route.getRouteTag(provider) - private fun RouteDirectionStop.getDirectionTag(provider: GTFSRealTimeProvider) = this.direction.getDirectionTag(provider) } diff --git a/src/main/java/org/mtransit/android/commons/provider/vehiclelocations/VehicleLocationDbHelper.kt b/src/main/java/org/mtransit/android/commons/provider/vehiclelocations/VehicleLocationDbHelper.kt index 44ba542c..a82882cc 100644 --- a/src/main/java/org/mtransit/android/commons/provider/vehiclelocations/VehicleLocationDbHelper.kt +++ b/src/main/java/org/mtransit/android/commons/provider/vehiclelocations/VehicleLocationDbHelper.kt @@ -5,19 +5,15 @@ import android.database.sqlite.SQLiteDatabase import android.provider.BaseColumns import org.mtransit.android.commons.SqlUtils import org.mtransit.android.commons.provider.common.MTSQLiteOpenHelper -import org.mtransit.commons.sql.SQLCreateBuilder.Companion.getNew +import org.mtransit.commons.sql.SQLCreateBuilder abstract class VehicleLocationDbHelper( context: Context?, - dbName: String, + name: String, factory: SQLiteDatabase.CursorFactory?, dbVersion: Int, -) : MTSQLiteOpenHelper( - context, - dbName, - factory, - dbVersion, -) { +) : MTSQLiteOpenHelper(context, name, factory, dbVersion) { + companion object { const val T_VEHICLE_LOCATION = "vehicle_location" @@ -36,7 +32,7 @@ abstract class VehicleLocationDbHelper( const val T_VEHICLE_LOCATION_K_SPEED = "speed" @JvmStatic - fun getSqlCreateBuilder(table: String) = getNew(table) + fun getSqlCreateBuilder(table: String) = SQLCreateBuilder.getNew(table) .appendColumn(T_VEHICLE_LOCATION_K_ID, SqlUtils.INT_PK_AUTO) .appendColumn(T_VEHICLE_LOCATION_K_TARGET_UUID, SqlUtils.TXT) .appendColumn(T_VEHICLE_LOCATION_K_TARGET_TRIP_ID, SqlUtils.TXT) @@ -53,4 +49,4 @@ abstract class VehicleLocationDbHelper( } abstract val dbName: String -} \ No newline at end of file +} diff --git a/src/main/java/org/mtransit/android/commons/provider/vehiclelocations/VehicleLocationProvider.kt b/src/main/java/org/mtransit/android/commons/provider/vehiclelocations/VehicleLocationProvider.kt index 38b9d421..abf4d0dd 100644 --- a/src/main/java/org/mtransit/android/commons/provider/vehiclelocations/VehicleLocationProvider.kt +++ b/src/main/java/org/mtransit/android/commons/provider/vehiclelocations/VehicleLocationProvider.kt @@ -98,7 +98,7 @@ abstract class VehicleLocationProvider : MTContentProvider(), } } if (cachedVehicleLocations.isNullOrEmpty()) { - MTLog.w(LOG_TAG, "getVehicleLocations() > no cache & no data from provider for %s!", filter.uuid) + MTLog.w(LOG_TAG, "getVehicleLocations() > no cache & no data from provider for %s!", filter.targetUuid) } return getVehicleLocationCursor(cachedVehicleLocations) } @@ -124,26 +124,25 @@ abstract class VehicleLocationProvider : MTContentProvider(), } } - fun

P.getCachedVehicleLocationsS(targetUUIDs: Collection, tripIds: List? = null): List? { - return getCachedVehicleLocationsS( - this.contentUri, - buildString { - append(SqlUtils.getWhereInString(VehicleLocationProviderContract.Columns.T_VEHICLE_LOCATION_K_TARGET_UUID, targetUUIDs)) - tripIds?.takeIf { it.isNotEmpty() }?.let { - append(SqlUtils.AND) - append(SqlUtils.getWhereInString(VehicleLocationProviderContract.Columns.T_VEHICLE_LOCATION_K_TARGET_TRIP_ID, it)) - } + fun

P.getCachedVehicleLocationsS( + targetUUIDs: Collection, + tripIds: List? = null, + ) = getCachedVehicleLocationsS( + this.contentUri, + selection = buildString { + append(SqlUtils.getWhereInString(VehicleLocationProviderContract.Columns.T_VEHICLE_LOCATION_K_TARGET_UUID, targetUUIDs)) + tripIds?.takeIf { it.isNotEmpty() }?.let { + append(SqlUtils.AND) + append( + SqlUtils.getWhereGroup( + SqlUtils.OR, + SqlUtils.getWhereInString(VehicleLocationProviderContract.Columns.T_VEHICLE_LOCATION_K_TARGET_TRIP_ID, it), + SqlUtils.getWhereColumnIsNull(VehicleLocationProviderContract.Columns.T_VEHICLE_LOCATION_K_TARGET_TRIP_ID), + ) + ) } - ) - } - - @Suppress("unused") - fun

P.getCachedVehicleLocationsS(targetUUID: String): List? { - return getCachedVehicleLocationsS( - this.contentUri, - SqlUtils.getWhereEqualsString(VehicleLocationProviderContract.Columns.T_VEHICLE_LOCATION_K_TARGET_UUID, targetUUID) - ) - } + } + ) //@formatter:off @JvmStatic @@ -174,8 +173,7 @@ abstract class VehicleLocationProvider : MTContentProvider(), tables = dbTableName projectionMap = VEHICLE_LOCATION_PROJECTION_MAP }.query( - getReadDB(), VehicleLocationProviderContract.PROJECTION_VEHICLE_LOCATION, selection, null, null, - null, null, null + readDB, VehicleLocationProviderContract.PROJECTION_VEHICLE_LOCATION, selection, null, null, null, null, null ).use { cursor -> buildList { if (cursor != null && cursor.count > 0) { @@ -250,10 +248,10 @@ abstract class VehicleLocationProvider : MTContentProvider(), } return deletedRows > 0 } + + private val VehicleLocationProviderContract.dbTableName: String + get() = this.vehicleLocationDbTableName } override fun getLogTag() = LOG_TAG } - -private val VehicleLocationProviderContract.dbTableName: String - get() = this.vehicleLocationDbTableName diff --git a/src/main/java/org/mtransit/android/commons/provider/vehiclelocations/VehicleLocationProviderContract.kt b/src/main/java/org/mtransit/android/commons/provider/vehiclelocations/VehicleLocationProviderContract.kt index f930e0b0..08ce74e9 100644 --- a/src/main/java/org/mtransit/android/commons/provider/vehiclelocations/VehicleLocationProviderContract.kt +++ b/src/main/java/org/mtransit/android/commons/provider/vehiclelocations/VehicleLocationProviderContract.kt @@ -4,7 +4,6 @@ import android.annotation.SuppressLint import android.net.Uri import android.provider.BaseColumns import androidx.annotation.Discouraged -import org.json.JSONArray import org.json.JSONException import org.json.JSONObject import org.mtransit.android.commons.JSONUtils @@ -12,9 +11,11 @@ import org.mtransit.android.commons.MTLog import org.mtransit.android.commons.MTLog.Loggable import org.mtransit.android.commons.SecureStringUtils import org.mtransit.android.commons.data.DefaultPOI +import org.mtransit.android.commons.data.Direction import org.mtransit.android.commons.data.POI import org.mtransit.android.commons.data.Route import org.mtransit.android.commons.data.RouteDirection +import org.mtransit.android.commons.data.RouteDirectionStop import org.mtransit.android.commons.provider.common.ProviderContract import org.mtransit.android.commons.provider.vehiclelocations.model.VehicleLocation import org.mtransit.commons.mapNotNullToMap @@ -94,7 +95,6 @@ interface VehicleLocationProviderContract : ProviderContract { val poi: POI? = null, // RouteDirectionStop or DefaultPOI val route: Route? = null, val routeDirection: RouteDirection? = null, - val tripIds: List?, // original // GTFS // cleaned ) : Loggable { var inFocus: Boolean? = null @@ -106,24 +106,17 @@ interface VehicleLocationProviderContract : ProviderContract { var providedEncryptKeysMap: Map? = null private set - @Discouraged("only for logs") - val targetUUIDs: List = buildList { - poi?.uuid?.let { add(it) } - route?.uuid?.let { add(it) } - routeDirection?.uuid?.let { add(it) } - } - @SuppressLint("DiscouragedApi") constructor(poi: POI, tripIds: List? = null) : - this(authority = poi.authority, poi = poi, tripIds = tripIds) + this(authority = poi.authority, poi = poi) @SuppressLint("DiscouragedApi") constructor(route: Route, tripIds: List? = null) : - this(authority = route.authority, route = route, tripIds = tripIds) + this(authority = route.authority, route = route) @SuppressLint("DiscouragedApi") constructor(routeDirection: RouteDirection, tripIds: List? = null) : - this(authority = routeDirection.authority, routeDirection = routeDirection, tripIds = tripIds) + this(authority = routeDirection.authority, routeDirection = routeDirection) @Suppress("unused") // main app only fun appendProvidedKeys(keysMap: Map?): Filter { @@ -145,7 +138,6 @@ interface VehicleLocationProviderContract : ProviderContract { private const val JSON_POI = "poi" private const val JSON_ROUTE = "route" private const val JSON_ROUTE_DIRECTION = "routeDirection" - private const val JSON_TRIP_IDS = "tripIds" private const val JSON_CACHE_ONLY = "cacheOnly" private const val JSON_IN_FOCUS = "inFocus" private const val JSON_PROVIDED_ENCRYPT_KEYS_MAP = "providedEncryptKeysMap" @@ -171,21 +163,14 @@ interface VehicleLocationProviderContract : ProviderContract { val routeDirection = json.optJSONObject(JSON_ROUTE_DIRECTION)?.let { jRouteDirection -> authority?.let { RouteDirection.fromJSON(jRouteDirection, it) } } - val tripIds = json.optJSONArray(JSON_TRIP_IDS)?.let { jTripIds -> - buildList { - for (i in 0 until jTripIds.length()) { - add(jTripIds.getString(i)) - } - } - } val inFocus = JSONUtils.optBoolean(json, JSON_IN_FOCUS) val cacheOnly = JSONUtils.optBoolean(json, JSON_CACHE_ONLY) val providedEncryptKeysMap: Map? = json.optJSONObject(JSON_PROVIDED_ENCRYPT_KEYS_MAP)?.let { jProvidedEncryptKeysMap -> JSONUtils.toMapOfStrings(jProvidedEncryptKeysMap) } - return (poi?.let { Filter(authority = it.authority, poi = it, tripIds = tripIds) } - ?: route?.let { Filter(authority = route.authority, route = it, tripIds = tripIds) } - ?: routeDirection?.let { Filter(authority = routeDirection.authority, routeDirection = it, tripIds = tripIds) }) + return (poi?.let { Filter(authority = it.authority, poi = it) } + ?: route?.let { Filter(authority = route.authority, route = it) } + ?: routeDirection?.let { Filter(authority = routeDirection.authority, routeDirection = it) }) ?.apply { this.inFocus = inFocus this.cacheOnly = cacheOnly @@ -203,7 +188,6 @@ interface VehicleLocationProviderContract : ProviderContract { vehicleLocationFilter.poi?.let { put(JSON_POI, it.toJSON()) } vehicleLocationFilter.route?.let { put(JSON_ROUTE, Route.toJSON(it)) } vehicleLocationFilter.routeDirection?.let { put(JSON_ROUTE_DIRECTION, RouteDirection.toJSON(it)) } - vehicleLocationFilter.tripIds?.let { put(JSON_TRIP_IDS, JSONArray(it)) } vehicleLocationFilter.inFocus?.let { put(JSON_IN_FOCUS, it) } vehicleLocationFilter.cacheOnly?.let { put(JSON_CACHE_ONLY, it) } vehicleLocationFilter.providedEncryptKeysMap?.let { put(JSON_PROVIDED_ENCRYPT_KEYS_MAP, JSONUtils.toJSONObject(it)) } @@ -220,7 +204,28 @@ interface VehicleLocationProviderContract : ProviderContract { @Suppress("unused") // used from main app fun toJSONString() = toJSONString(this) - val uuid: String? + private val _route: Route? + get() = (poi as? RouteDirectionStop)?.route + ?: route + ?: routeDirection?.route + + private val _direction: Direction? + get() = (poi as? RouteDirectionStop)?.direction + ?: routeDirection?.direction + + val routeId: Long? + get() = _route?.id + + val directionId: Long? + get() = _direction?.id + + val targetAuthority: String? + get() = poi?.authority + ?: route?.authority + ?: routeDirection?.authority + + @get:JvmName("getTargetUUID") + val targetUuid: String? get() = poi?.uuid ?: route?.uuid ?: routeDirection?.uuid