Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ android {
namespace = "org.mtransit.android.commons"

defaultConfig {
consumerProguardFiles("proguard-rules.pro")
consumerProguardFiles("consumer-proguard-rules.pro")
minSdk = libs.versions.sdk.min.get().toInteger()
targetSdk = libs.versions.sdk.target.get().toInteger()

Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions src/main/java/org/mtransit/android/commons/SqlUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ public static String unescapeString(@NonNull String string) {
}

@Nullable
public static String unescapeStringOrNull(@NonNull String string) {
return SQLUtils.unescapeStringOrNull(string);
public static String unquoteUnescapeStringOrNull(@NonNull String string) {
return SQLUtils.unquoteUnescapeStringOrNull(string);
}

private SqlUtils() {
Expand Down
30 changes: 1 addition & 29 deletions src/main/java/org/mtransit/android/commons/TimeUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -208,34 +208,6 @@ private static DateFormat getShortDateTimeFormatter() {

@NonNull
public static String formatSimpleDuration(long durationInMs) {
StringBuilder sb = new StringBuilder();
if (durationInMs < 0) {
durationInMs = abs(durationInMs);
}
sb.append("-");
final long days = durationInMs / TimeUnit.DAYS.toMillis(1L);
if (days > 0) {
sb.append(" ").append(days).append(" days");
durationInMs = durationInMs % days;
}
final long hours = durationInMs / TimeUnit.HOURS.toMillis(1L);
if (hours > 0) {
sb.append(" ").append(hours).append(" h");
durationInMs = durationInMs % hours;
}
final long minutes = durationInMs / TimeUnit.MINUTES.toMillis(1L);
if (minutes > 0) {
sb.append(" ").append(minutes).append(" min");
durationInMs = durationInMs % minutes;
}
final long seconds = durationInMs / TimeUnit.MINUTES.toMillis(1L);
if (seconds > 0) {
sb.append(" ").append(seconds).append(" sec");
durationInMs = durationInMs % seconds;
}
if (durationInMs > 0) {
sb.append(" ").append(durationInMs).append(" ms");
}
return sb.toString();
return TimeUtilsKt.formatSimpleDuration(durationInMs);
}
}
17 changes: 17 additions & 0 deletions src/main/java/org/mtransit/android/commons/TimeUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.mtransit.android.commons

import kotlin.math.abs
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.nanoseconds

fun formatSimpleDuration(durationInMs: Long) = buildString {
val negative = durationInMs < 0
abs(durationInMs).milliseconds.toComponents { days, hours, minutes, seconds, nanoseconds ->
days.takeIf { it > 0 }?.let { append(it).append(" days ") }
hours.takeIf { it > 0 }?.let { append(it).append(" h ") }
minutes.takeIf { it > 0 }?.let { append(it).append(" min ") }
seconds.takeIf { it > 0 }?.let { append(it).append(" sec ") }
nanoseconds.takeIf { it > 0 }?.nanoseconds?.inWholeMilliseconds?.let { append(it).append(" ms ") }
}
if (negative) insert(0, "-")
}.trim()
100 changes: 86 additions & 14 deletions src/main/java/org/mtransit/android/commons/data/Schedule.java
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,10 @@ public String getLogTag() {
private Boolean oldSchedule = null;
@Nullable
private Integer accessible = null;
@Nullable
private String tripId = null; // will store trip ID int initially but replaced with real trip ID soon after
@Nullable
private Long arrivalDiffMs = null;

@VisibleForTesting
public Timestamp(long t) {
Expand All @@ -453,6 +457,28 @@ public long getT() {
return t;
}

public long getArrivalT() {
return t + (arrivalDiffMs == null ? 0L : arrivalDiffMs);
}

@Nullable
public Long getArrivalTIfDifferent() {
return arrivalDiffMs == null ? null : t + arrivalDiffMs;
}

public void setArrivalTimestamp(long arrivalTimestamp) {
setArrivalDiffMs(arrivalTimestamp - this.t);
}

public void setArrivalDiffMs(@Nullable Long arrivalDiffMs) {
this.arrivalDiffMs = arrivalDiffMs;
}

@Nullable
public Long getArrivalDiffMs() {
return arrivalDiffMs;
}

@NonNull
public Timestamp setHeadsign(@Direction.HeadSignType int headsignType, @Nullable String headsignValue) {
this.headsignType = headsignType;
Expand Down Expand Up @@ -600,6 +626,15 @@ public int getAccessibleOrDefault() {
return this.accessible == null ? Accessibility.DEFAULT : this.accessible;
}

public void setTripId(@Nullable String tripId) {
this.tripId = tripId;
}

@Nullable
public String getTripId() {
return tripId;
}

@SuppressWarnings("RedundantIfStatement")
@Override
public boolean equals(Object o) {
Expand All @@ -615,6 +650,8 @@ public boolean equals(Object o) {
if (!Objects.equals(realTime, timestamp.realTime)) return false;
if (!Objects.equals(oldSchedule, timestamp.oldSchedule)) return false;
if (!Objects.equals(accessible, timestamp.accessible)) return false;
if (!Objects.equals(tripId, timestamp.tripId)) return false;
if (!Objects.equals(arrivalDiffMs, timestamp.arrivalDiffMs)) return false;
// if (!Objects.equals(heading, timestamp.heading)) return false; // LAZY
return true;
}
Expand All @@ -628,26 +665,49 @@ public int hashCode() {
result = 31 * result + (realTime != null ? realTime.hashCode() : 0);
result = 31 * result + (oldSchedule != null ? oldSchedule.hashCode() : 0);
result = 31 * result + (accessible != null ? accessible : 0);
result = 31 * result + (tripId != null ? tripId.hashCode() : 0);
result = 31 * result + (arrivalDiffMs != null ? arrivalDiffMs.hashCode() : 0);
// result = 31 * result + (heading != null ? heading.hashCode() : 0); // LAZY
return result;
}

@NonNull
@Override
public String toString() {
return Timestamp.class.getSimpleName() + "{" +
"t=" + (Constants.DEBUG ? MTLog.formatDateTime(t) : t) +
", headsignType=" + headsignType +
", headsignValue='" + headsignValue + '\'' +
", localTimeZone='" + localTimeZoneId + '\'' +
", realTime=" + realTime +
", oldSchedule=" + oldSchedule +
", accessible=" + accessible +
", heading='" + heading + '\'' +
'}';
StringBuilder sb = new StringBuilder(Timestamp.class.getSimpleName());
sb.append('{');
sb.append("t=").append(Constants.DEBUG ? MTLog.formatDateTime(t) : t);
if (arrivalDiffMs != null) {
sb.append(", aD:").append(arrivalDiffMs);
}
if (tripId != null) {
sb.append(", tripId:'").append(tripId).append('\'');
}
if (headsignType != Direction.HEADSIGN_TYPE_NONE) {
sb.append(", ht:").append(headsignType);
}
if (headsignValue != null) {
sb.append(", hv:'").append(headsignValue).append('\'');
}
if (localTimeZoneId != null) {
sb.append(", tz:'").append(localTimeZoneId).append('\'');
}
if (realTime != null) {
sb.append(", rt:").append(realTime);
}
if (oldSchedule != null) {
sb.append(", old:").append(oldSchedule);
}
if (accessible != null) {
sb.append(", a11y:").append(accessible);
}
sb.append('}');
return sb.toString();
}

private static final String JSON_TIMESTAMP = "t";
private static final String JSON_ARRIVAL_DIFF = "tDiffA";
private static final String JSON_TRIP_ID = "trip_id";
private static final String JSON_HEADSIGN_TYPE = "ht";
private static final String JSON_HEADSIGN_VALUE = "hv";
private static final String JSON_LOCAL_TIME_ZONE = "localTimeZone";
Expand All @@ -658,10 +718,16 @@ public String toString() {
@Nullable
static Timestamp parseJSON(@NonNull JSONObject jTimestamp) {
try {
long t = jTimestamp.getLong(JSON_TIMESTAMP);
Timestamp timestamp = new Timestamp(t);
int headSignType = jTimestamp.optInt(JSON_HEADSIGN_TYPE, -1);
String headSignValue = jTimestamp.optString(JSON_HEADSIGN_VALUE, StringUtils.EMPTY);
final long t = jTimestamp.getLong(JSON_TIMESTAMP);
final Timestamp timestamp = new Timestamp(t);
if (jTimestamp.has(JSON_ARRIVAL_DIFF)) {
timestamp.setArrivalDiffMs(jTimestamp.getLong(JSON_ARRIVAL_DIFF));
}
if (jTimestamp.has(JSON_TRIP_ID)) {
timestamp.setTripId(jTimestamp.getString(JSON_TRIP_ID));
}
final int headSignType = jTimestamp.optInt(JSON_HEADSIGN_TYPE, -1);
final String headSignValue = jTimestamp.optString(JSON_HEADSIGN_VALUE, StringUtils.EMPTY);
if (headSignType >= 0 && !headSignValue.isEmpty()) {
timestamp.setHeadsign(headSignType, headSignValue);
} else {
Expand Down Expand Up @@ -699,6 +765,12 @@ public static JSONObject toJSON(@NonNull Timestamp timestamp) {
try {
JSONObject jTimestamp = new JSONObject();
jTimestamp.put(JSON_TIMESTAMP, timestamp.t);
if (timestamp.arrivalDiffMs != null) {
jTimestamp.put(JSON_ARRIVAL_DIFF, timestamp.arrivalDiffMs);
}
if (timestamp.tripId != null) {
jTimestamp.put(JSON_TRIP_ID, timestamp.tripId);
}
if (timestamp.headsignType != Direction.HEADSIGN_TYPE_NONE && timestamp.headsignValue != null) {
jTimestamp.put(JSON_HEADSIGN_TYPE, timestamp.headsignType);
jTimestamp.put(JSON_HEADSIGN_VALUE, timestamp.headsignValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ public String getLogTag() {
*/
public static final String DB_NAME = "gtfs_rts.db"; // do not change to avoid breaking compat w/ old modules

static final String T_STRINGS = GTFSCommons.T_STRINGS;
static final String T_STRINGS_K_ID = GTFSCommons.T_STRINGS_K_ID;
static final String T_STRINGS_K_STRING = GTFSCommons.T_STRINGS_K_STRING;
public static final String T_STRINGS = GTFSCommons.T_STRINGS;
public static final String T_STRINGS_K_ID = GTFSCommons.T_STRINGS_K_ID;
public static final String T_STRINGS_K_STRING = GTFSCommons.T_STRINGS_K_STRING;
private static final String T_STRINGS_SQL_CREATE = GTFSCommons.getT_STRINGS_SQL_CREATE();
private static final String T_STRINGS_SQL_INSERT = GTFSCommons.getT_STRINGS_SQL_INSERT();
private static final String T_STRINGS_SQL_DROP = GTFSCommons.getT_STRINGS_SQL_DROP();
Expand Down Expand Up @@ -93,6 +93,13 @@ public String getLogTag() {
private static final String T_DIRECTION_STOPS_SQL_INSERT = GTFSCommons.getT_DIRECTION_STOPS_SQL_INSERT();
private static final String T_DIRECTION_STOPS_SQL_DROP = GTFSCommons.getT_DIRECTION_STOPS_SQL_DROP();

public static final String T_TRIP_IDS = GTFSCommons.T_TRIP_IDS;
public static final String T_TRIP_IDS_K_ID = GTFSCommons.T_TRIP_IDS_K_ID;
public static final String T_TRIP_IDS_K_ID_INT = GTFSCommons.T_TRIP_IDS_K_ID_INT;
private static final String T_TRIP_IDS_SQL_CREATE = GTFSCommons.getT_TRIP_IDS_SQL_CREATE();
private static final String T_TRIP_IDS_SQL_INSERT = GTFSCommons.getT_TRIP_IDS_SQL_INSERT();
private static final String T_TRIP_IDS_SQL_DROP = GTFSCommons.getT_TRIP_IDS_SQL_DROP();

@SuppressWarnings("WeakerAccess")
static final String T_SERVICE_IDS = GTFSCommons.T_SERVICE_IDS;
@SuppressWarnings("unused") // not used by main app currently
Expand Down Expand Up @@ -150,6 +157,9 @@ public void onUpgradeMT(@NonNull SQLiteDatabase db, int oldVersion, int newVersi
if (FeatureFlags.F_EXPORT_SERVICE_ID_INTS) {
db.execSQL(T_SERVICE_IDS_SQL_DROP);
}
if (FeatureFlags.F_EXPORT_TRIP_ID_INTS) {
db.execSQL(T_TRIP_IDS_SQL_DROP);
}
db.execSQL(T_SERVICE_DATES_SQL_DROP);
db.execSQL(T_ROUTE_DIRECTION_STOP_STATUS_SQL_DROP);
initAllDbTables(db, true);
Expand All @@ -163,8 +173,11 @@ public boolean isDbExist(@NonNull Context context) {
private void initAllDbTables(@NonNull SQLiteDatabase db, boolean upgrade) {
MTLog.i(this, "Data: deploying DB...");
final int nId = TimeUtils.currentTimeSec();
final int nbTotalOperations = 8;
int progress = 0;
final long startInMs = TimeUtils.currentTimeMillis();
int nbTotalOperations = 7;
if (FeatureFlags.F_EXPORT_SERVICE_ID_INTS) nbTotalOperations++;
if (FeatureFlags.F_EXPORT_TRIP_ID_INTS) nbTotalOperations++;
int progress = -1;
final NotificationManagerCompat nm = NotificationManagerCompat.from(this.context);
final boolean notifEnabled = nm.areNotificationsEnabled();
final NotificationCompat.Builder nb;
Expand All @@ -180,38 +193,58 @@ private void initAllDbTables(@NonNull SQLiteDatabase db, boolean upgrade) {
nb = null;
}
db.execSQL(SQLUtils.PRAGMA_AUTO_VACUUM_NONE);
if (notifEnabled) NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, progress++);
if (notifEnabled) NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, ++progress);
final Map<Integer, String> allStrings = new HashMap<>();
if (FeatureFlags.F_EXPORT_STRINGS) {
if (FeatureFlags.F_EXPORT_STRINGS || FeatureFlags.F_EXPORT_SCHEDULE_STRINGS) {
initDbTableWithRetry(context, db, T_STRINGS, T_STRINGS_SQL_CREATE, T_STRINGS_SQL_INSERT, T_STRINGS_SQL_DROP, getStringsFiles(), null, null,
(id, string) -> {
allStrings.put(id, string);
return Unit.INSTANCE;
}
); // 1st
}
if (notifEnabled) NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, progress++);
if (notifEnabled) NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, ++progress);
initDbTableWithRetry(context, db, T_ROUTE, T_ROUTE_SQL_CREATE, T_ROUTE_SQL_INSERT, T_ROUTE_SQL_DROP, getRouteFiles(), allStrings, T_ROUTE_STRINGS_COLUMN_IDX);
if (notifEnabled) NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, progress++);
if (notifEnabled) NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, ++progress);
initDbTableWithRetry(context, db, T_DIRECTION, T_DIRECTION_SQL_CREATE, T_DIRECTION_SQL_INSERT, T_DIRECTION_SQL_DROP, getDirectionFiles(), allStrings, T_DIRECTION_STRINGS_COLUMN_IDX);
if (notifEnabled) NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, progress++);
if (notifEnabled) NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, ++progress);
initDbTableWithRetry(context, db, T_STOP, T_STOP_SQL_CREATE, T_STOP_SQL_INSERT, T_STOP_SQL_DROP, getStopFiles(), allStrings, T_STOP_STRINGS_COLUMN_IDX);
if (notifEnabled) NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, progress++);
if (notifEnabled) NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, ++progress);
initDbTableWithRetry(context, db, T_DIRECTION_STOPS, T_DIRECTION_STOPS_SQL_CREATE, T_DIRECTION_STOPS_SQL_INSERT, T_DIRECTION_STOPS_SQL_DROP, getDirectionStopsFiles());
if (notifEnabled) NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, progress++);
if (notifEnabled) NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, ++progress);
if (FeatureFlags.F_EXPORT_SERVICE_ID_INTS) {
initDbTableWithRetry(context, db, T_SERVICE_IDS, T_SERVICE_IDS_SQL_CREATE, T_SERVICE_IDS_SQL_INSERT, T_SERVICE_IDS_SQL_DROP, getServiceIdsFiles());
}
if (notifEnabled) NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, progress++);
if (notifEnabled) NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, ++progress);
initDbTableWithRetry(context, db, T_SERVICE_DATES, T_SERVICE_DATES_SQL_CREATE, T_SERVICE_DATES_SQL_INSERT, T_SERVICE_DATES_SQL_DROP, getServiceDatesFiles());
if (notifEnabled) NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, progress++);
if (FeatureFlags.F_EXPORT_TRIP_ID_INTS) {
if (notifEnabled) NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, ++progress);
initDbTableWithRetry(context, db, T_TRIP_IDS, T_TRIP_IDS_SQL_CREATE, T_TRIP_IDS_SQL_INSERT, T_TRIP_IDS_SQL_DROP, getTripIdsFiles());
}
if (notifEnabled) NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, ++progress);
db.execSQL(T_ROUTE_DIRECTION_STOP_STATUS_SQL_CREATE);
if (notifEnabled) {
nb.setSmallIcon(android.R.drawable.stat_notify_sync_noanim); //
NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, progress);
nb.setSmallIcon(android.R.drawable.stat_notify_sync_noanim);
NotificationUtils.setProgressAndNotify(nm, nb, nId, nbTotalOperations, nbTotalOperations);
nm.cancel(nId);
}
MTLog.i(this, "Data: deploying DB... DONE");
final long durationInMs = TimeUtils.currentTimeMillis() - startInMs;
MTLog.i(this, "Data: deploying DB... DONE (%s)", MTLog.formatDuration(durationInMs));
}

/**
* Override if multiple {@link GTFSProviderDbHelper} implementations in same app.
*/
private int[] getTripIdsFiles() {
if (GTFSCurrentNextProvider.hasCurrentData(context)) {
if (GTFSCurrentNextProvider.isNextData(context)) {
return new int[]{R.raw.next_gtfs_schedule_trip_ids};
} else { // CURRENT = default
return new int[]{R.raw.current_gtfs_schedule_trip_ids};
}
} else {
return new int[]{R.raw.gtfs_schedule_trip_ids};
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import org.mtransit.android.commons.data.Schedule;
import org.mtransit.android.commons.data.ScheduleTimestamps;
import org.mtransit.android.commons.provider.agency.AgencyUtils;
import org.mtransit.android.commons.provider.gtfs.GTFSStringsUtils;
import org.mtransit.android.commons.provider.gtfs.GTFSTripIdsUtils;
import org.mtransit.commons.FeatureFlags;

import java.util.ArrayList;
Expand Down Expand Up @@ -107,9 +109,12 @@ static ScheduleTimestamps getScheduleTimestamps(@NonNull GTFSProvider provider,
}
startsAt.add(Calendar.DATE, +1); // NEXT DAY
}
if (FeatureFlags.F_EXPORT_STRINGS) {
if (FeatureFlags.F_EXPORT_STRINGS || FeatureFlags.F_EXPORT_SCHEDULE_STRINGS) {
allTimestamps = GTFSStringsUtils.updateStrings(allTimestamps, provider);
}
if (FeatureFlags.F_EXPORT_TRIP_ID_INTS) {
allTimestamps = GTFSTripIdsUtils.updateTripIds(allTimestamps, provider);
}
ScheduleTimestamps scheduleTimestamps = new ScheduleTimestamps(rds.getUUID(), startsAtInMs, endsAtInMs);
scheduleTimestamps.setSourceLabel(GTFSProvider.getSOURCE_LABEL(provider.requireContextCompat()));
scheduleTimestamps.setTimestampsAndSort(allTimestamps);
Expand Down
Loading