/*------------------------------------------------------------------------------ ** Ident: Innovation en Inspiration > Google Android ** Author: rene ** Copyright: (c) Jan 22, 2009 Sogeti Nederland B.V. All Rights Reserved. **------------------------------------------------------------------------------ ** Sogeti Nederland B.V. | No part of this file may be reproduced ** Distributed Software Engineering | or transmitted in any form or by any ** Lange Dreef 17 | means, electronic or mechanical, for the ** 4131 NJ Vianen | purpose, without the express written ** The Netherlands | permission of the copyright holder. *------------------------------------------------------------------------------ * * This file is part of OpenGPSTracker. * * OpenGPSTracker is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenGPSTracker is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenGPSTracker. If not, see <http://www.gnu.org/licenses/>. * */ package nl.sogeti.android.gpstracker.db; import java.util.List; import nl.sogeti.android.gpstracker.db.GPStracking.Segments; import nl.sogeti.android.gpstracker.db.GPStracking.Tracks; import nl.sogeti.android.gpstracker.db.GPStracking.Waypoints; import nl.sogeti.android.gpstracker.db.GPStracking.WaypointsColumns; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteQueryBuilder; import android.location.Location; import android.net.Uri; import android.util.Log; /** * Goal of this Content Provider is to make the GPS Tracking information uniformly * available to this application and even other applications. The GPS-tracking * database can hold, tracks, segments or waypoints * <p> * A track is an actual route taken from start to finish. All the GPS locations * collected are waypoints. Waypoints taken in sequence without loss of GPS-signal * are considered connected and are grouped in segments. A route is build up out of * 1 or more segments. * <p> * For example:<br> * <code>content://nl.sogeti.android.gpstracker/tracks</code> * is the URI that returns all the stored tracks or starts a new track on insert * <p> * <code>content://nl.sogeti.android.gpstracker/tracks/2</code> * is the URI string that would return a single result row, the track with ID = 23. * <p> * <code>content://nl.sogeti.android.gpstracker/tracks/2/segments</code> is the URI that returns * all the stored segments of a track with ID = 2 or starts a new segment on insert * <p> * <code>content://nl.sogeti.android.gpstracker/tracks/2/waypoints</code> is the URI that returns * all the stored waypoints of a track with ID = 2 * <p> * <code>content://nl.sogeti.android.gpstracker/tracks/2/segments</code> is the URI that returns * all the stored segments of a track with ID = 2 * <p> * <code>content://nl.sogeti.android.gpstracker/tracks/2/segments/3</code> is * the URI string that would return a single result row, the segment with ID = 3 of a track with ID = 2 . * <p> * <code>content://nl.sogeti.android.gpstracker/tracks/2/segments/1/waypoints</code> is the URI that * returns all the waypoints of a segment 1 of track 2. * <p> * <code>content://nl.sogeti.android.gpstracker/tracks/2/segments/1/waypoints/52</code> is the URI string that * would return a single result row, the waypoint with ID = 52 * * @version $Id: GPStrackingProvider.java 149 2009-11-07 15:27:26Z rcgroot@gmail.com $ * @author rene (c) Jan 22, 2009, Sogeti B.V. */ public class GPStrackingProvider extends ContentProvider { private static final String LOG_TAG = GPStrackingProvider.class.getName(); /* Action types as numbers for using the UriMatcher */ private static final int TRACKS = 1; private static final int TRACK_ID = 2; private static final int TRACK_WAYPOINTS = 3; private static final int SEGMENTS = 8; private static final int SEGMENT_ID = 4; private static final int WAYPOINTS = 7; private static final int WAYPOINT_ID = 6; private static final String TAG = GPStrackingProvider.class.getName(); private static UriMatcher sURIMatcher = new UriMatcher( UriMatcher.NO_MATCH ); /** * Although it is documented that in addURI(null, path, 0) "path" should be an absolute path this does not seem to work. A relative path gets the jobs done and matches an absolute path. */ static { GPStrackingProvider.sURIMatcher = new UriMatcher( UriMatcher.NO_MATCH ); GPStrackingProvider.sURIMatcher.addURI( GPStracking.AUTHORITY, "tracks", GPStrackingProvider.TRACKS ); GPStrackingProvider.sURIMatcher.addURI( GPStracking.AUTHORITY, "tracks/#", GPStrackingProvider.TRACK_ID ); GPStrackingProvider.sURIMatcher.addURI( GPStracking.AUTHORITY, "tracks/#/waypoints", GPStrackingProvider.TRACK_WAYPOINTS ); GPStrackingProvider.sURIMatcher.addURI( GPStracking.AUTHORITY, "tracks/#/segments", GPStrackingProvider.SEGMENTS ); GPStrackingProvider.sURIMatcher.addURI( GPStracking.AUTHORITY, "tracks/#/segments/#", GPStrackingProvider.SEGMENT_ID ); GPStrackingProvider.sURIMatcher.addURI( GPStracking.AUTHORITY, "tracks/#/segments/#/waypoints", GPStrackingProvider.WAYPOINTS ); GPStrackingProvider.sURIMatcher.addURI( GPStracking.AUTHORITY, "tracks/#/segments/#/waypoints/#", GPStrackingProvider.WAYPOINT_ID ); } private DatabaseHelper mDbHelper; /** * (non-Javadoc) * @see android.content.ContentProvider#delete(android.net.Uri, java.lang.String, java.lang.String[]) */ @Override public int delete( Uri uri, String selection, String[] selectionArgs ) { int match = GPStrackingProvider.sURIMatcher.match( uri ); int affected = 0; switch( match ) { case GPStrackingProvider.TRACK_ID: affected = this.mDbHelper.deleteTrack( new Long( uri.getLastPathSegment() ).longValue() ); break; default: affected = 0; break; } return affected; } /** * (non-Javadoc) * @see android.content.ContentProvider#getType(android.net.Uri) */ @Override public String getType( Uri uri ) { int match = GPStrackingProvider.sURIMatcher.match( uri ); String mime = null; switch (match) { case TRACKS: mime = Tracks.CONTENT_TYPE; break; case TRACK_ID: mime = Tracks.CONTENT_ITEM_TYPE; break; case SEGMENTS: mime = Segments.CONTENT_TYPE; break; case SEGMENT_ID: mime = Segments.CONTENT_ITEM_TYPE; break; case WAYPOINTS: mime = Waypoints.CONTENT_TYPE; break; case WAYPOINT_ID: mime = Waypoints.CONTENT_ITEM_TYPE; break; } return mime; } /** * (non-Javadoc) * @see android.content.ContentProvider#insert(android.net.Uri, android.content.ContentValues) */ @Override public Uri insert( Uri uri, ContentValues values ) { //Log.d( TAG, "insert on "+uri ); Uri insertedUri = null; int match = GPStrackingProvider.sURIMatcher.match( uri ); List<String> pathSegments = null; long trackId; long segmentId; long waypointId = -1; switch (match) { case WAYPOINTS: pathSegments = uri.getPathSegments(); trackId = Integer.parseInt( pathSegments.get( 1 ) ); segmentId = Integer.parseInt( pathSegments.get( 3 ) ); Location loc = new Location( TAG ); Double latitude = values.getAsDouble( Waypoints.LATITUDE ); Double longitude = values.getAsDouble( Waypoints.LONGITUDE ); Long time = values.getAsLong( Waypoints.TIME ); Float speed = values.getAsFloat( Waypoints.SPEED ); if( time == null ) { time = System.currentTimeMillis(); } if( speed == null ) { speed = 0f; } loc.setLatitude( latitude ); loc.setLongitude( longitude ); loc.setTime( time ); loc.setSpeed( speed ); if( values.containsKey( Waypoints.ACCURACY ) ) { loc.setAccuracy( values.getAsFloat( Waypoints.ACCURACY ) ); } if( values.containsKey( Waypoints.ALTITUDE ) ) { loc.setAltitude( values.getAsDouble( Waypoints.ALTITUDE ) ); } if( values.containsKey( Waypoints.BEARING ) ) { loc.setBearing( values.getAsFloat( Waypoints.BEARING ) ); } waypointId = this.mDbHelper.insertWaypoint( trackId, segmentId, loc ); insertedUri = ContentUris.withAppendedId( uri, waypointId ); break; case SEGMENTS: pathSegments = uri.getPathSegments(); trackId = Integer.parseInt( pathSegments.get( 1 ) ); segmentId = this.mDbHelper.toNextSegment( trackId ); insertedUri = ContentUris.withAppendedId( uri, segmentId ); break; case TRACKS: String name = ( values == null ) ? "" : values.getAsString( Tracks.NAME ); trackId = this.mDbHelper.toNextTrack( name ); insertedUri = ContentUris.withAppendedId( uri, trackId ); break; default: Log.e( GPStrackingProvider.LOG_TAG, "Unable to match the URI:" + uri.toString() ); insertedUri = null; break; } return insertedUri; } /** * (non-Javadoc) * @see android.content.ContentProvider#onCreate() */ @Override public boolean onCreate() { if (this.mDbHelper == null) { this.mDbHelper = new DatabaseHelper( getContext() ); } return true; } /** * (non-Javadoc) * @see android.content.ContentProvider#query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) */ @Override public Cursor query( Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder ) { // Log.d( TAG, "Query on Uri:"+uri ); int match = GPStrackingProvider.sURIMatcher.match( uri ); String tableName = null; String whereclause = null; List<String> pathSegments = uri.getPathSegments(); switch (match) { case TRACKS: tableName = Tracks.TABLE; break; case TRACK_ID: tableName = Tracks.TABLE; whereclause = Tracks._ID + " = " + new Long( pathSegments.get( 1 ) ).longValue(); break; case SEGMENTS: tableName = Segments.TABLE; whereclause = Segments.TRACK + " = " + new Long( pathSegments.get( 1 ) ).longValue(); break; case SEGMENT_ID: tableName = Segments.TABLE; whereclause = Segments.TRACK + " = " + new Long( pathSegments.get( 1 ) ).longValue() + " and " + Segments._ID + " = " + new Long( pathSegments.get( 3 ) ).longValue(); break; case WAYPOINTS: tableName = Waypoints.TABLE; whereclause = Waypoints.SEGMENT + " = " + new Long( pathSegments.get( 3 ) ).longValue(); break; case WAYPOINT_ID: tableName = Waypoints.TABLE; whereclause = Waypoints.SEGMENT + " = " + new Long( pathSegments.get( 3 ) ).longValue() + " and " + Waypoints._ID + " = " + new Long( pathSegments.get( 5 ) ).longValue(); break; case TRACK_WAYPOINTS: tableName = Waypoints.TABLE + " INNER JOIN " + Segments.TABLE + " ON "+ Segments.TABLE+"."+Segments._ID +"=="+ Waypoints.SEGMENT; whereclause = Segments.TRACK + " = " + new Long( pathSegments.get( 1 ) ).longValue(); break; default: Log.e( GPStrackingProvider.LOG_TAG, "Unable to come to an action in the query uri" + uri.toString() ); return null; } // SQLiteQueryBuilder is a helper class that creates the // proper SQL syntax for us. SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder(); // Set the table we're querying. qBuilder.setTables( tableName ); // If the query ends in a specific record number, we're // being asked for a specific record, so set the // WHERE clause in our query. if (whereclause != null) { qBuilder.appendWhere( whereclause ); } // Make the query. SQLiteDatabase mDb = this.mDbHelper.getWritableDatabase(); Cursor c = qBuilder.query( mDb, projection, selection, selectionArgs, null, null, null ); c.setNotificationUri( getContext().getContentResolver(), uri ); return c; } /** * (non-Javadoc) * @see android.content.ContentProvider#update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) */ @Override public int update( Uri uri, ContentValues givenValues, String selection, String[] selectionArgs ) { int updates = -1 ; int match = GPStrackingProvider.sURIMatcher.match( uri ); String tableName; String whereclause; ContentValues args = new ContentValues(); Uri notifyUri; switch (match) { case TRACK_ID: tableName = Tracks.TABLE; long trackId = new Long( uri.getLastPathSegment() ).longValue(); whereclause = Tracks._ID + " = " + trackId; args.put( Tracks.NAME, givenValues.getAsString( Tracks.NAME ) ); notifyUri = ContentUris.withAppendedId( Tracks.CONTENT_URI, trackId ) ; break; default: Log.e( GPStrackingProvider.LOG_TAG, "Unable to come to an action in the query uri" + uri.toString() ); return -1; } // Execute the query. SQLiteDatabase mDb = this.mDbHelper.getWritableDatabase(); updates = mDb.update(tableName, args , whereclause, null) ; ContentResolver resolver = this.getContext().getContentResolver(); resolver.notifyChange( notifyUri, null ); return updates; } }