From 0ad824520cff9d3e96cfa0702cc952d09514ee6f Mon Sep 17 00:00:00 2001 From: Jeremy D Monin Date: Thu, 13 Sep 2012 17:58:03 -0400 Subject: [PATCH 1/4] Schema v15: Add track.tp_count, wp_count --- .../android/osmtracker/db/DatabaseHelper.java | 12 ++++++++++-- .../android/osmtracker/db/TrackContentProvider.java | 10 +++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) 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..5fdcdbd1 100644 --- a/src/me/guillaumin/android/osmtracker/db/TrackContentProvider.java +++ b/src/me/guillaumin/android/osmtracker/db/TrackContentProvider.java @@ -444,8 +444,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 From 58bc7e26e19d78ec37015f70a07f96c97c0f0489 Mon Sep 17 00:00:00 2001 From: Jeremy D Monin Date: Thu, 13 Sep 2012 19:22:52 -0400 Subject: [PATCH 2/4] TrackContentProvider: get track point counts from new URIs, not inner join --- .../osmtracker/db/TrackContentProvider.java | 66 ++++++++++++++++++- .../android/osmtracker/db/model/Track.java | 47 ++++++++++++- 2 files changed, 107 insertions(+), 6 deletions(-) diff --git a/src/me/guillaumin/android/osmtracker/db/TrackContentProvider.java b/src/me/guillaumin/android/osmtracker/db/TrackContentProvider.java index 5fdcdbd1..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); } @@ -465,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/model/Track.java b/src/me/guillaumin/android/osmtracker/db/model/Track.java index aeb992e9..f273a85b 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 @@ -88,9 +91,47 @@ 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)); + final boolean readPointCounts = true; + 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(); From 373d926dd0103419373fbbeafde08aac8c86c873 Mon Sep 17 00:00:00 2001 From: Jeremy D Monin Date: Thu, 13 Sep 2012 19:56:06 -0400 Subject: [PATCH 3/4] Track.build: Read point counts only when needed --- .../android/osmtracker/activity/OpenStreetMapUpload.java | 2 +- .../android/osmtracker/activity/TrackDetail.java | 2 +- src/me/guillaumin/android/osmtracker/db/DataHelper.java | 5 +++++ .../guillaumin/android/osmtracker/db/TracklistAdapter.java | 2 +- src/me/guillaumin/android/osmtracker/db/model/Track.java | 7 +++++-- 5 files changed, 13 insertions(+), 5 deletions(-) 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/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 f273a85b..347dbf63 100644 --- a/src/me/guillaumin/android/osmtracker/db/model/Track.java +++ b/src/me/guillaumin/android/osmtracker/db/model/Track.java @@ -71,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; @@ -91,7 +95,6 @@ public static Track build(final long trackId, Cursor tc, ContentResolver cr, boo out.visibility = OSMVisibility.valueOf(tc.getString(tc.getColumnIndex(Schema.COL_OSM_VISIBILITY))); - final boolean readPointCounts = true; if (readPointCounts) { final boolean trackInactive = (tc.getInt(tc.getColumnIndex(Schema.COL_ACTIVE)) == Schema.VAL_TRACK_INACTIVE); boolean countedAlready = trackInactive; From fbf9323611422adfbf69d00312464b3fc4816f5b Mon Sep 17 00:00:00 2001 From: Jeremy D Monin Date: Fri, 18 Oct 2013 07:02:50 -0400 Subject: [PATCH 4/4] classpath add com.android.ide.eclipse.adt.DEPENDENCIES --- .classpath | 1 + 1 file changed, 1 insertion(+) diff --git a/.classpath b/.classpath index b09fd4a7..c089de00 100644 --- a/.classpath +++ b/.classpath @@ -12,5 +12,6 @@ +