Protect MyTracksProvider based on the MyTracks settings bit.

Move MyTracksProvider to DatabaseProvider and protect the DatabaseProvider
using the AndroidManifest.xml.

Create a MyTracksProviderUtilFactory to create an instance of
MyTracksProviderUtils that accesses the DatabaseProvider.

Recreate MyTracksProvider by extending DatabaseProvider.
The recreated provider checks access, changes the authority,
and invokes the DatabaseProvider methods.
This commit is contained in:
Jimmy Shih
2011-10-07 16:23:59 -07:00
parent 1ffd77595d
commit 9e5204934f
42 changed files with 752 additions and 560 deletions
@@ -1,5 +1,6 @@
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsFactory;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.stats.TripStatistics;
@@ -57,7 +58,7 @@ public class AggregatedStatsActivity extends Activity implements
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.tracksProvider = MyTracksProviderUtils.Factory.get(this);
this.tracksProvider = MyTracksProviderUtilsFactory.get(this);
// We don't need a window title bar:
requestWindowFeature(Window.FEATURE_NO_TITLE);
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsFactory;
import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.maps.mytracks.R;
@@ -59,7 +59,7 @@ public class DeleteAllTracks extends Handler {
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
Log.w(Constants.TAG, "deleting all!");
MyTracksProviderUtils.Factory.get(context).deleteAllTracks();
MyTracksProviderUtilsFactory.get(context).deleteAllTracks();
SharedPreferences prefs =
context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
SharedPreferences.Editor editor = prefs.edit();
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsFactory;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.apps.mytracks.util.UriUtils;
@@ -53,13 +54,13 @@ public class DeleteTrack extends Activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
providerUtils = MyTracksProviderUtils.Factory.get(this);
providerUtils = MyTracksProviderUtilsFactory.get(this);
Intent intent = getIntent();
String action = intent.getAction();
Uri data = intent.getData();
if (!Intent.ACTION_DELETE.equals(action) ||
!UriUtils.matchesContentUri(data, TracksColumns.CONTENT_URI)) {
if (!Intent.ACTION_DELETE.equals(action)
|| !UriUtils.matchesContentUri(data, TracksColumns.DATABASE_CONTENT_URI)) {
Log.e(TAG, "Got bad delete intent: " + intent);
finish();
}
@@ -15,6 +15,7 @@
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsFactory;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.io.file.TrackWriter;
@@ -148,8 +149,7 @@ public class ExportAllTracks {
// Get a cursor over all tracks.
Cursor cursor = null;
try {
MyTracksProviderUtils providerUtils =
MyTracksProviderUtils.Factory.get(activity);
MyTracksProviderUtils providerUtils = MyTracksProviderUtilsFactory.get(activity);
cursor = providerUtils.getTracksCursor("");
if (cursor == null) {
return;
@@ -15,6 +15,7 @@
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsFactory;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.io.file.GpxImporter;
import com.google.android.apps.mytracks.util.FileUtils;
@@ -132,7 +133,7 @@ public class ImportAllTracks {
* been acquired.
*/
private void importAll() {
MyTracksProviderUtils providerUtils = MyTracksProviderUtils.Factory.get(activity);
MyTracksProviderUtils providerUtils = MyTracksProviderUtilsFactory.get(activity);
if (!fileUtils.isSdCardAvailable()) {
return;
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsFactory;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TrackDataHub;
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
@@ -317,7 +318,7 @@ public class MapActivity extends com.google.android.maps.MapActivity
* Zooms and pans the map so that the given waypoint is visible.
*/
public void showWaypoint(long waypointId) {
MyTracksProviderUtils providerUtils = MyTracksProviderUtils.Factory.get(this);
MyTracksProviderUtils providerUtils = MyTracksProviderUtilsFactory.get(this);
Waypoint wpt = providerUtils.getWaypoint(waypointId);
if (wpt != null && wpt.getLocation() != null) {
keepMyLocationVisible = false;
@@ -424,7 +425,7 @@ public class MapActivity extends com.google.android.maps.MapActivity
}
case Constants.MENU_DELETE: {
Uri uri = ContentUris.withAppendedId(
TracksColumns.CONTENT_URI, dataHub.getSelectedTrackId());
TracksColumns.DATABASE_CONTENT_URI, dataHub.getSelectedTrackId());
Intent intent = new Intent(Intent.ACTION_DELETE, uri);
startActivity(intent);
return true;
@@ -19,6 +19,7 @@ import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.analytics.GoogleAnalyticsTracker;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsFactory;
import com.google.android.apps.mytracks.content.TrackDataHub;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
@@ -144,7 +145,7 @@ public class MyTracks extends TabActivity implements OnTouchListener {
tracker.trackPageView("/appstart");
tracker.dispatch();
providerUtils = MyTracksProviderUtils.Factory.get(this);
providerUtils = MyTracksProviderUtilsFactory.get(this);
preferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
dataHub = ((MyTracksApplication) getApplication()).getTrackDataHub();
menuManager = new MenuManager(this);
@@ -208,7 +209,7 @@ public class MyTracks extends TabActivity implements OnTouchListener {
Uri data = intent.getData();
if ((Intent.ACTION_VIEW.equals(action) || Intent.ACTION_EDIT.equals(action))
&& TracksColumns.CONTENT_ITEMTYPE.equals(intent.getType())
&& UriUtils.matchesContentUri(data, TracksColumns.CONTENT_URI)) {
&& UriUtils.matchesContentUri(data, TracksColumns.DATABASE_CONTENT_URI)) {
long trackId = ContentUris.parseId(data);
dataHub.loadTrack(trackId);
}
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsFactory;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.maps.mytracks.R;
@@ -89,7 +89,7 @@ public class TrackDetails extends Activity implements OnClickListener {
}
private void fillDialog() {
Track track = MyTracksProviderUtils.Factory.get(this).getTrack(trackId);
Track track = MyTracksProviderUtilsFactory.get(this).getTrack(trackId);
if (track != null) {
name.setText(track.getName());
description.setText(track.getDescription());
@@ -103,7 +103,7 @@ public class TrackDetails extends Activity implements OnClickListener {
values.put(TracksColumns.DESCRIPTION, description.getText().toString());
values.put(TracksColumns.CATEGORY, category.getText().toString());
getContentResolver().update(
TracksColumns.CONTENT_URI,
TracksColumns.DATABASE_CONTENT_URI,
values,
"_id = " + trackId,
null/*selectionArgs*/);
@@ -189,7 +189,7 @@ public class TrackList extends ListActivity
return true;
case Constants.MENU_DELETE: {
Intent intent = new Intent(Intent.ACTION_DELETE);
Uri uri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId);
Uri uri = ContentUris.withAppendedId(TracksColumns.DATABASE_CONTENT_URI, trackId);
intent.setDataAndType(uri, TracksColumns.CONTENT_ITEMTYPE);
startActivity(intent);
return true;
@@ -251,7 +251,7 @@ public class TrackList extends ListActivity
preferences.getLong(getString(R.string.recording_track_key), -1);
tracksCursor = getContentResolver().query(
TracksColumns.CONTENT_URI, null, null, null, "_id DESC");
TracksColumns.DATABASE_CONTENT_URI, null, null, null, "_id DESC");
startManagingCursor(tracksCursor);
setListAdapter();
}
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsFactory;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.WaypointsColumns;
import com.google.android.apps.mytracks.stats.TripStatistics;
@@ -119,7 +119,7 @@ public class WaypointDetails extends Activity
}
private void fillDialog() {
waypoint = MyTracksProviderUtils.Factory.get(this).getWaypoint(waypointId);
waypoint = MyTracksProviderUtilsFactory.get(this).getWaypoint(waypointId);
if (waypoint != null) {
name.setText(waypoint.getName());
ImageView icon = (ImageView) findViewById(R.id.waypointdetails_icon);
@@ -156,7 +156,7 @@ public class WaypointDetails extends Activity
values.put(WaypointsColumns.CATEGORY, category.getText().toString());
}
getContentResolver().update(
WaypointsColumns.CONTENT_URI,
WaypointsColumns.DATABASE_CONTENT_URI,
values,
"_id = " + waypointId,
null /*selectionArgs*/);
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsFactory;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.content.WaypointsColumns;
@@ -134,7 +135,7 @@ public class WaypointsList extends ListActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
providerUtils = MyTracksProviderUtils.Factory.get(this);
providerUtils = MyTracksProviderUtilsFactory.get(this);
serviceConnection = new TrackRecordingServiceConnection(this, null);
// We don't need a window title bar:
@@ -174,10 +175,10 @@ public class WaypointsList extends ListActivity
}
final long firstWaypointId = providerUtils.getFirstWaypointId(trackId);
String selection = WaypointsColumns.TRACKID + "=" + trackId + " AND " + WaypointsColumns._ID
+ "!=" + firstWaypointId;
waypointsCursor = getContentResolver().query(
WaypointsColumns.CONTENT_URI, null,
WaypointsColumns.TRACKID + "=" + trackId + " AND "
+ WaypointsColumns._ID + "!=" + firstWaypointId, null, null);
WaypointsColumns.DATABASE_CONTENT_URI, null, selection, null, null);
startManagingCursor(waypointsCursor);
setListAdapter();
}
@@ -211,14 +211,15 @@ class DataSourceManager {
break;
case POINT_UPDATES:
dataSources.registerContentObserver(
TrackPointsColumns.CONTENT_URI, false, pointObserver);
TrackPointsColumns.DATABASE_CONTENT_URI, false, pointObserver);
break;
case TRACK_UPDATES:
dataSources.registerContentObserver(TracksColumns.CONTENT_URI, false, trackObserver);
dataSources.registerContentObserver(
TracksColumns.DATABASE_CONTENT_URI, false, trackObserver);
break;
case WAYPOINT_UPDATES:
dataSources.registerContentObserver(
WaypointsColumns.CONTENT_URI, false, waypointObserver);
WaypointsColumns.DATABASE_CONTENT_URI, false, waypointObserver);
break;
case DISPLAY_PREFERENCES:
dataSources.registerOnSharedPreferenceChangeListener(preferenceListener);
@@ -0,0 +1,434 @@
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.content;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.util.ApiFeatures;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
/**
* A provider that handles recorded (GPS) tracks and their track points.
*
* @author Leif Hendrik Wilden
*/
public class DatabaseProvider extends ContentProvider {
private static final String DATABASE_NAME = "mytracks.db";
private static final int DATABASE_VERSION = 19;
private static final int TRACKPOINTS = 1;
private static final int TRACKPOINTS_ID = 2;
private static final int TRACKS = 3;
private static final int TRACKS_ID = 4;
private static final int WAYPOINTS = 5;
private static final int WAYPOINTS_ID = 6;
private static final String TRACKPOINTS_TABLE = "trackpoints";
private static final String TRACKS_TABLE = "tracks";
private static final String WAYPOINTS_TABLE = "waypoints";
public static final String TAG = DatabaseProvider.class.getSimpleName();
/**
* Helper which creates or upgrades the database if necessary.
*/
private static class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TRACKPOINTS_TABLE + " ("
+ TrackPointsColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ TrackPointsColumns.TRACKID + " INTEGER, "
+ TrackPointsColumns.LONGITUDE + " INTEGER, "
+ TrackPointsColumns.LATITUDE + " INTEGER, "
+ TrackPointsColumns.TIME + " INTEGER, "
+ TrackPointsColumns.ALTITUDE + " FLOAT, "
+ TrackPointsColumns.ACCURACY + " FLOAT, "
+ TrackPointsColumns.SPEED + " FLOAT, "
+ TrackPointsColumns.BEARING + " FLOAT, "
+ TrackPointsColumns.SENSOR + " BLOB);");
db.execSQL("CREATE TABLE " + TRACKS_TABLE + " ("
+ TracksColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ TracksColumns.NAME + " STRING, "
+ TracksColumns.DESCRIPTION + " STRING, "
+ TracksColumns.CATEGORY + " STRING, "
+ TracksColumns.STARTID + " INTEGER, "
+ TracksColumns.STOPID + " INTEGER, "
+ TracksColumns.STARTTIME + " INTEGER, "
+ TracksColumns.STOPTIME + " INTEGER, "
+ TracksColumns.NUMPOINTS + " INTEGER, "
+ TracksColumns.TOTALDISTANCE + " FLOAT, "
+ TracksColumns.TOTALTIME + " INTEGER, "
+ TracksColumns.MOVINGTIME + " INTEGER, "
+ TracksColumns.MINLAT + " INTEGER, "
+ TracksColumns.MAXLAT + " INTEGER, "
+ TracksColumns.MINLON + " INTEGER, "
+ TracksColumns.MAXLON + " INTEGER, "
+ TracksColumns.AVGSPEED + " FLOAT, "
+ TracksColumns.AVGMOVINGSPEED + " FLOAT, "
+ TracksColumns.MAXSPEED + " FLOAT, "
+ TracksColumns.MINELEVATION + " FLOAT, "
+ TracksColumns.MAXELEVATION + " FLOAT, "
+ TracksColumns.ELEVATIONGAIN + " FLOAT, "
+ TracksColumns.MINGRADE + " FLOAT, "
+ TracksColumns.MAXGRADE + " FLOAT, "
+ TracksColumns.MAPID + " STRING, "
+ TracksColumns.TABLEID + " STRING);");
db.execSQL("CREATE TABLE " + WAYPOINTS_TABLE + " ("
+ WaypointsColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ WaypointsColumns.NAME + " STRING, "
+ WaypointsColumns.DESCRIPTION + " STRING, "
+ WaypointsColumns.CATEGORY + " STRING, "
+ WaypointsColumns.ICON + " STRING, "
+ WaypointsColumns.TRACKID + " INTEGER, "
+ WaypointsColumns.TYPE + " INTEGER, "
+ WaypointsColumns.LENGTH + " FLOAT, "
+ WaypointsColumns.DURATION + " INTEGER, "
+ WaypointsColumns.STARTTIME + " INTEGER, "
+ WaypointsColumns.STARTID + " INTEGER, "
+ WaypointsColumns.STOPID + " INTEGER, "
+ WaypointsColumns.LONGITUDE + " INTEGER, "
+ WaypointsColumns.LATITUDE + " INTEGER, "
+ WaypointsColumns.TIME + " INTEGER, "
+ WaypointsColumns.ALTITUDE + " FLOAT, "
+ WaypointsColumns.ACCURACY + " FLOAT, "
+ WaypointsColumns.SPEED + " FLOAT, "
+ WaypointsColumns.BEARING + " FLOAT, "
+ WaypointsColumns.TOTALDISTANCE + " FLOAT, "
+ WaypointsColumns.TOTALTIME + " INTEGER, "
+ WaypointsColumns.MOVINGTIME + " INTEGER, "
+ WaypointsColumns.AVGSPEED + " FLOAT, "
+ WaypointsColumns.AVGMOVINGSPEED + " FLOAT, "
+ WaypointsColumns.MAXSPEED + " FLOAT, "
+ WaypointsColumns.MINELEVATION + " FLOAT, "
+ WaypointsColumns.MAXELEVATION + " FLOAT, "
+ WaypointsColumns.ELEVATIONGAIN + " FLOAT, "
+ WaypointsColumns.MINGRADE + " FLOAT, "
+ WaypointsColumns.MAXGRADE + " FLOAT);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 17) {
// Wipe the old data.
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS " + TRACKPOINTS_TABLE);
db.execSQL("DROP TABLE IF EXISTS " + TRACKS_TABLE);
db.execSQL("DROP TABLE IF EXISTS " + WAYPOINTS_TABLE);
onCreate(db);
} else {
// Incremental updates go here.
// Each time you increase the DB version, add a corresponding if clause.
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion);
// Sensor data.
if (oldVersion <= 17) {
Log.w(TAG, "Upgrade DB: Adding sensor column.");
db.execSQL("ALTER TABLE " + TRACKPOINTS_TABLE
+ " ADD " + TrackPointsColumns.SENSOR + " BLOB");
}
if (oldVersion <= 18) {
Log.w(TAG, "Upgrade DB: Adding tableid column.");
db.execSQL("ALTER TABLE " + TRACKS_TABLE
+ " ADD " + TracksColumns.TABLEID + " STRING");
}
}
}
}
private final UriMatcher urlMatcher;
private SQLiteDatabase db;
public DatabaseProvider() {
urlMatcher = new UriMatcher(UriMatcher.NO_MATCH);
urlMatcher.addURI(MyTracksProviderUtils.DATABASE_AUTHORITY, "trackpoints", TRACKPOINTS);
urlMatcher.addURI(MyTracksProviderUtils.DATABASE_AUTHORITY, "trackpoints/#", TRACKPOINTS_ID);
urlMatcher.addURI(MyTracksProviderUtils.DATABASE_AUTHORITY, "tracks", TRACKS);
urlMatcher.addURI(MyTracksProviderUtils.DATABASE_AUTHORITY, "tracks/#", TRACKS_ID);
urlMatcher.addURI(MyTracksProviderUtils.DATABASE_AUTHORITY, "waypoints", WAYPOINTS);
urlMatcher.addURI(MyTracksProviderUtils.DATABASE_AUTHORITY, "waypoints/#", WAYPOINTS_ID);
}
@Override
public boolean onCreate() {
DatabaseHelper dbHelper = new DatabaseHelper(getContext());
try {
db = dbHelper.getWritableDatabase();
} catch (SQLiteException e) {
Log.e(TAG, "Unable to open database for writing", e);
}
return db != null;
}
@Override
public int delete(Uri url, String where, String[] selectionArgs) {
String table;
boolean shouldVacuum = false;
switch (urlMatcher.match(url)) {
case TRACKPOINTS:
table = TRACKPOINTS_TABLE;
break;
case TRACKS:
table = TRACKS_TABLE;
shouldVacuum = true;
break;
case WAYPOINTS:
table = WAYPOINTS_TABLE;
break;
default:
throw new IllegalArgumentException("Unknown URL " + url);
}
Log.w(DatabaseProvider.TAG, "provider delete in " + table + "!");
int count = db.delete(table, where, selectionArgs);
getContext().getContentResolver().notifyChange(url, null, true);
if (shouldVacuum) {
// If a potentially large amount of data was deleted, we want to reclaim its space.
Log.i(TAG, "Vacuuming the database");
db.execSQL("VACUUM");
}
return count;
}
@Override
public String getType(Uri url) {
switch (urlMatcher.match(url)) {
case TRACKPOINTS:
return TrackPointsColumns.CONTENT_TYPE;
case TRACKPOINTS_ID:
return TrackPointsColumns.CONTENT_ITEMTYPE;
case TRACKS:
return TracksColumns.CONTENT_TYPE;
case TRACKS_ID:
return TracksColumns.CONTENT_ITEMTYPE;
case WAYPOINTS:
return WaypointsColumns.CONTENT_TYPE;
case WAYPOINTS_ID:
return WaypointsColumns.CONTENT_ITEMTYPE;
default:
throw new IllegalArgumentException("Unknown URL " + url);
}
}
@Override
public Uri insert(Uri url, ContentValues initialValues) {
Log.d(DatabaseProvider.TAG, "MyTracksProvider.insert");
ContentValues values;
if (initialValues != null) {
values = initialValues;
} else {
values = new ContentValues();
}
int urlMatchType = urlMatcher.match(url);
return insertType(url, urlMatchType, values);
}
private Uri insertType(Uri url, int urlMatchType, ContentValues values) {
switch (urlMatchType) {
case TRACKPOINTS:
return insertTrackPoint(url, values);
case TRACKS:
return insertTrack(url, values);
case WAYPOINTS:
return insertWaypoint(url, values);
default:
throw new IllegalArgumentException("Unknown URL " + url);
}
}
@Override
public int bulkInsert(Uri url, ContentValues[] valuesBulk) {
Log.d(DatabaseProvider.TAG, "MyTracksProvider.bulkInsert");
int numInserted = 0;
try {
// Use a transaction in order to make the insertions run as a single batch
db.beginTransaction();
int urlMatch = urlMatcher.match(url);
for (numInserted = 0; numInserted < valuesBulk.length; numInserted++) {
ContentValues values = valuesBulk[numInserted];
if (values == null) { values = new ContentValues(); }
insertType(url, urlMatch, values);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
return numInserted;
}
private Uri insertTrackPoint(Uri url, ContentValues values) {
boolean hasLat = values.containsKey(TrackPointsColumns.LATITUDE);
boolean hasLong = values.containsKey(TrackPointsColumns.LONGITUDE);
boolean hasTime = values.containsKey(TrackPointsColumns.TIME);
if (!hasLat || !hasLong || !hasTime) {
throw new IllegalArgumentException(
"Latitude, longitude, and time values are required.");
}
long rowId = db.insert(TRACKPOINTS_TABLE, TrackPointsColumns._ID, values);
if (rowId >= 0) {
Uri uri = ContentUris
.appendId(TrackPointsColumns.DATABASE_CONTENT_URI.buildUpon(), rowId).build();
getContext().getContentResolver().notifyChange(url, null, true);
return uri;
}
throw new SQLiteException("Failed to insert row into " + url);
}
private Uri insertTrack(Uri url, ContentValues values) {
boolean hasStartTime = values.containsKey(TracksColumns.STARTTIME);
boolean hasStartId = values.containsKey(TracksColumns.STARTID);
if (!hasStartTime || !hasStartId) {
throw new IllegalArgumentException(
"Both start time and start id values are required.");
}
long rowId = db.insert(TRACKS_TABLE, TracksColumns._ID, values);
if (rowId > 0) {
Uri uri = ContentUris.appendId(TracksColumns.DATABASE_CONTENT_URI.buildUpon(), rowId).build();
getContext().getContentResolver().notifyChange(url, null, true);
return uri;
}
throw new SQLException("Failed to insert row into " + url);
}
private Uri insertWaypoint(Uri url, ContentValues values) {
long rowId = db.insert(WAYPOINTS_TABLE, WaypointsColumns._ID, values);
if (rowId > 0) {
Uri uri = ContentUris
.appendId(WaypointsColumns.DATABASE_CONTENT_URI.buildUpon(), rowId).build();
getContext().getContentResolver().notifyChange(url, null, true);
return uri;
}
throw new SQLException("Failed to insert row into " + url);
}
@Override
public Cursor query(
Uri url, String[] projection, String selection, String[] selectionArgs,
String sort) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
int match = urlMatcher.match(url);
String sortOrder = null;
if (match == TRACKPOINTS) {
qb.setTables(TRACKPOINTS_TABLE);
if (sort != null) {
sortOrder = sort;
} else {
sortOrder = TrackPointsColumns.DEFAULT_SORT_ORDER;
}
} else if (match == TRACKPOINTS_ID) {
qb.setTables(TRACKPOINTS_TABLE);
qb.appendWhere("_id=" + url.getPathSegments().get(1));
} else if (match == TRACKS) {
qb.setTables(TRACKS_TABLE);
if (sort != null) {
sortOrder = sort;
} else {
sortOrder = TracksColumns.DEFAULT_SORT_ORDER;
}
} else if (match == TRACKS_ID) {
qb.setTables(TRACKS_TABLE);
qb.appendWhere("_id=" + url.getPathSegments().get(1));
} else if (match == WAYPOINTS) {
qb.setTables(WAYPOINTS_TABLE);
if (sort != null) {
sortOrder = sort;
} else {
sortOrder = WaypointsColumns.DEFAULT_SORT_ORDER;
}
} else if (match == WAYPOINTS_ID) {
qb.setTables(WAYPOINTS_TABLE);
qb.appendWhere("_id=" + url.getPathSegments().get(1));
} else {
throw new IllegalArgumentException("Unknown URL " + url);
}
if (ApiFeatures.getInstance().canReuseSQLiteQueryBuilder()) {
Log.i(Constants.TAG,
"Build query: " + qb.buildQuery(projection, selection, selectionArgs,
null, null, sortOrder, null));
}
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null,
sortOrder);
c.setNotificationUri(getContext().getContentResolver(), url);
return c;
}
@Override
public int update(Uri url, ContentValues values, String where,
String[] selectionArgs) {
int count;
int match = urlMatcher.match(url);
if (match == TRACKPOINTS) {
count = db.update(TRACKPOINTS_TABLE, values, where, selectionArgs);
} else if (match == TRACKPOINTS_ID) {
String segment = url.getPathSegments().get(1);
count = db.update(TRACKPOINTS_TABLE, values, "_id=" + segment
+ (!TextUtils.isEmpty(where)
? " AND (" + where + ')'
: ""),
selectionArgs);
} else if (match == TRACKS) {
count = db.update(TRACKS_TABLE, values, where, selectionArgs);
} else if (match == TRACKS_ID) {
String segment = url.getPathSegments().get(1);
count = db.update(TRACKS_TABLE, values, "_id=" + segment
+ (!TextUtils.isEmpty(where)
? " AND (" + where + ')'
: ""),
selectionArgs);
} else if (match == WAYPOINTS) {
count = db.update(WAYPOINTS_TABLE, values, where, selectionArgs);
} else if (match == WAYPOINTS_ID) {
String segment = url.getPathSegments().get(1);
count = db.update(WAYPOINTS_TABLE, values, "_id=" + segment
+ (!TextUtils.isEmpty(where)
? " AND (" + where + ')'
: ""),
selectionArgs);
} else {
throw new IllegalArgumentException("Unknown URL " + url);
}
getContext().getContentResolver().notifyChange(url, null, true);
return count;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2008 Google Inc.
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -16,423 +16,101 @@
package com.google.android.apps.mytracks.content;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.maps.mytracks.R;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import android.os.Binder;
import android.os.Process;
/**
* A provider that handles recorded (GPS) tracks and their track points.
* A content provider that accesses MyTracks tracks, track points, and
* waypoints. After checking access, calls the corresponding methods in
* {@link DatabaseProvider}.
*
* @author Leif Hendrik Wilden
* @author Jimmy Shih
*/
public class MyTracksProvider extends ContentProvider {
private static final String DATABASE_NAME = "mytracks.db";
private static final int DATABASE_VERSION = 19;
private static final int TRACKPOINTS = 1;
private static final int TRACKPOINTS_ID = 2;
private static final int TRACKS = 3;
private static final int TRACKS_ID = 4;
private static final int WAYPOINTS = 5;
private static final int WAYPOINTS_ID = 6;
private static final String TRACKPOINTS_TABLE = "trackpoints";
private static final String TRACKS_TABLE = "tracks";
private static final String WAYPOINTS_TABLE = "waypoints";
public static final String TAG = "MyTracksProvider";
/**
* Helper which creates or upgrades the database if necessary.
*/
private static class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TRACKPOINTS_TABLE + " ("
+ TrackPointsColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ TrackPointsColumns.TRACKID + " INTEGER, "
+ TrackPointsColumns.LONGITUDE + " INTEGER, "
+ TrackPointsColumns.LATITUDE + " INTEGER, "
+ TrackPointsColumns.TIME + " INTEGER, "
+ TrackPointsColumns.ALTITUDE + " FLOAT, "
+ TrackPointsColumns.ACCURACY + " FLOAT, "
+ TrackPointsColumns.SPEED + " FLOAT, "
+ TrackPointsColumns.BEARING + " FLOAT, "
+ TrackPointsColumns.SENSOR + " BLOB);");
db.execSQL("CREATE TABLE " + TRACKS_TABLE + " ("
+ TracksColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ TracksColumns.NAME + " STRING, "
+ TracksColumns.DESCRIPTION + " STRING, "
+ TracksColumns.CATEGORY + " STRING, "
+ TracksColumns.STARTID + " INTEGER, "
+ TracksColumns.STOPID + " INTEGER, "
+ TracksColumns.STARTTIME + " INTEGER, "
+ TracksColumns.STOPTIME + " INTEGER, "
+ TracksColumns.NUMPOINTS + " INTEGER, "
+ TracksColumns.TOTALDISTANCE + " FLOAT, "
+ TracksColumns.TOTALTIME + " INTEGER, "
+ TracksColumns.MOVINGTIME + " INTEGER, "
+ TracksColumns.MINLAT + " INTEGER, "
+ TracksColumns.MAXLAT + " INTEGER, "
+ TracksColumns.MINLON + " INTEGER, "
+ TracksColumns.MAXLON + " INTEGER, "
+ TracksColumns.AVGSPEED + " FLOAT, "
+ TracksColumns.AVGMOVINGSPEED + " FLOAT, "
+ TracksColumns.MAXSPEED + " FLOAT, "
+ TracksColumns.MINELEVATION + " FLOAT, "
+ TracksColumns.MAXELEVATION + " FLOAT, "
+ TracksColumns.ELEVATIONGAIN + " FLOAT, "
+ TracksColumns.MINGRADE + " FLOAT, "
+ TracksColumns.MAXGRADE + " FLOAT, "
+ TracksColumns.MAPID + " STRING, "
+ TracksColumns.TABLEID + " STRING);");
db.execSQL("CREATE TABLE " + WAYPOINTS_TABLE + " ("
+ WaypointsColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ WaypointsColumns.NAME + " STRING, "
+ WaypointsColumns.DESCRIPTION + " STRING, "
+ WaypointsColumns.CATEGORY + " STRING, "
+ WaypointsColumns.ICON + " STRING, "
+ WaypointsColumns.TRACKID + " INTEGER, "
+ WaypointsColumns.TYPE + " INTEGER, "
+ WaypointsColumns.LENGTH + " FLOAT, "
+ WaypointsColumns.DURATION + " INTEGER, "
+ WaypointsColumns.STARTTIME + " INTEGER, "
+ WaypointsColumns.STARTID + " INTEGER, "
+ WaypointsColumns.STOPID + " INTEGER, "
+ WaypointsColumns.LONGITUDE + " INTEGER, "
+ WaypointsColumns.LATITUDE + " INTEGER, "
+ WaypointsColumns.TIME + " INTEGER, "
+ WaypointsColumns.ALTITUDE + " FLOAT, "
+ WaypointsColumns.ACCURACY + " FLOAT, "
+ WaypointsColumns.SPEED + " FLOAT, "
+ WaypointsColumns.BEARING + " FLOAT, "
+ WaypointsColumns.TOTALDISTANCE + " FLOAT, "
+ WaypointsColumns.TOTALTIME + " INTEGER, "
+ WaypointsColumns.MOVINGTIME + " INTEGER, "
+ WaypointsColumns.AVGSPEED + " FLOAT, "
+ WaypointsColumns.AVGMOVINGSPEED + " FLOAT, "
+ WaypointsColumns.MAXSPEED + " FLOAT, "
+ WaypointsColumns.MINELEVATION + " FLOAT, "
+ WaypointsColumns.MAXELEVATION + " FLOAT, "
+ WaypointsColumns.ELEVATIONGAIN + " FLOAT, "
+ WaypointsColumns.MINGRADE + " FLOAT, "
+ WaypointsColumns.MAXGRADE + " FLOAT);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 17) {
// Wipe the old data.
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS " + TRACKPOINTS_TABLE);
db.execSQL("DROP TABLE IF EXISTS " + TRACKS_TABLE);
db.execSQL("DROP TABLE IF EXISTS " + WAYPOINTS_TABLE);
onCreate(db);
} else {
// Incremental updates go here.
// Each time you increase the DB version, add a corresponding if clause.
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion);
// Sensor data.
if (oldVersion <= 17) {
Log.w(TAG, "Upgrade DB: Adding sensor column.");
db.execSQL("ALTER TABLE " + TRACKPOINTS_TABLE
+ " ADD " + TrackPointsColumns.SENSOR + " BLOB");
}
if (oldVersion <= 18) {
Log.w(TAG, "Upgrade DB: Adding tableid column.");
db.execSQL("ALTER TABLE " + TRACKS_TABLE
+ " ADD " + TracksColumns.TABLEID + " STRING");
}
}
}
}
private final UriMatcher urlMatcher;
private SQLiteDatabase db;
public MyTracksProvider() {
urlMatcher = new UriMatcher(UriMatcher.NO_MATCH);
urlMatcher.addURI(MyTracksProviderUtils.AUTHORITY,
"trackpoints", TRACKPOINTS);
urlMatcher.addURI(MyTracksProviderUtils.AUTHORITY,
"trackpoints/#", TRACKPOINTS_ID);
urlMatcher.addURI(MyTracksProviderUtils.AUTHORITY, "tracks", TRACKS);
urlMatcher.addURI(MyTracksProviderUtils.AUTHORITY, "tracks/#", TRACKS_ID);
urlMatcher.addURI(MyTracksProviderUtils.AUTHORITY, "waypoints", WAYPOINTS);
urlMatcher.addURI(MyTracksProviderUtils.AUTHORITY,
"waypoints/#", WAYPOINTS_ID);
}
@Override
public boolean onCreate() {
DatabaseHelper dbHelper = new DatabaseHelper(getContext());
try {
db = dbHelper.getWritableDatabase();
} catch (SQLiteException e) {
Log.e(TAG, "Unable to open database for writing", e);
}
return db != null;
}
@Override
public int delete(Uri url, String where, String[] selectionArgs) {
String table;
boolean shouldVacuum = false;
switch (urlMatcher.match(url)) {
case TRACKPOINTS:
table = TRACKPOINTS_TABLE;
break;
case TRACKS:
table = TRACKS_TABLE;
shouldVacuum = true;
break;
case WAYPOINTS:
table = WAYPOINTS_TABLE;
break;
default:
throw new IllegalArgumentException("Unknown URL " + url);
}
Log.w(MyTracksProvider.TAG, "provider delete in " + table + "!");
int count = db.delete(table, where, selectionArgs);
getContext().getContentResolver().notifyChange(url, null, true);
if (shouldVacuum) {
// If a potentially large amount of data was deleted, we want to reclaim its space.
Log.i(TAG, "Vacuuming the database");
db.execSQL("VACUUM");
}
return count;
}
@Override
public String getType(Uri url) {
switch (urlMatcher.match(url)) {
case TRACKPOINTS:
return TrackPointsColumns.CONTENT_TYPE;
case TRACKPOINTS_ID:
return TrackPointsColumns.CONTENT_ITEMTYPE;
case TRACKS:
return TracksColumns.CONTENT_TYPE;
case TRACKS_ID:
return TracksColumns.CONTENT_ITEMTYPE;
case WAYPOINTS:
return WaypointsColumns.CONTENT_TYPE;
case WAYPOINTS_ID:
return WaypointsColumns.CONTENT_ITEMTYPE;
default:
throw new IllegalArgumentException("Unknown URL " + url);
}
}
@Override
public Uri insert(Uri url, ContentValues initialValues) {
Log.d(MyTracksProvider.TAG, "MyTracksProvider.insert");
ContentValues values;
if (initialValues != null) {
values = initialValues;
public class MyTracksProvider extends DatabaseProvider {
private boolean canAccess() {
if (Binder.getCallingPid() == Process.myPid()) {
return true;
} else {
values = new ContentValues();
}
int urlMatchType = urlMatcher.match(url);
return insertType(url, urlMatchType, values);
}
private Uri insertType(Uri url, int urlMatchType, ContentValues values) {
switch (urlMatchType) {
case TRACKPOINTS:
return insertTrackPoint(url, values);
case TRACKS:
return insertTrack(url, values);
case WAYPOINTS:
return insertWaypoint(url, values);
default:
throw new IllegalArgumentException("Unknown URL " + url);
Context context = getContext();
SharedPreferences sharedPreferences = context.getSharedPreferences(
Constants.SETTINGS_NAME, 0);
return sharedPreferences.getBoolean(context.getString(R.string.share_data_key), false);
}
}
/**
* Gets a URI based on the input URI, but replaces the
* {@link MyTracksProvider} authority with the {@link DatabaseProvider}
* authority. Returns null if the input URI doesn't contain the
* {@link MyTracksProvider} authority.
*/
private Uri getDatabaseProviderUri(Uri uri) {
String authority = uri.getAuthority();
if (authority != null && authority.equals(MyTracksProviderUtils.AUTHORITY)) {
String databaseUri = "content://" + MyTracksProviderUtils.DATABASE_AUTHORITY;
String path = uri.getPath();
if (path != null && !path.isEmpty()) {
databaseUri += path;
}
return Uri.parse(databaseUri);
}
return null;
}
@Override
public int bulkInsert(Uri url, ContentValues[] valuesBulk) {
Log.d(MyTracksProvider.TAG, "MyTracksProvider.bulkInsert");
int numInserted = 0;
try {
// Use a transaction in order to make the insertions run as a single batch
db.beginTransaction();
int urlMatch = urlMatcher.match(url);
for (numInserted = 0; numInserted < valuesBulk.length; numInserted++) {
ContentValues values = valuesBulk[numInserted];
if (values == null) { values = new ContentValues(); }
insertType(url, urlMatch, values);
public int delete(Uri uri, String selection, String[] selectionArgs) {
if (!canAccess()) {
return 0;
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
return numInserted;
return super.delete(getDatabaseProviderUri(uri), selection, selectionArgs);
}
private Uri insertTrackPoint(Uri url, ContentValues values) {
boolean hasLat = values.containsKey(TrackPointsColumns.LATITUDE);
boolean hasLong = values.containsKey(TrackPointsColumns.LONGITUDE);
boolean hasTime = values.containsKey(TrackPointsColumns.TIME);
if (!hasLat || !hasLong || !hasTime) {
throw new IllegalArgumentException(
"Latitude, longitude, and time values are required.");
@Override
public String getType(Uri uri) {
if (!canAccess()) {
return null;
}
long rowId = db.insert(TRACKPOINTS_TABLE, TrackPointsColumns._ID, values);
if (rowId >= 0) {
Uri uri = ContentUris.appendId(
TrackPointsColumns.CONTENT_URI.buildUpon(), rowId).build();
getContext().getContentResolver().notifyChange(url, null, true);
return uri;
}
throw new SQLiteException("Failed to insert row into " + url);
return super.getType(getDatabaseProviderUri(uri));
}
private Uri insertTrack(Uri url, ContentValues values) {
boolean hasStartTime = values.containsKey(TracksColumns.STARTTIME);
boolean hasStartId = values.containsKey(TracksColumns.STARTID);
if (!hasStartTime || !hasStartId) {
throw new IllegalArgumentException(
"Both start time and start id values are required.");
@Override
public Uri insert(Uri uri, ContentValues values) {
if (!canAccess()) {
return null;
}
long rowId = db.insert(TRACKS_TABLE, TracksColumns._ID, values);
if (rowId > 0) {
Uri uri = ContentUris.appendId(
TracksColumns.CONTENT_URI.buildUpon(), rowId).build();
getContext().getContentResolver().notifyChange(url, null, true);
return uri;
}
throw new SQLException("Failed to insert row into " + url);
return super.insert(getDatabaseProviderUri(uri), values);
}
private Uri insertWaypoint(Uri url, ContentValues values) {
long rowId = db.insert(WAYPOINTS_TABLE, WaypointsColumns._ID, values);
if (rowId > 0) {
Uri uri = ContentUris.appendId(
WaypointsColumns.CONTENT_URI.buildUpon(), rowId).build();
getContext().getContentResolver().notifyChange(url, null, true);
return uri;
@Override
public int bulkInsert(Uri uri, ContentValues[] values) {
if (!canAccess()) {
return 0;
}
throw new SQLException("Failed to insert row into " + url);
return super.bulkInsert(getDatabaseProviderUri(uri), values);
}
@Override
public Cursor query(
Uri url, String[] projection, String selection, String[] selectionArgs,
String sort) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
int match = urlMatcher.match(url);
String sortOrder = null;
if (match == TRACKPOINTS) {
qb.setTables(TRACKPOINTS_TABLE);
if (sort != null) {
sortOrder = sort;
} else {
sortOrder = TrackPointsColumns.DEFAULT_SORT_ORDER;
}
} else if (match == TRACKPOINTS_ID) {
qb.setTables(TRACKPOINTS_TABLE);
qb.appendWhere("_id=" + url.getPathSegments().get(1));
} else if (match == TRACKS) {
qb.setTables(TRACKS_TABLE);
if (sort != null) {
sortOrder = sort;
} else {
sortOrder = TracksColumns.DEFAULT_SORT_ORDER;
}
} else if (match == TRACKS_ID) {
qb.setTables(TRACKS_TABLE);
qb.appendWhere("_id=" + url.getPathSegments().get(1));
} else if (match == WAYPOINTS) {
qb.setTables(WAYPOINTS_TABLE);
if (sort != null) {
sortOrder = sort;
} else {
sortOrder = WaypointsColumns.DEFAULT_SORT_ORDER;
}
} else if (match == WAYPOINTS_ID) {
qb.setTables(WAYPOINTS_TABLE);
qb.appendWhere("_id=" + url.getPathSegments().get(1));
} else {
throw new IllegalArgumentException("Unknown URL " + url);
Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
if (!canAccess()) {
return null;
}
if (ApiFeatures.getInstance().canReuseSQLiteQueryBuilder()) {
Log.i(Constants.TAG,
"Build query: " + qb.buildQuery(projection, selection, selectionArgs,
null, null, sortOrder, null));
}
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null,
sortOrder);
c.setNotificationUri(getContext().getContentResolver(), url);
return c;
return super.query(getDatabaseProviderUri(uri), projection, selection, selectionArgs, sortOrder);
}
@Override
public int update(Uri url, ContentValues values, String where,
String[] selectionArgs) {
int count;
int match = urlMatcher.match(url);
if (match == TRACKPOINTS) {
count = db.update(TRACKPOINTS_TABLE, values, where, selectionArgs);
} else if (match == TRACKPOINTS_ID) {
String segment = url.getPathSegments().get(1);
count = db.update(TRACKPOINTS_TABLE, values, "_id=" + segment
+ (!TextUtils.isEmpty(where)
? " AND (" + where + ')'
: ""),
selectionArgs);
} else if (match == TRACKS) {
count = db.update(TRACKS_TABLE, values, where, selectionArgs);
} else if (match == TRACKS_ID) {
String segment = url.getPathSegments().get(1);
count = db.update(TRACKS_TABLE, values, "_id=" + segment
+ (!TextUtils.isEmpty(where)
? " AND (" + where + ')'
: ""),
selectionArgs);
} else if (match == WAYPOINTS) {
count = db.update(WAYPOINTS_TABLE, values, where, selectionArgs);
} else if (match == WAYPOINTS_ID) {
String segment = url.getPathSegments().get(1);
count = db.update(WAYPOINTS_TABLE, values, "_id=" + segment
+ (!TextUtils.isEmpty(where)
? " AND (" + where + ')'
: ""),
selectionArgs);
} else {
throw new IllegalArgumentException("Unknown URL " + url);
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
if (!canAccess()) {
return 0;
}
getContext().getContentResolver().notifyChange(url, null, true);
return count;
return super.update(getDatabaseProviderUri(uri), values, selection, selectionArgs);
}
}
@@ -0,0 +1,37 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.content;
import android.content.Context;
/**
* A factory to return a new {@link MyTracksProviderUtils} that can access the
* Database content provider, {@link DatabaseProvider}.
*
* @author jshih@google.com (Jimmy Shih)
*/
public class MyTracksProviderUtilsFactory {
/**
* Creates a new instance of {@link MyTracksProviderUtils} that uses the given
* context to access the Database content provider, {@link DatabaseProvider}.
*/
public static MyTracksProviderUtils get(Context context) {
return new MyTracksProviderUtilsImpl(
context.getContentResolver(), MyTracksProviderUtils.DATABASE_AUTHORITY);
}
}
@@ -202,7 +202,7 @@ public class TrackDataHub {
*/
public synchronized static TrackDataHub newInstance(Context context) {
SharedPreferences preferences = context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
MyTracksProviderUtils providerUtils = MyTracksProviderUtils.Factory.get(context);
MyTracksProviderUtils providerUtils = MyTracksProviderUtilsFactory.get(context);
return new TrackDataHub(context,
new TrackDataListeners(),
preferences, providerUtils,
@@ -17,7 +17,7 @@ package com.google.android.apps.mytracks.io;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.ProgressIndicator;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsFactory;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.io.docs.DocsHelper;
import com.google.android.apps.mytracks.io.gdata.GDataClientFactory;
@@ -102,8 +102,7 @@ public class SendToDocs {
}
// Get the track from the provider:
Track track =
MyTracksProviderUtils.Factory.get(activity).getTrack(trackId);
Track track = MyTracksProviderUtilsFactory.get(activity).getTrack(trackId);
if (track == null) {
Log.w(Constants.TAG, "Cannot get track.");
return;
@@ -20,6 +20,7 @@ import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.ProgressIndicator;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsFactory;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.io.gdata.GDataWrapper;
@@ -138,7 +139,7 @@ public class SendToFusionTables implements Runnable {
this.progressIndicator = progressIndicator;
this.onCompletion = onCompletion;
this.stringUtils = new StringUtils(context);
this.providerUtils = MyTracksProviderUtils.Factory.get(context);
this.providerUtils = MyTracksProviderUtilsFactory.get(context);
HttpTransport transport = ApiFeatures.getInstance().useNetHttpTransport()
? new NetHttpTransport() : new ApacheHttpTransport();
@@ -16,9 +16,11 @@
package com.google.android.apps.mytracks.io;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.ProgressIndicator;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsFactory;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.io.mymaps.MapsFacade;
@@ -87,7 +89,7 @@ public class SendToMyMaps implements Runnable {
this.progressIndicator = progressIndicator;
this.onCompletion = onCompletion;
this.stringUtils = new StringUtils(context);
this.providerUtils = MyTracksProviderUtils.Factory.get(context);
this.providerUtils = MyTracksProviderUtilsFactory.get(context);
}
@Override
@@ -177,7 +177,7 @@ class ExternalFileBackup {
// Dump the entire contents of each table
ContentResolver contentResolver = context.getContentResolver();
Cursor tracksCursor = contentResolver.query(
TracksColumns.CONTENT_URI, null, null, null, null);
TracksColumns.DATABASE_CONTENT_URI, null, null, null, null);
try {
trackDumper.writeAllRows(tracksCursor, outWriter);
} finally {
@@ -185,7 +185,7 @@ class ExternalFileBackup {
}
Cursor waypointsCursor = contentResolver.query(
WaypointsColumns.CONTENT_URI, null, null, null, null);
WaypointsColumns.DATABASE_CONTENT_URI, null, null, null, null);
try {
waypointDumper.writeAllRows(waypointsCursor, outWriter);
} finally {
@@ -193,7 +193,7 @@ class ExternalFileBackup {
}
Cursor pointsCursor = contentResolver.query(
TrackPointsColumns.CONTENT_URI, null, null, null, null);
TrackPointsColumns.DATABASE_CONTENT_URI, null, null, null, null);
try {
pointDumper.writeAllRows(pointsCursor, outWriter);
} finally {
@@ -227,12 +227,12 @@ class ExternalFileBackup {
PreferenceBackupHelper preferencesHelper = new PreferenceBackupHelper();
ContentResolver resolver = context.getContentResolver();
DatabaseImporter trackImporter =
new DatabaseImporter(TracksColumns.CONTENT_URI, resolver, false);
DatabaseImporter waypointImporter =
new DatabaseImporter(WaypointsColumns.CONTENT_URI, resolver, false);
DatabaseImporter pointImporter =
new DatabaseImporter(TrackPointsColumns.CONTENT_URI, resolver, false);
DatabaseImporter trackImporter = new DatabaseImporter(
TracksColumns.DATABASE_CONTENT_URI, resolver, false);
DatabaseImporter waypointImporter = new DatabaseImporter(
WaypointsColumns.DATABASE_CONTENT_URI, resolver, false);
DatabaseImporter pointImporter = new DatabaseImporter(
TrackPointsColumns.DATABASE_CONTENT_URI, resolver, false);
ZipFile zipFile = new ZipFile(inputFile, ZipFile.OPEN_READ);
ZipEntry zipEntry = zipFile.getEntry(ZIP_ENTRY_NAME);
@@ -245,9 +245,9 @@ class ExternalFileBackup {
try {
// Delete all previous contents of the tables and preferences.
resolver.delete(TracksColumns.CONTENT_URI, null, null);
resolver.delete(TrackPointsColumns.CONTENT_URI, null, null);
resolver.delete(WaypointsColumns.CONTENT_URI, null, null);
resolver.delete(TracksColumns.DATABASE_CONTENT_URI, null, null);
resolver.delete(TrackPointsColumns.DATABASE_CONTENT_URI, null, null);
resolver.delete(WaypointsColumns.DATABASE_CONTENT_URI, null, null);
// Import the new contents of each table
trackImporter.importAllRows(reader);
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks.io.file;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsFactory;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.util.UriUtils;
import com.google.android.maps.mytracks.R;
@@ -64,7 +65,7 @@ public class ImportActivity extends Activity {
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
providerUtils = MyTracksProviderUtils.Factory.get(this);
providerUtils = MyTracksProviderUtilsFactory.get(this);
}
@Override
@@ -147,7 +148,7 @@ public class ImportActivity extends Activity {
protected void showImportedTrack() {
long lastTrackId = importedTrackIds[importedTrackIds.length - 1];
Uri trackUri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, lastTrackId);
Uri trackUri = ContentUris.withAppendedId(TracksColumns.DATABASE_CONTENT_URI, lastTrackId);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(trackUri, TracksColumns.CONTENT_ITEMTYPE);
@@ -19,6 +19,7 @@ import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsFactory;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.util.FileUtils;
@@ -63,7 +64,7 @@ public class SaveActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
providerUtils = MyTracksProviderUtils.Factory.get(this);
providerUtils = MyTracksProviderUtilsFactory.get(this);
}
@Override
@@ -74,9 +75,9 @@ public class SaveActivity extends Activity {
String action = intent.getAction();
String type = intent.getType();
Uri data = intent.getData();
if (!getString(R.string.save_intent_action).equals(action) ||
!TracksColumns.CONTENT_ITEMTYPE.equals(type) ||
!UriUtils.matchesContentUri(data, TracksColumns.CONTENT_URI)) {
if (!getString(R.string.save_intent_action).equals(action)
|| !TracksColumns.CONTENT_ITEMTYPE.equals(type)
|| !UriUtils.matchesContentUri(data, TracksColumns.DATABASE_CONTENT_URI)) {
Log.e(TAG, "Got bad save intent: " + intent);
finish();
return;
@@ -224,7 +225,7 @@ public class SaveActivity extends Activity {
shareFile = true;
}
Uri uri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId);
Uri uri = ContentUris.withAppendedId(TracksColumns.DATABASE_CONTENT_URI, trackId);
Intent intent = new Intent(ctx, SaveActivity.class);
intent.setAction(ctx.getString(R.string.save_intent_action));
@@ -23,6 +23,7 @@ import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.MyMapsList;
import com.google.android.apps.mytracks.ProgressIndicator;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsFactory;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.io.AuthManager;
@@ -158,7 +159,7 @@ public class SendActivity extends Activity implements ProgressIndicator {
Log.d(TAG, "SendActivity.onCreate");
super.onCreate(savedInstanceState);
providerUtils = MyTracksProviderUtils.Factory.get(this);
providerUtils = MyTracksProviderUtilsFactory.get(this);
sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
tracker = GoogleAnalyticsTracker.getInstance();
@@ -197,9 +198,8 @@ public class SendActivity extends Activity implements ProgressIndicator {
String action = intent.getAction();
String type = intent.getType();
Uri data = intent.getData();
if (!Intent.ACTION_SEND.equals(action) ||
!TracksColumns.CONTENT_ITEMTYPE.equals(type) ||
!UriUtils.matchesContentUri(data, TracksColumns.CONTENT_URI)) {
if (!Intent.ACTION_SEND.equals(action) || !TracksColumns.CONTENT_ITEMTYPE.equals(type)
|| !UriUtils.matchesContentUri(data, TracksColumns.DATABASE_CONTENT_URI)) {
Log.e(TAG, "Got bad send intent: " + intent);
return false;
}
@@ -911,7 +911,7 @@ public class SendActivity extends Activity implements ProgressIndicator {
}
public static void sendToGoogle(Context ctx, long trackId, boolean shareLink) {
Uri uri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId);
Uri uri = ContentUris.withAppendedId(TracksColumns.DATABASE_CONTENT_URI, trackId);
Intent intent = new Intent(ctx, SendActivity.class);
intent.setAction(Intent.ACTION_SEND);
@@ -18,7 +18,7 @@ package com.google.android.apps.mytracks.maps;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsFactory;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.maps.mytracks.R;
@@ -104,7 +104,7 @@ public class DynamicSpeedTrackPathDescriptor
// Could not find track.
return false;
}
Track track = MyTracksProviderUtils.Factory.get(context).getTrack(currentTrackId);
Track track = MyTracksProviderUtilsFactory.get(context).getTrack(currentTrackId);
TripStatistics stats = track.getStatistics();
double newaverageSpeed = (int) Math.floor(stats.getAverageMovingSpeed() * 3.6);
@@ -235,6 +235,11 @@ public class TrackRecordingService extends Service {
public void onCreate() {
super.onCreate();
Log.d(TAG, "TrackRecordingService.onCreate");
/*
* Use the MyTracksProviderUtils that access the MyTracksProvider because
* this service can be called by MyTracks or another app.
*/
providerUtils = MyTracksProviderUtils.Factory.get(this);
notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
@@ -21,6 +21,7 @@ import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.MyTracks;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.MyTracksProviderUtilsFactory;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.services.ControlRecordingService;
@@ -91,7 +92,7 @@ public class TrackWidgetProvider
}
this.context = context;
trackObserver = new TrackObserver();
providerUtils = MyTracksProviderUtils.Factory.get(context);
providerUtils = MyTracksProviderUtilsFactory.get(context);
unknown = context.getString(R.string.unknown);
sharedPreferences = context.getSharedPreferences(SETTINGS_NAME, 0);
@@ -99,7 +100,7 @@ public class TrackWidgetProvider
onSharedPreferenceChanged(sharedPreferences, null);
context.getContentResolver().registerContentObserver(
TracksColumns.CONTENT_URI, true, trackObserver);
TracksColumns.DATABASE_CONTENT_URI, true, trackObserver);
TRACK_STARTED_ACTION = context.getString(R.string.track_started_broadcast_action);
TRACK_STOPPED_ACTION = context.getString(R.string.track_stopped_broadcast_action);
}