diff --git a/.classpath b/.classpath
index b09fd4a7..c089de00 100644
--- a/.classpath
+++ b/.classpath
@@ -12,5 +12,6 @@
+
diff --git a/src/me/guillaumin/android/osmtracker/activity/OpenStreetMapUpload.java b/src/me/guillaumin/android/osmtracker/activity/OpenStreetMapUpload.java
index 7255521a..3a655243 100644
--- a/src/me/guillaumin/android/osmtracker/activity/OpenStreetMapUpload.java
+++ b/src/me/guillaumin/android/osmtracker/activity/OpenStreetMapUpload.java
@@ -116,7 +116,7 @@ protected void onResume() {
return; // <--- Early return ---
}
- bindTrack(Track.build(trackId, cursor, getContentResolver(), false));
+ bindTrack(Track.build(trackId, cursor, getContentResolver(), false, false));
Uri uri = getIntent().getData();
Log.d(TAG, "URI: " + uri);
diff --git a/src/me/guillaumin/android/osmtracker/activity/TrackDetail.java b/src/me/guillaumin/android/osmtracker/activity/TrackDetail.java
index 8d593294..05e8d73c 100644
--- a/src/me/guillaumin/android/osmtracker/activity/TrackDetail.java
+++ b/src/me/guillaumin/android/osmtracker/activity/TrackDetail.java
@@ -122,7 +122,7 @@ protected void onResume() {
// Bind WP count, TP count, start date, etc.
// Fill name-field only if empty (in case changed by user/restored by onRestoreInstanceState)
- Track t = Track.build(trackId, cursor, cr, true);
+ Track t = Track.build(trackId, cursor, cr, true, true);
bindTrack(t);
diff --git a/src/me/guillaumin/android/osmtracker/db/DataHelper.java b/src/me/guillaumin/android/osmtracker/db/DataHelper.java
index 73e4ba3d..1dcd0572 100644
--- a/src/me/guillaumin/android/osmtracker/db/DataHelper.java
+++ b/src/me/guillaumin/android/osmtracker/db/DataHelper.java
@@ -218,6 +218,11 @@ public void stopTracking(long trackId) {
ContentValues values = new ContentValues();
values.put(Schema.COL_ACTIVE, Schema.VAL_TRACK_INACTIVE);
contentResolver.update(trackUri, values, null, null);
+
+ // The next time TrackManager displays this track in the list,
+ // Track.build will count the trackpoints and waypoints and
+ // save them to the track's tp_count and wp_count columns.
+ // We don't need to do that here.
}
/**
diff --git a/src/me/guillaumin/android/osmtracker/db/DatabaseHelper.java b/src/me/guillaumin/android/osmtracker/db/DatabaseHelper.java
index c3bf55b8..e938b9c1 100644
--- a/src/me/guillaumin/android/osmtracker/db/DatabaseHelper.java
+++ b/src/me/guillaumin/android/osmtracker/db/DatabaseHelper.java
@@ -88,7 +88,9 @@ public class DatabaseHelper extends SQLiteOpenHelper {
+ Schema.COL_DIR + " text," // unused since DB_VERSION 13, since SQLite doesn't support to remove a column it will stay for now
+ Schema.COL_ACTIVE + " integer not null default 0,"
+ Schema.COL_EXPORT_DATE + " long," // null indicates not yet exported
- + Schema.COL_OSM_UPLOAD_DATE + " long" // null indicates not yet uploaded
+ + Schema.COL_OSM_UPLOAD_DATE + " long," // null indicates not yet uploaded
+ + Schema.COL_TRACKPOINT_COUNT + " integer," // null indicates active track or not yet calculated
+ + Schema.COL_WAYPOINT_COUNT + " integer" // null indicates active track or not yet calculated
+ ")";
/**
@@ -112,9 +114,10 @@ public class DatabaseHelper extends SQLiteOpenHelper {
* v13: TBL_TRACK.COL_DIR is now deprecated (rxxx) v0.5.3 TODO: fill in correct revision and version
* v14: add TBL_TRACK.COL_OSM_UPLOAD_DATE, TBL_TRACK.COL_DESCRIPTION,
* TBL_TRACK.COL_TAGS and TBL_TRACK.COL_OSM_VISIBILITY for OSM upload - v0.6.0
+ * v15: add TBL_TRACK.COL_TRACKPOINT_COUNT, COL_WAYPOINT_COUNT
*
*/
- private static final int DB_VERSION = 14;
+ private static final int DB_VERSION = 15;
public DatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
@@ -132,6 +135,7 @@ public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_TABLE_TRACK);
}
+ /** Upgrade an existing db to the latest {@link #DB_VERSION}. */
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch(oldVersion){
@@ -157,6 +161,10 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("alter table " + Schema.TBL_TRACK + " add column " + Schema.COL_TAGS + " text");
db.execSQL("alter table " + Schema.TBL_TRACK + " add column " + Schema.COL_OSM_VISIBILITY
+ " text default '"+OSMVisibility.Private+"'");
+ case 14:
+ // Create 'tp_count', 'wp_count'
+ db.execSQL("alter table " + Schema.TBL_TRACK + " add column " + Schema.COL_TRACKPOINT_COUNT + " integer");
+ db.execSQL("alter table " + Schema.TBL_TRACK + " add column " + Schema.COL_WAYPOINT_COUNT + " integer");
}
}
diff --git a/src/me/guillaumin/android/osmtracker/db/TrackContentProvider.java b/src/me/guillaumin/android/osmtracker/db/TrackContentProvider.java
index 868e9cb0..9917947d 100644
--- a/src/me/guillaumin/android/osmtracker/db/TrackContentProvider.java
+++ b/src/me/guillaumin/android/osmtracker/db/TrackContentProvider.java
@@ -48,7 +48,7 @@ public class TrackContentProvider extends ContentProvider {
/**
* tables and joins to be used within a query to get the important informations of a track
*/
- private static final String TRACK_TABLES = Schema.TBL_TRACK + " left join " + Schema.TBL_TRACKPOINT + " on " + Schema.TBL_TRACK + "." + Schema.COL_ID + " = " + Schema.TBL_TRACKPOINT + "." + Schema.COL_TRACK_ID;
+ private static final String TRACK_TABLES = Schema.TBL_TRACK;
/**
* the projection to be used to get the important informations of a track
@@ -64,10 +64,15 @@ public class TrackContentProvider extends ContentProvider {
Schema.COL_TAGS,
Schema.COL_OSM_VISIBILITY,
Schema.COL_START_DATE,
- "count(" + Schema.TBL_TRACKPOINT + "." + Schema.COL_ID + ") as " + Schema.COL_TRACKPOINT_COUNT,
- "(SELECT count("+Schema.TBL_WAYPOINT+"."+Schema.COL_TRACK_ID+") FROM "+Schema.TBL_WAYPOINT+" WHERE "+Schema.TBL_WAYPOINT+"."+Schema.COL_TRACK_ID+" = " + Schema.TBL_TRACK + "." + Schema.COL_ID + ") as " + Schema.COL_WAYPOINT_COUNT
+ Schema.COL_TRACKPOINT_COUNT,
+ Schema.COL_WAYPOINT_COUNT
};
+ /**
+ * Projection with one column: count(*).
+ */
+ private static final String[] ROWCOUNT_PROJECTION = { "count(*)" };
+
/**
* the group by statement that is used for the track statements
*/
@@ -88,6 +93,8 @@ public class TrackContentProvider extends ContentProvider {
uriMatcher.addURI(AUTHORITY, Schema.TBL_TRACK + "/#/" + Schema.TBL_WAYPOINT + "s", Schema.URI_CODE_TRACK_WAYPOINTS);
uriMatcher.addURI(AUTHORITY, Schema.TBL_TRACK + "/#/" + Schema.TBL_TRACKPOINT + "s", Schema.URI_CODE_TRACK_TRACKPOINTS);
uriMatcher.addURI(AUTHORITY, Schema.TBL_WAYPOINT + "/uuid/*", Schema.URI_CODE_WAYPOINT_UUID);
+ uriMatcher.addURI(AUTHORITY, Schema.TBL_TRACK + "/#/tpcount", Schema.URI_CODE_TRACK_TP_COUNT);
+ uriMatcher.addURI(AUTHORITY, Schema.TBL_TRACK + "/#/wpcount", Schema.URI_CODE_TRACK_WP_COUNT);
}
@@ -131,6 +138,34 @@ public static final Uri trackEndUri(long trackId) {
"end" );
}
+ /**
+ * Get a URI for the track's trackpoint count in the {@link Schema#TBL_TRACKPOINT} table.
+ * This queries and calculates using SQL COUNT(*), it does not use the track table's
+ * {@link Schema#COL_TRACKPOINT_COUNT} field.
+ * @param trackId target track id
+ * @return Uri for the trackpoint count of the track
+ * @since schema 15
+ */
+ public static final Uri trackTrackpointCountUri(long trackId) {
+ return Uri.withAppendedPath(
+ ContentUris.withAppendedId(CONTENT_URI_TRACK, trackId),
+ "tpcount" ); // URI_CODE_TRACK_TP_COUNT
+ }
+
+ /**
+ * Get a URI for the track's waypoint count in the {@link Schema#TBL_WAYPOINT} table.
+ * This queries and calculates using SQL COUNT(*), it does not use the track table's
+ * {@link Schema#COL_WAYPOINT_COUNT} field.
+ * @param trackId target track id
+ * @return Uri for the waypoint count of the track
+ * @since schema 15
+ */
+ public static final Uri trackWaypointCountUri(long trackId) {
+ return Uri.withAppendedPath(
+ ContentUris.withAppendedId(CONTENT_URI_TRACK, trackId),
+ "wpcount" ); // URI_CODE_TRACK_WP_COUNT
+ }
+
/**
* Database Helper
*/
@@ -356,6 +391,29 @@ public Cursor query(Uri uri, String[] projection, String selectionIn, String[] s
selection = Schema.COL_ACTIVE + " = ?";
selectionArgs = new String[] {Integer.toString(Schema.VAL_TRACK_ACTIVE)};
break;
+ case Schema.URI_CODE_TRACK_TP_COUNT:
+ if (selectionIn != null || selectionArgsIn != null) {
+ // Any selection/selectionArgs will be rejected
+ throw new UnsupportedOperationException();
+ }
+ trackId = uri.getPathSegments().get(1);
+ qb.setTables(Schema.TBL_TRACKPOINT);
+ projection = ROWCOUNT_PROJECTION;
+ selection = Schema.COL_TRACK_ID + " = ?";
+ selectionArgs = new String[] {trackId};
+ break;
+ case Schema.URI_CODE_TRACK_WP_COUNT:
+ if (selectionIn != null || selectionArgsIn != null) {
+ // Any selection/selectionArgs will be rejected
+ throw new UnsupportedOperationException();
+ }
+ trackId = uri.getPathSegments().get(1);
+ qb.setTables(Schema.TBL_WAYPOINT);
+ projection = ROWCOUNT_PROJECTION;
+ selection = Schema.COL_TRACK_ID + " = ?";
+ selectionArgs = new String[] {trackId};
+ break;
+
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
@@ -444,8 +502,16 @@ public static final class Schema {
public static final String COL_EXPORT_DATE = "export_date";
public static final String COL_OSM_UPLOAD_DATE = "osm_upload_date";
- // virtual colums that are used in some sqls but dont exist in database
+ /**
+ * A track's calculated trackpoint count, or null if active. Before schema 15,
+ * this was a virtual column used in some SQLs that didn't exist in the database.
+ * @since 15
+ */
public static final String COL_TRACKPOINT_COUNT = "tp_count";
+ /**
+ * A track's calculated waypoint count, or null if active.
+ * @since 15
+ */
public static final String COL_WAYPOINT_COUNT = "wp_count";
// Codes for UriMatcher
@@ -457,6 +523,8 @@ public static final class Schema {
public static final int URI_CODE_WAYPOINT_UUID = 8;
public static final int URI_CODE_TRACK_START = 9;
public static final int URI_CODE_TRACK_END = 10;
+ private static final int URI_CODE_TRACK_TP_COUNT = 11; // query only
+ private static final int URI_CODE_TRACK_WP_COUNT = 12; // query only
public static final int VAL_TRACK_ACTIVE = 1;
diff --git a/src/me/guillaumin/android/osmtracker/db/TracklistAdapter.java b/src/me/guillaumin/android/osmtracker/db/TracklistAdapter.java
index 06f9cff7..a3f43c48 100644
--- a/src/me/guillaumin/android/osmtracker/db/TracklistAdapter.java
+++ b/src/me/guillaumin/android/osmtracker/db/TracklistAdapter.java
@@ -82,7 +82,7 @@ private View bind(Cursor cursor, View v, Context context) {
vId.setText("#" + strTrackId);
// Bind WP count, TP count, name
- Track t = Track.build(trackId, cursor, context.getContentResolver(), false);
+ Track t = Track.build(trackId, cursor, context.getContentResolver(), true, false);
vTps.setText(Integer.toString(t.getTpCount()));
vWps.setText(Integer.toString(t.getWpCount()));
vNameOrStartDate.setText(t.getName());
diff --git a/src/me/guillaumin/android/osmtracker/db/model/Track.java b/src/me/guillaumin/android/osmtracker/db/model/Track.java
index aeb992e9..347dbf63 100644
--- a/src/me/guillaumin/android/osmtracker/db/model/Track.java
+++ b/src/me/guillaumin/android/osmtracker/db/model/Track.java
@@ -10,7 +10,10 @@
import me.guillaumin.android.osmtracker.db.TrackContentProvider;
import me.guillaumin.android.osmtracker.db.TrackContentProvider.Schema;
import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
import android.database.Cursor;
+import android.net.Uri;
/**
* Represents a Track
@@ -68,10 +71,14 @@ public static OSMVisibility fromPosition(int position) {
* @param trackId id of the track that will be built
* @param tc cursor that is used to build the track
* @param cr the content resolver to use
+ * @param readPointCounts if trackpoint/waypoint counts will be needed; may be more work for the database.
+ * If the track table's tp_count and wp_count fields are null, or the track is active,
+ * the points are counted with SQL COUNT(*) select statements. The counts will then be
+ * saved to tp_count and wp_count unless the track is active.
* @param withExtraInformation if additional informations (startDate, endDate, first and last track point will be loaded from the database
* @return Track
*/
- public static Track build(final long trackId, Cursor tc, ContentResolver cr, boolean withExtraInformation) {
+ public static Track build(final long trackId, Cursor tc, ContentResolver cr, final boolean readPointCounts, boolean withExtraInformation) {
Track out = new Track();
out.trackId = trackId;
@@ -88,9 +95,46 @@ public static Track build(final long trackId, Cursor tc, ContentResolver cr, boo
out.visibility = OSMVisibility.valueOf(tc.getString(tc.getColumnIndex(Schema.COL_OSM_VISIBILITY)));
- out.tpCount = tc.getInt(tc.getColumnIndex(Schema.COL_TRACKPOINT_COUNT));
-
- out.wpCount = tc.getInt(tc.getColumnIndex(Schema.COL_WAYPOINT_COUNT));
+ if (readPointCounts) {
+ final boolean trackInactive = (tc.getInt(tc.getColumnIndex(Schema.COL_ACTIVE)) == Schema.VAL_TRACK_INACTIVE);
+ boolean countedAlready = trackInactive;
+ if (countedAlready) {
+ // try to retrieve from tp_count, wp_count columns
+ final int idx_tp = tc.getColumnIndex(Schema.COL_TRACKPOINT_COUNT),
+ idx_wp = tc.getColumnIndex(Schema.COL_WAYPOINT_COUNT);
+ if (tc.isNull(idx_tp) || tc.isNull(idx_wp)) {
+ countedAlready = false;
+ } else {
+ out.tpCount = tc.getInt(idx_tp);
+ out.wpCount = tc.getInt(idx_wp);
+ }
+ }
+
+ if (! countedAlready) {
+ Cursor pcc = cr.query(TrackContentProvider.trackTrackpointCountUri(trackId), null, null, null, null);
+ if (pcc.moveToFirst())
+ out.tpCount = pcc.getInt(0);
+ else
+ out.tpCount = -1;
+ pcc.close();
+
+ pcc = cr.query(TrackContentProvider.trackWaypointCountUri(trackId), null, null, null, null);
+ if (pcc.moveToFirst())
+ out.wpCount = pcc.getInt(0);
+ else
+ out.wpCount = -1;
+ pcc.close();
+
+ if (trackInactive && (out.tpCount != -1) && (out.wpCount != -1)) {
+ // remember those counts in track table
+ Uri trackUri = ContentUris.withAppendedId(TrackContentProvider.CONTENT_URI_TRACK, trackId);
+ ContentValues values = new ContentValues();
+ values.put(Schema.COL_TRACKPOINT_COUNT, out.tpCount);
+ values.put(Schema.COL_WAYPOINT_COUNT, out.wpCount);
+ cr.update(trackUri, values, null, null);
+ }
+ }
+ }
if(withExtraInformation){
out.readExtraInformation();