diff --git a/src/main/java/de/dennisguse/opentracks/TrackListActivity.java b/src/main/java/de/dennisguse/opentracks/TrackListActivity.java index af7014a87..4259bbbda 100644 --- a/src/main/java/de/dennisguse/opentracks/TrackListActivity.java +++ b/src/main/java/de/dennisguse/opentracks/TrackListActivity.java @@ -42,11 +42,11 @@ import androidx.core.app.ActivityCompat; import androidx.cursoradapter.widget.ResourceCursorAdapter; import androidx.loader.app.LoaderManager; import androidx.loader.app.LoaderManager.LoaderCallbacks; +import androidx.loader.content.CursorLoader; import androidx.loader.content.Loader; import de.dennisguse.opentracks.content.data.Track; import de.dennisguse.opentracks.content.data.TracksColumns; -import de.dennisguse.opentracks.content.provider.ContentProviderUtils; import de.dennisguse.opentracks.databinding.TrackListBinding; import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment; import de.dennisguse.opentracks.services.TrackRecordingServiceConnection; @@ -60,6 +60,7 @@ import de.dennisguse.opentracks.util.ListItemUtils; import de.dennisguse.opentracks.util.PreferencesUtils; import de.dennisguse.opentracks.util.StringUtils; import de.dennisguse.opentracks.util.TrackIconUtils; +import de.dennisguse.opentracks.util.TrackUtils; /** * An activity displaying a list of tracks. @@ -71,7 +72,6 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe private static final String TAG = TrackListActivity.class.getSimpleName(); // The following are set in onCreate - private ContentProviderUtils contentProviderUtils; private SharedPreferences sharedPreferences; private TrackRecordingServiceConnection trackRecordingServiceConnection; private TrackController trackController; @@ -83,7 +83,11 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe private final LoaderCallbacks loaderCallbacks = new LoaderCallbacks() { @Override public Loader onCreateLoader(int arg0, Bundle arg1) { - return ContentProviderUtils.getTracksCursorLoader(TrackListActivity.this); + String[] PROJECTION = new String[]{TracksColumns._ID, TracksColumns.NAME, + TracksColumns.DESCRIPTION, TracksColumns.CATEGORY, TracksColumns.STARTTIME, + TracksColumns.TOTALDISTANCE, TracksColumns.TOTALTIME, TracksColumns.ICON, "markerCount"}; + + return new CursorLoader(TrackListActivity.this, TracksColumns.CONTENT_URI, PROJECTION, null, null, TrackUtils.TRACK_SORT_ORDER); } @Override @@ -224,7 +228,6 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe recordingTrackPaused = PreferencesUtils.isRecordingTrackPausedDefault(this); - contentProviderUtils = new ContentProviderUtils(this); sharedPreferences = PreferencesUtils.getSharedPreferences(this); trackRecordingServiceConnection = new TrackRecordingServiceConnection(bindChangedCallback); @@ -256,14 +259,15 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe resourceCursorAdapter = new ResourceCursorAdapter(this, R.layout.list_item, null, 0) { @Override public void bindView(View view, Context context, Cursor cursor) { - int idIndex = cursor.getColumnIndex(TracksColumns._ID); - int iconIndex = cursor.getColumnIndex(TracksColumns.ICON); - int nameIndex = cursor.getColumnIndex(TracksColumns.NAME); + int idIndex = cursor.getColumnIndexOrThrow(TracksColumns._ID); + int iconIndex = cursor.getColumnIndexOrThrow(TracksColumns.ICON); + int nameIndex = cursor.getColumnIndexOrThrow(TracksColumns.NAME); int totalTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.TOTALTIME); int totalDistanceIndex = cursor.getColumnIndexOrThrow(TracksColumns.TOTALDISTANCE); int startTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.STARTTIME); - int categoryIndex = cursor.getColumnIndex(TracksColumns.CATEGORY); - int descriptionIndex = cursor.getColumnIndex(TracksColumns.DESCRIPTION); + int categoryIndex = cursor.getColumnIndexOrThrow(TracksColumns.CATEGORY); + int descriptionIndex = cursor.getColumnIndexOrThrow(TracksColumns.DESCRIPTION); + int markerCountIndex = cursor.getColumnIndexOrThrow(TracksColumns.MARKER_COUNT); Track.Id trackId = new Track.Id(cursor.getLong(idIndex)); boolean isRecording = trackId.equals(recordingTrackId); @@ -272,7 +276,7 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe String name = cursor.getString(nameIndex); String totalTime = StringUtils.formatElapsedTime(cursor.getLong(totalTimeIndex)); String totalDistance = StringUtils.formatDistance(TrackListActivity.this, cursor.getDouble(totalDistanceIndex), metricUnits); - int markerCount = contentProviderUtils.getMarkerCount(trackId); + int markerCount = cursor.getInt(markerCountIndex); long startTime = cursor.getLong(startTimeIndex); String category = icon != null && !icon.equals("") ? null : cursor.getString(categoryIndex); String description = cursor.getString(descriptionIndex); diff --git a/src/main/java/de/dennisguse/opentracks/content/data/TracksColumns.java b/src/main/java/de/dennisguse/opentracks/content/data/TracksColumns.java index d7e67fdd2..14c7e4228 100644 --- a/src/main/java/de/dennisguse/opentracks/content/data/TracksColumns.java +++ b/src/main/java/de/dennisguse/opentracks/content/data/TracksColumns.java @@ -35,12 +35,13 @@ public interface TracksColumns extends BaseColumns { String DEFAULT_SORT_ORDER = _ID; // Columns - String UUID = "uuid"; + String UUID = "uuid"; // identifier to make tracks globally unique (prevent re-import) String NAME = "name"; // track name String DESCRIPTION = "description"; // track description String CATEGORY = "category"; // track activity type String STARTTIME = "starttime"; // track start time String STOPTIME = "stoptime"; // track stop time + String MARKER_COUNT = "markerCount"; // the numbers of markers (virtual column) @Deprecated String NUMPOINTS = "numpoints"; // number of track points //TODO UNUSED String TOTALDISTANCE = "totaldistance"; // total distance @@ -55,25 +56,25 @@ public interface TracksColumns extends BaseColumns { String ELEVATIONGAIN = "elevationgain"; // elevation gain String ICON = "icon"; // track activity type icon - String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" // table - + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " // id - + NAME + " TEXT, " // name - + DESCRIPTION + " TEXT, " // description - + CATEGORY + " TEXT, " // category - + STARTTIME + " INTEGER, " // start time - + STOPTIME + " INTEGER, " // stop time - + NUMPOINTS + " INTEGER, " // num points - + TOTALDISTANCE + " FLOAT, " // total distance - + TOTALTIME + " INTEGER, " // total time - + MOVINGTIME + " INTEGER, " // moving time - + AVGSPEED + " FLOAT, " // average speed - + AVGMOVINGSPEED + " FLOAT, " // average moving speed - + MAXSPEED + " FLOAT, " // max speed - + MINELEVATION + " FLOAT, " // min elevation - + MAXELEVATION + " FLOAT, " // max elevation - + ELEVATIONGAIN + " FLOAT, " // elevation gain - + ICON + " TEXT, " // icon - + UUID + " BLOB)"; // UUID + String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + NAME + " TEXT, " + + DESCRIPTION + " TEXT, " + + CATEGORY + " TEXT, " + + STARTTIME + " INTEGER, " + + STOPTIME + " INTEGER, " + + NUMPOINTS + " INTEGER, " + + TOTALDISTANCE + " FLOAT, " + + TOTALTIME + " INTEGER, " + + MOVINGTIME + " INTEGER, " + + AVGSPEED + " FLOAT, " + + AVGMOVINGSPEED + " FLOAT, " + + MAXSPEED + " FLOAT, " + + MINELEVATION + " FLOAT, " + + MAXELEVATION + " FLOAT, " + + ELEVATIONGAIN + " FLOAT, " + + ICON + " TEXT, " + + UUID + " BLOB)"; String CREATE_TABLE_INDEX = "CREATE UNIQUE INDEX " + TABLE_NAME + "_" + UUID + "_index ON " + TABLE_NAME + "(" + UUID + ")"; diff --git a/src/main/java/de/dennisguse/opentracks/content/provider/ContentProviderUtils.java b/src/main/java/de/dennisguse/opentracks/content/provider/ContentProviderUtils.java index 969df8910..25313dc8c 100644 --- a/src/main/java/de/dennisguse/opentracks/content/provider/ContentProviderUtils.java +++ b/src/main/java/de/dennisguse/opentracks/content/provider/ContentProviderUtils.java @@ -47,7 +47,6 @@ import de.dennisguse.opentracks.content.data.TrackPointsColumns; import de.dennisguse.opentracks.content.data.TracksColumns; import de.dennisguse.opentracks.stats.TrackStatistics; import de.dennisguse.opentracks.util.FileUtils; -import de.dennisguse.opentracks.util.TrackUtils; import de.dennisguse.opentracks.util.UUIDUtils; /** @@ -220,14 +219,6 @@ public class ContentProviderUtils { return tracks; } - public static Loader getTracksCursorLoader(Context context) { - String[] PROJECTION = new String[]{TracksColumns._ID, TracksColumns.NAME, - TracksColumns.DESCRIPTION, TracksColumns.CATEGORY, TracksColumns.STARTTIME, - TracksColumns.TOTALDISTANCE, TracksColumns.TOTALTIME, TracksColumns.ICON}; - - return new CursorLoader(context, TracksColumns.CONTENT_URI, PROJECTION, null, null, TrackUtils.TRACK_SORT_ORDER); - } - @Deprecated //TODO Do not use; rather get the proper TrackId (e.g., resume a track might give you some weird effects). @VisibleForTesting @@ -498,7 +489,7 @@ public class ContentProviderUtils { } } - @Deprecated //TODO Expose information via Cursor + @Deprecated //TODO TracksColumns.MARKER_COUNT while querying for tracks public int getMarkerCount(Track.Id trackId) { if (!trackId.isValid()) { return 0; diff --git a/src/main/java/de/dennisguse/opentracks/content/provider/CustomContentProvider.java b/src/main/java/de/dennisguse/opentracks/content/provider/CustomContentProvider.java index 6df820754..cad2a15d9 100644 --- a/src/main/java/de/dennisguse/opentracks/content/provider/CustomContentProvider.java +++ b/src/main/java/de/dennisguse/opentracks/content/provider/CustomContentProvider.java @@ -33,6 +33,8 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; +import java.util.Arrays; + import de.dennisguse.opentracks.content.data.MarkerColumns; import de.dennisguse.opentracks.content.data.TrackPointsColumns; import de.dennisguse.opentracks.content.data.TracksColumns; @@ -210,7 +212,11 @@ public class CustomContentProvider extends ContentProvider { queryBuilder.appendWhere(TrackPointsColumns.TRACKID + " IN (" + TextUtils.join(SQL_LIST_DELIMITER, ContentProviderUtils.parseTrackIdsFromUri(url)) + ")"); break; case TRACKS: - queryBuilder.setTables(TracksColumns.TABLE_NAME); + if (projection != null && Arrays.asList(projection).contains(TracksColumns.MARKER_COUNT)) { + queryBuilder.setTables(TracksColumns.TABLE_NAME + " LEFT OUTER JOIN (SELECT " + MarkerColumns.TRACKID + " AS markerTrackId, COUNT(*) AS " + TracksColumns.MARKER_COUNT + " FROM " + MarkerColumns.TABLE_NAME + " GROUP BY " + MarkerColumns.TRACKID + ") ON (" + TracksColumns.TABLE_NAME + "." + TracksColumns._ID + "= markerTrackId)"); + } else { + queryBuilder.setTables(TracksColumns.TABLE_NAME); + } sortOrder = sort != null ? sort : TracksColumns.DEFAULT_SORT_ORDER; break; case TRACKS_BY_ID: @@ -291,11 +297,6 @@ public class CustomContentProvider extends ContentProvider { return count; } - /** - * Gets the {@link UrlType} for a url. - * - * @param url the url - */ @NonNull private UrlType getUrlType(Uri url) { UrlType[] urlTypes = UrlType.values(); @@ -327,12 +328,6 @@ public class CustomContentProvider extends ContentProvider { } } - /** - * Inserts a track point. - * - * @param url the content url - * @param values the content values - */ private Uri insertTrackPoint(Uri url, ContentValues values) { boolean hasLatitude = values.containsKey(TrackPointsColumns.LATITUDE); boolean hasLongitude = values.containsKey(TrackPointsColumns.LONGITUDE); @@ -347,12 +342,6 @@ public class CustomContentProvider extends ContentProvider { throw new SQLiteException("Failed to insert a track point " + url); } - /** - * Inserts a track. - * - * @param url the content url - * @param contentValues the content values - */ private Uri insertTrack(Uri url, ContentValues contentValues) { boolean hasStartTime = contentValues.containsKey(TracksColumns.STARTTIME); if (!hasStartTime) {