forked from upstream-mirrors/OpenTracks
Merge heads
This commit is contained in:
@@ -63,6 +63,7 @@ limitations under the License.
|
||||
<string name="auto_resume_track_current_retry_key">autoResumeTrackCurrentRetry</string>
|
||||
<string name="bluetooth_sensor_key">bluetoothSensor</string>
|
||||
<string name="drive_deleted_list_key">driveDeletedList</string>
|
||||
<string name="drive_edited_list_key">driveEditedList</string>
|
||||
<string name="drive_largest_change_id_key">driveLargestChangeId</string>
|
||||
<string name="drive_sync_key">driveSync</string>
|
||||
<string name="google_account_key">googleAccount</string>
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.google.android.apps.mytracks;
|
||||
*/
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.io.sync.SyncUtils;
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
@@ -97,7 +98,19 @@ public class DeleteAsyncTask extends AsyncTask<Void, Integer, Boolean> {
|
||||
if (isCancelled()) {
|
||||
return false;
|
||||
}
|
||||
Track track = myTracksProviderUtils.getTrack(id);
|
||||
myTracksProviderUtils.deleteTrack(id);
|
||||
if (track != null) {
|
||||
String driveId = track.getDriveId();
|
||||
if (driveId != null && !driveId.equals("")) {
|
||||
boolean driveSync = PreferencesUtils.getBoolean(
|
||||
context, R.string.drive_sync_key, PreferencesUtils.DRIVE_SYNC_DEFAULT);
|
||||
if (driveSync) {
|
||||
PreferencesUtils.addToList(context, R.string.drive_deleted_list_key,
|
||||
PreferencesUtils.DRIVE_DELETED_LIST_DEFAULT, driveId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -17,10 +17,12 @@
|
||||
package com.google.android.apps.mytracks;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.content.Waypoint.WaypointType;
|
||||
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
|
||||
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
@@ -123,6 +125,17 @@ public class MarkerEditActivity extends AbstractMyTracksActivity {
|
||||
} else {
|
||||
saveMarker();
|
||||
}
|
||||
boolean driveSync = PreferencesUtils.getBoolean(
|
||||
MarkerEditActivity.this, R.string.drive_sync_key, PreferencesUtils.DRIVE_SYNC_DEFAULT);
|
||||
if (driveSync) {
|
||||
MyTracksProviderUtils myTracksProviderUtils = MyTracksProviderUtils.Factory.get(
|
||||
MarkerEditActivity.this);
|
||||
Track track = myTracksProviderUtils.getTrack(newMarker ? trackId : waypoint.getTrackId());
|
||||
track.setModifiedTime(System.currentTimeMillis());
|
||||
myTracksProviderUtils.updateTrack(track);
|
||||
PreferencesUtils.addToList(MarkerEditActivity.this, R.string.drive_edited_list_key,
|
||||
PreferencesUtils.DRIVE_EDITED_LIST_DEFAULT, String.valueOf(track.getId()));
|
||||
}
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -79,7 +79,6 @@ public class TrackDetailActivity extends AbstractSendToGoogleActivity implements
|
||||
public static final String EXTRA_TRACK_ID = "track_id";
|
||||
public static final String EXTRA_MARKER_ID = "marker_id";
|
||||
|
||||
private static final String TAG = TrackDetailActivity.class.getSimpleName();
|
||||
private static final String CURRENT_TAB_TAG_KEY = "current_tab_tag_key";
|
||||
private static final String PHOTO_URI_KEY = "photo_uri_key";
|
||||
private static final String HAS_PHOTO_KEY = "has_photo_key";
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.google.android.apps.mytracks.fragments.ChooseActivityTypeDialogFragme
|
||||
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
|
||||
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||
import com.google.android.apps.mytracks.util.CalorieUtils;
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.apps.mytracks.util.TrackIconUtils;
|
||||
import com.google.android.apps.mytracks.util.TrackNameUtils;
|
||||
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
|
||||
@@ -199,6 +200,12 @@ public class TrackEditActivity extends AbstractMyTracksActivity
|
||||
track.setDescription(description.getText().toString());
|
||||
track.setModifiedTime(System.currentTimeMillis());
|
||||
myTracksProviderUtils.updateTrack(track);
|
||||
boolean driveSync = PreferencesUtils.getBoolean(
|
||||
TrackEditActivity.this, R.string.drive_sync_key, PreferencesUtils.DRIVE_SYNC_DEFAULT);
|
||||
if (driveSync) {
|
||||
PreferencesUtils.addToList(TrackEditActivity.this, R.string.drive_edited_list_key,
|
||||
PreferencesUtils.DRIVE_EDITED_LIST_DEFAULT, String.valueOf(track.getId()));
|
||||
}
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.google.android.apps.mytracks.content;
|
||||
|
||||
import com.google.android.apps.mytracks.io.sync.SyncUtils;
|
||||
import com.google.android.apps.mytracks.util.FileUtils;
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
@@ -42,7 +41,6 @@ import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* A {@link ContentProvider} that handles access to track points, tracks, and
|
||||
@@ -218,18 +216,6 @@ public class MyTracksProvider extends ContentProvider {
|
||||
throw new IllegalArgumentException("Unknown URL " + url);
|
||||
}
|
||||
|
||||
boolean driveSync = false;
|
||||
String driveIds = "";
|
||||
if (table.equals(TracksColumns.TABLE_NAME)) {
|
||||
driveSync = PreferencesUtils.getBoolean(
|
||||
getContext(), R.string.drive_sync_key, PreferencesUtils.DRIVE_SYNC_DEFAULT);
|
||||
if (driveSync) {
|
||||
driveIds = where != null ? getDriveIds(null, where, selectionArgs)
|
||||
: getDriveIds(
|
||||
new String[] { TracksColumns.DRIVEID }, SyncUtils.DRIVE_ID_TRACKS_QUERY, null);
|
||||
}
|
||||
}
|
||||
|
||||
Log.w(MyTracksProvider.TAG, "Deleting table " + table);
|
||||
int count;
|
||||
try {
|
||||
@@ -240,17 +226,6 @@ public class MyTracksProvider extends ContentProvider {
|
||||
db.endTransaction();
|
||||
}
|
||||
getContext().getContentResolver().notifyChange(url, null, false);
|
||||
|
||||
if (driveSync && table.equals(TracksColumns.TABLE_NAME)) {
|
||||
String driveDeletedList = PreferencesUtils.getString(getContext(),
|
||||
R.string.drive_deleted_list_key, PreferencesUtils.DRIVE_DELETED_LIST_DEFAULT);
|
||||
if (driveDeletedList.equals(PreferencesUtils.DRIVE_DELETED_LIST_DEFAULT)) {
|
||||
driveDeletedList = driveIds;
|
||||
} else {
|
||||
driveDeletedList += ";" + driveIds;
|
||||
}
|
||||
PreferencesUtils.setString(getContext(), R.string.drive_deleted_list_key, driveDeletedList);
|
||||
}
|
||||
|
||||
if (shouldVacuum) {
|
||||
// If a potentially large amount of data was deleted, reclaim its space.
|
||||
@@ -536,33 +511,4 @@ public class MyTracksProvider extends ContentProvider {
|
||||
}
|
||||
throw new SQLException("Failed to insert a waypoint " + url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of dirve ids.
|
||||
*
|
||||
* @param projection the projection
|
||||
* @param where where
|
||||
* @param selectionArgs selection args
|
||||
*/
|
||||
private String getDriveIds(String[] projection, String where, String[] selectionArgs) {
|
||||
ArrayList<String> driveIds = new ArrayList<String>();
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = query(TracksColumns.CONTENT_URI, projection, where, selectionArgs, null);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
int index = cursor.getColumnIndex(TracksColumns.DRIVEID);
|
||||
do {
|
||||
String driveId = cursor.getString(index);
|
||||
if (driveId != null && !driveId.equals("")) {
|
||||
driveIds.add(driveId);
|
||||
}
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
return TextUtils.join(";", driveIds);
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import com.google.android.apps.mytracks.util.UnitConversions;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
@@ -188,7 +189,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
public void onSampledInTrackPoint(Location location) {
|
||||
if (isResumed()) {
|
||||
double[] data = new double[ChartView.NUM_SERIES + 1];
|
||||
fillDataPoint(location, data);
|
||||
fillDataPoint(location, data, getActivity());
|
||||
pendingPoints.add(data);
|
||||
}
|
||||
}
|
||||
@@ -196,14 +197,14 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
@Override
|
||||
public void onSampledOutTrackPoint(Location location) {
|
||||
if (isResumed()) {
|
||||
fillDataPoint(location, null);
|
||||
fillDataPoint(location, null, getActivity());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSegmentSplit(Location location) {
|
||||
if (isResumed()) {
|
||||
fillDataPoint(location, null);
|
||||
fillDataPoint(location, null, getActivity());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,9 +440,10 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
*
|
||||
* @param location the location
|
||||
* @param data the data point to fill in, can be null
|
||||
* @param context the context
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void fillDataPoint(Location location, double data[]) {
|
||||
void fillDataPoint(Location location, double data[], Context context) {
|
||||
double timeOrDistance = Double.NaN;
|
||||
double elevation = Double.NaN;
|
||||
double speed = Double.NaN;
|
||||
@@ -451,7 +453,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
||||
double power = Double.NaN;
|
||||
|
||||
if (tripStatisticsUpdater != null) {
|
||||
tripStatisticsUpdater.addLocation(location, recordingDistanceInterval, getActivity());
|
||||
tripStatisticsUpdater.addLocation(location, recordingDistanceInterval, context);
|
||||
TripStatistics tripStatistics = tripStatisticsUpdater.getTripStatistics();
|
||||
if (chartByDistance) {
|
||||
double distance = tripStatistics.getTotalDistance() * UnitConversions.M_TO_KM;
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.google.android.apps.mytracks.content.ContentTypeIds;
|
||||
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
@@ -52,6 +53,7 @@ public class PreferenceBackupHelper {
|
||||
doNotBackup.add(context.getString(R.string.auto_resume_track_current_retry_key));
|
||||
doNotBackup.add(context.getString(R.string.bluetooth_sensor_key));
|
||||
doNotBackup.add(context.getString(R.string.drive_deleted_list_key));
|
||||
doNotBackup.add(context.getString(R.string.drive_edited_list_key));
|
||||
doNotBackup.add(context.getString(R.string.drive_largest_change_id_key));
|
||||
doNotBackup.add(context.getString(R.string.drive_sync_key));
|
||||
doNotBackup.add(context.getString(R.string.google_account_key));
|
||||
@@ -117,6 +119,7 @@ public class PreferenceBackupHelper {
|
||||
* @param preferences the shared preferences to edit
|
||||
* @throws IOException if there are any errors while reading
|
||||
*/
|
||||
@SuppressLint("CommitPrefEdits")
|
||||
public void importPreferences(DataInputStream reader, SharedPreferences preferences)
|
||||
throws IOException {
|
||||
Editor editor = preferences.edit();
|
||||
|
||||
@@ -90,14 +90,16 @@ public class SendDriveAsyncTask extends AbstractSendAsyncTask {
|
||||
String driveId = track.getDriveId();
|
||||
if (driveId != null && !driveId.equals("")) {
|
||||
File driveFile = drive.files().get(driveId).execute();
|
||||
if (SyncUtils.isValid(driveFile, folderId) && SyncUtils.updateDriveFile(
|
||||
drive, driveFile, context, myTracksProviderUtils, track, false)) {
|
||||
if (driveFile != null && updateDriveFile(drive, driveFile, folderId, track)) {
|
||||
addPermission(drive, driveFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
// clear sync state
|
||||
SyncUtils.updateTrack(myTracksProviderUtils, track, null);
|
||||
}
|
||||
|
||||
// insert new drive file
|
||||
File file = SyncUtils.insertDriveFile(
|
||||
drive, folderId, context, myTracksProviderUtils, track, false);
|
||||
if (file == null) {
|
||||
@@ -119,6 +121,29 @@ public class SendDriveAsyncTask extends AbstractSendAsyncTask {
|
||||
return retryTask();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a drive file using info from a track. Returns true if successful.
|
||||
*
|
||||
* @param drive the drive
|
||||
* @param driveFile the drive file
|
||||
* @param folderId the folder id of the drive file
|
||||
* @param track the track
|
||||
*/
|
||||
private boolean updateDriveFile(Drive drive, File driveFile, String folderId, Track track)
|
||||
throws IOException {
|
||||
if (!SyncUtils.isInMyTracksAndValid(driveFile, folderId)) {
|
||||
return false;
|
||||
}
|
||||
long driveModifiedTime = driveFile.getModifiedDate().getValue();
|
||||
long modifiedTime = track.getModifiedTime();
|
||||
|
||||
if (driveModifiedTime != modifiedTime) {
|
||||
return SyncUtils.updateDriveFile(
|
||||
drive, driveFile, context, myTracksProviderUtils, track, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invalidateToken() {}
|
||||
|
||||
@@ -57,6 +57,7 @@ import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -77,7 +78,8 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
private final MyTracksProviderUtils myTracksProviderUtils;
|
||||
private Drive drive;
|
||||
private String driveAccountName; // the account name associated with the drive
|
||||
|
||||
private String folderId;
|
||||
|
||||
public SyncAdapter(Context context) {
|
||||
super(context, true);
|
||||
this.context = context;
|
||||
@@ -118,22 +120,14 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
driveAccountName = account.name;
|
||||
}
|
||||
|
||||
File folder = SyncUtils.getMyTracksFolder(context, drive);
|
||||
if (folder == null) {
|
||||
return;
|
||||
}
|
||||
String folderId = folder.getId();
|
||||
if (folderId == null) {
|
||||
return;
|
||||
}
|
||||
long largestChangeId = PreferencesUtils.getLong(
|
||||
context, R.string.drive_largest_change_id_key);
|
||||
if (largestChangeId == PreferencesUtils.DRIVE_LARGEST_CHANGE_ID_DEFAULT) {
|
||||
performInitialSync(folderId);
|
||||
performInitialSync();
|
||||
} else {
|
||||
performIncrementalSync(folderId, largestChangeId);
|
||||
performIncrementalSync(largestChangeId);
|
||||
}
|
||||
insertNewDriveFiles(folderId);
|
||||
insertNewDriveFiles();
|
||||
} catch (UserRecoverableAuthException e) {
|
||||
SendToGoogleUtils.sendNotification(
|
||||
context, account.name, e.getIntent(), SendToGoogleUtils.DRIVE_NOTIFICATION_ID);
|
||||
@@ -148,23 +142,38 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs initial sync.
|
||||
*
|
||||
* @param folderId the folder id
|
||||
* Gets the folder id..
|
||||
*/
|
||||
private void performInitialSync(String folderId) throws IOException {
|
||||
private String getFolderId() throws IOException {
|
||||
if (folderId == null) {
|
||||
File folder = SyncUtils.getMyTracksFolder(context, drive);
|
||||
if (folder == null) {
|
||||
throw new IOException("folder is null");
|
||||
}
|
||||
folderId = folder.getId();
|
||||
if (folderId == null) {
|
||||
throw new IOException("folder id is null");
|
||||
}
|
||||
}
|
||||
return folderId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs initial sync.
|
||||
*/
|
||||
private void performInitialSync() throws IOException {
|
||||
|
||||
// Get the largest change id first to avoid race conditions
|
||||
About about = drive.about().get().setFields(ABOUT_GET_FIELDS).execute();
|
||||
long largestChangeId = about.getLargestChangeId();
|
||||
|
||||
// Get all the KML/KMZ files in the "My Drive:/My Tracks" folder
|
||||
Files.List myTracksFolderRequest = drive.files()
|
||||
.list().setQ(String.format(Locale.US, SyncUtils.MY_TRACKS_FOLDER_FILES_QUERY, folderId));
|
||||
Files.List myTracksFolderRequest = drive.files().list()
|
||||
.setQ(String.format(Locale.US, SyncUtils.MY_TRACKS_FOLDER_FILES_QUERY, getFolderId()));
|
||||
Map<String, File> myTracksFolderMap = getFiles(myTracksFolderRequest, true);
|
||||
|
||||
// Handle tracks that are already uploaded to Google Drive
|
||||
Set<String> syncedDriveIds = updateSyncedTracks(folderId);
|
||||
Set<String> syncedDriveIds = updateSyncedTracks();
|
||||
for (String driveId : syncedDriveIds) {
|
||||
myTracksFolderMap.remove(driveId);
|
||||
}
|
||||
@@ -204,10 +213,9 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
/**
|
||||
* Updates synced tracks.
|
||||
*
|
||||
* @param folderId the folder id
|
||||
* @return drive ids of the synced tracks
|
||||
*/
|
||||
private Set<String> updateSyncedTracks(String folderId) throws IOException {
|
||||
private Set<String> updateSyncedTracks() throws IOException {
|
||||
Set<String> result = new HashSet<String>();
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
@@ -219,7 +227,7 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
if (driveId != null && !driveId.equals("")) {
|
||||
if (!track.isSharedWithMe()) {
|
||||
File driveFile = drive.files().get(driveId).execute();
|
||||
if (SyncUtils.isValid(driveFile, folderId)) {
|
||||
if (SyncUtils.isInMyTracksAndValid(driveFile, getFolderId())) {
|
||||
merge(track, driveFile);
|
||||
result.add(driveId);
|
||||
} else {
|
||||
@@ -245,79 +253,107 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
/**
|
||||
* Performs incremental sync.
|
||||
*
|
||||
* @param folderId the folder id
|
||||
* @param largestChangeId the largest change id
|
||||
*/
|
||||
private void performIncrementalSync(String folderId, long largestChangeId) throws IOException {
|
||||
private void performIncrementalSync(long largestChangeId) throws IOException {
|
||||
|
||||
// Handle deleted tracks
|
||||
String driveDeletedList = PreferencesUtils.getString(
|
||||
context, R.string.drive_deleted_list_key, PreferencesUtils.DRIVE_DELETED_LIST_DEFAULT);
|
||||
String deletedIds[] = TextUtils.split(driveDeletedList, ";");
|
||||
for (String driveId : deletedIds) {
|
||||
deleteDriveFile(driveId, folderId, true);
|
||||
}
|
||||
PreferencesUtils.setString(
|
||||
context, R.string.drive_deleted_list_key, PreferencesUtils.DRIVE_DELETED_LIST_DEFAULT);
|
||||
|
||||
Map<String, File> changes = new HashMap<String, File>();
|
||||
largestChangeId = getDriveChangesInfo(folderId, largestChangeId, changes);
|
||||
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
// Get all the local tracks with drive file id
|
||||
cursor = myTracksProviderUtils.getTrackCursor(SyncUtils.DRIVE_ID_TRACKS_QUERY, null, null);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
do {
|
||||
Track track = myTracksProviderUtils.createTrack(cursor);
|
||||
String driveId = track.getDriveId();
|
||||
|
||||
if (changes.containsKey(driveId)) {
|
||||
|
||||
// Track has changed
|
||||
File driveFile = changes.get(driveId);
|
||||
if (driveFile == null) {
|
||||
Log.d(TAG, "Delete local track " + track.getName());
|
||||
myTracksProviderUtils.deleteTrack(track.getId());
|
||||
} else {
|
||||
merge(track, driveFile);
|
||||
}
|
||||
changes.remove(driveId);
|
||||
} else {
|
||||
if (!track.isSharedWithMe()) {
|
||||
|
||||
// Handle the case the track has changed
|
||||
File driveFile = drive.files().get(driveId).execute();
|
||||
if (SyncUtils.isValid(driveFile, folderId)) {
|
||||
merge(track, driveFile);
|
||||
} else {
|
||||
/*
|
||||
* Track has a drive id, but the drive id is no longer valid.
|
||||
* E.g., the file is moved to another folder. Clear the drive
|
||||
* id.
|
||||
*/
|
||||
SyncUtils.updateTrack(myTracksProviderUtils, track, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (cursor.moveToNext());
|
||||
if (!PreferencesUtils.DRIVE_DELETED_LIST_DEFAULT.equals(driveDeletedList)) {
|
||||
String deletedIds[] = TextUtils.split(driveDeletedList, ";");
|
||||
for (String driveId : deletedIds) {
|
||||
deleteDriveFile(driveId, true);
|
||||
}
|
||||
PreferencesUtils.setString(
|
||||
context, R.string.drive_deleted_list_key, PreferencesUtils.DRIVE_DELETED_LIST_DEFAULT);
|
||||
}
|
||||
|
||||
// Insert new tracks from new drive files
|
||||
insertNewTracks(changes.values());
|
||||
PreferencesUtils.setLong(context, R.string.drive_largest_change_id_key, largestChangeId);
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
// Handle edited tracks
|
||||
String driveEditedList = PreferencesUtils.getString(
|
||||
context, R.string.drive_edited_list_key, PreferencesUtils.DRIVE_EDITED_LIST_DEFAULT);
|
||||
if (!PreferencesUtils.DRIVE_EDITED_LIST_DEFAULT.equals(driveEditedList)) {
|
||||
String editedIds[] = TextUtils.split(driveEditedList, ";");
|
||||
for (String id : editedIds) {
|
||||
Track track = myTracksProviderUtils.getTrack(Long.valueOf(id));
|
||||
if (track == null) {
|
||||
continue;
|
||||
}
|
||||
if (track.isSharedWithMe()) {
|
||||
continue;
|
||||
}
|
||||
String driveId = track.getDriveId();
|
||||
if (driveId == null || driveId.equals("")) {
|
||||
continue;
|
||||
}
|
||||
File driveFile = drive.files().get(driveId).execute();
|
||||
if (SyncUtils.isInMyTracksAndValid(driveFile, getFolderId())) {
|
||||
merge(track, driveFile);
|
||||
}
|
||||
}
|
||||
PreferencesUtils.setString(
|
||||
context, R.string.drive_edited_list_key, PreferencesUtils.DRIVE_EDITED_LIST_DEFAULT);
|
||||
}
|
||||
|
||||
// Handle changes from Google Drive
|
||||
Map<String, File> changes = new HashMap<String, File>();
|
||||
long newLargestChangeId = getDriveChangesInfo(largestChangeId, changes);
|
||||
if (newLargestChangeId != largestChangeId) {
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
// Get all the local tracks with drive file id
|
||||
cursor = myTracksProviderUtils.getTrackCursor(SyncUtils.DRIVE_ID_TRACKS_QUERY, null, null);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
do {
|
||||
Track track = myTracksProviderUtils.createTrack(cursor);
|
||||
String driveId = track.getDriveId();
|
||||
|
||||
if (changes.containsKey(driveId)) {
|
||||
|
||||
// Track has changed
|
||||
File driveFile = changes.get(driveId);
|
||||
if (driveFile == null) {
|
||||
Log.d(TAG, "Delete local track " + track.getName());
|
||||
myTracksProviderUtils.deleteTrack(track.getId());
|
||||
} else {
|
||||
if (SyncUtils.isInMyTracksAndValid(driveFile, getFolderId())
|
||||
|| SyncUtils.isInSharedWithMe(driveFile)) {
|
||||
merge(track, driveFile);
|
||||
} else {
|
||||
SyncUtils.updateTrack(myTracksProviderUtils, track, null);
|
||||
}
|
||||
}
|
||||
changes.remove(driveId);
|
||||
}
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
|
||||
// Insert valid new drive file changes as new tracks
|
||||
Iterator<String> iterator = changes.keySet().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
String driveId = iterator.next();
|
||||
File file = changes.get(driveId);
|
||||
if (!SyncUtils.isInMyTracksAndValid(file, getFolderId())
|
||||
&& !SyncUtils.isInSharedWithMeAndValid(file)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
insertNewTracks(changes.values());
|
||||
PreferencesUtils.setLong(context, R.string.drive_largest_change_id_key, newLargestChangeId);
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts new drive files from tracks without a drive id.
|
||||
*
|
||||
* @param folderId the folder id
|
||||
*/
|
||||
private void insertNewDriveFiles(String folderId) throws IOException {
|
||||
private void insertNewDriveFiles() throws IOException {
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = myTracksProviderUtils.getTrackCursor(SyncUtils.NO_DRIVE_ID_TRACKS_QUERY, null, null);
|
||||
@@ -330,7 +366,8 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
continue;
|
||||
}
|
||||
// If not successful, the next sync will retry again
|
||||
SyncUtils.insertDriveFile(drive, folderId, context, myTracksProviderUtils, track, true);
|
||||
SyncUtils.insertDriveFile(
|
||||
drive, getFolderId(), context, myTracksProviderUtils, track, true);
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
} finally {
|
||||
@@ -350,17 +387,7 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
if (driveFile == null) {
|
||||
return;
|
||||
}
|
||||
boolean success = false;
|
||||
long trackId = -1L;
|
||||
try {
|
||||
Uri uri = myTracksProviderUtils.insertTrack(new Track());
|
||||
trackId = Long.parseLong(uri.getLastPathSegment());
|
||||
success = updateTrack(trackId, driveFile);
|
||||
} finally {
|
||||
if (!success && trackId != -1L) {
|
||||
myTracksProviderUtils.deleteTrack(trackId);
|
||||
}
|
||||
}
|
||||
updateTrack(-1L, driveFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,12 +418,11 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
/**
|
||||
* Gets the drive changes info in the My Tracks folder, including deleted files.
|
||||
*
|
||||
* @param folderId the folder id
|
||||
* @param changeId the largest change id
|
||||
* @param changes a map of drive id to file for the changes
|
||||
* @return an updated largest change id
|
||||
*/
|
||||
private long getDriveChangesInfo(String folderId, long changeId, Map<String, File> changes)
|
||||
private long getDriveChangesInfo(long changeId, Map<String, File> changes)
|
||||
throws IOException {
|
||||
Changes.List request = drive.changes().list().setStartChangeId(changeId + 1);
|
||||
do {
|
||||
@@ -408,12 +434,10 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
changes.put(change.getFileId(), null);
|
||||
} else {
|
||||
File file = change.getFile();
|
||||
if (SyncUtils.isInFolder(file, folderId) || SyncUtils.isSharedWithMe(file)) {
|
||||
if (file.getLabels().getTrashed()) {
|
||||
changes.put(change.getFileId(), null);
|
||||
} else {
|
||||
changes.put(change.getFileId(), file);
|
||||
}
|
||||
if (file.getLabels().getTrashed()) {
|
||||
changes.put(change.getFileId(), null);
|
||||
} else {
|
||||
changes.put(change.getFileId(), file);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -449,8 +473,12 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
+ driveFile.getTitle());
|
||||
if (!updateTrack(track.getId(), driveFile)) {
|
||||
Log.e(TAG, "Unable to update drive change");
|
||||
track.setModifiedTime(driveModifiedTime);
|
||||
myTracksProviderUtils.updateTrack(track);
|
||||
// The track could have been deleted in the unsuccessful update
|
||||
track = myTracksProviderUtils.getTrack(track.getId());
|
||||
if (track != null) {
|
||||
track.setModifiedTime(driveModifiedTime);
|
||||
myTracksProviderUtils.updateTrack(track);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -458,7 +486,7 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
/**
|
||||
* Updates a track based on a drive file. Returns true if successful.
|
||||
*
|
||||
* @param trackId the track id
|
||||
* @param trackId the track id. -1L to insert a new track
|
||||
* @param driveFile the drive file
|
||||
*/
|
||||
private boolean updateTrack(long trackId, File driveFile) throws IOException {
|
||||
@@ -501,7 +529,7 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
/**
|
||||
* Imports drive file to track.
|
||||
*
|
||||
* @param trackId the track id
|
||||
* @param trackId the track id. -1L to insert a new track
|
||||
* @param driveFile the drive file
|
||||
*/
|
||||
private Track importDriveFile(long trackId, File driveFile) throws IOException {
|
||||
@@ -509,14 +537,17 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
try {
|
||||
inputStream = downloadDriveFile(driveFile, true);
|
||||
if (inputStream == null) {
|
||||
Log.e(TAG,
|
||||
"Unable to import file. Input stream is null for drive file " + driveFile.getTitle());
|
||||
Log.e(TAG, "Unable to import drive file. Input stream is null.");
|
||||
return null;
|
||||
}
|
||||
|
||||
TrackImporter trackImporter;
|
||||
boolean useKmz = KmzTrackExporter.KMZ_EXTENSION.equals(driveFile.getFileExtension());
|
||||
if (useKmz) {
|
||||
if (trackId == -1L) {
|
||||
Uri uri = myTracksProviderUtils.insertTrack(new Track());
|
||||
trackId = Long.parseLong(uri.getLastPathSegment());
|
||||
}
|
||||
trackImporter = new KmzTrackImporter(context, trackId);
|
||||
} else {
|
||||
trackImporter = new KmlFileTrackImporter(context, trackId);
|
||||
@@ -524,18 +555,18 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
|
||||
long importedId = trackImporter.importFile(inputStream);
|
||||
if (importedId == -1L) {
|
||||
Log.e(TAG, "Unable to merge, imported id is -1L");
|
||||
Log.e(TAG, "Unable to import drive file. Imported id is -1L.");
|
||||
return null;
|
||||
}
|
||||
Track track = myTracksProviderUtils.getTrack(importedId);
|
||||
if (track == null) {
|
||||
Log.e(TAG, "Unable to merge, imported track is null");
|
||||
Log.e(TAG, "Unable to import drive file. Imported track is null.");
|
||||
return null;
|
||||
} else {
|
||||
return track;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Unable to merge", e);
|
||||
Log.e(TAG, "Unable to import drive file.", e);
|
||||
return null;
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
@@ -548,19 +579,19 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
* Deletes a drive file.
|
||||
*
|
||||
* @param driveId the drive id
|
||||
* @param folderId the folder id
|
||||
* @param canRetry true if can retry the request
|
||||
* @throws IOException
|
||||
*/
|
||||
private void deleteDriveFile(String driveId, String folderId, boolean canRetry)
|
||||
throws UserRecoverableAuthIOException {
|
||||
private void deleteDriveFile(String driveId, boolean canRetry)
|
||||
throws IOException {
|
||||
try {
|
||||
File driveFile = drive.files().get(driveId).execute();
|
||||
if (SyncUtils.isInFolder(driveFile, folderId)) {
|
||||
if (SyncUtils.isInMyTracks(driveFile, getFolderId())) {
|
||||
if (!driveFile.getLabels().getTrashed()) {
|
||||
drive.files().trash(driveId).execute();
|
||||
}
|
||||
// if trashed, ignore
|
||||
} else if (SyncUtils.isSharedWithMe(driveFile)) {
|
||||
} else if (SyncUtils.isInSharedWithMe(driveFile)) {
|
||||
if (!driveFile.getLabels().getTrashed()) {
|
||||
drive.files().delete(driveId).execute();
|
||||
}
|
||||
@@ -570,7 +601,7 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
if (canRetry) {
|
||||
deleteDriveFile(driveId, folderId, false);
|
||||
deleteDriveFile(driveId, false);
|
||||
return;
|
||||
}
|
||||
Log.e(TAG, "Unable to delete Drive file for " + driveId, e);
|
||||
|
||||
@@ -47,13 +47,9 @@ import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -189,6 +185,9 @@ public class SyncUtils {
|
||||
PreferencesUtils.setLong(context, R.string.drive_largest_change_id_key,
|
||||
PreferencesUtils.DRIVE_LARGEST_CHANGE_ID_DEFAULT);
|
||||
|
||||
PreferencesUtils.setString(
|
||||
context, R.string.drive_edited_list_key, PreferencesUtils.DRIVE_EDITED_LIST_DEFAULT);
|
||||
|
||||
// Clear the drive_deleted_list_key last
|
||||
PreferencesUtils.setString(
|
||||
context, R.string.drive_deleted_list_key, PreferencesUtils.DRIVE_DELETED_LIST_DEFAULT);
|
||||
@@ -226,40 +225,13 @@ public class SyncUtils {
|
||||
return drive.files().insert(file).execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a drive file is a Shared with me KML or KMZ file.
|
||||
*
|
||||
* @param driveFile the drive file
|
||||
*/
|
||||
public static boolean isSharedWithMe(File driveFile) {
|
||||
if (driveFile == null) {
|
||||
return false;
|
||||
}
|
||||
String mimeType = driveFile.getMimeType();
|
||||
if (!SyncUtils.KML_MIME_TYPE.equals(mimeType) && !SyncUtils.KMZ_MIME_TYPE.equals(mimeType)) {
|
||||
return false;
|
||||
}
|
||||
return driveFile.getSharedWithMeDate() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a drive file is a KML or KMZ file in the My Tracks folder
|
||||
* and not trashed.
|
||||
*
|
||||
* @param driveFile the drive file
|
||||
* @param folderId the My Tracks folder id
|
||||
*/
|
||||
public static boolean isValid(File driveFile, String folderId) {
|
||||
return isInFolder(driveFile, folderId) && !driveFile.getLabels().getTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a drive file is a KML or KMZ file in the My Tracks folder.
|
||||
*
|
||||
* @param driveFile the drive file
|
||||
* @param folderId the My Tracks folder id
|
||||
*/
|
||||
public static boolean isInFolder(File driveFile, String folderId) {
|
||||
public static boolean isInMyTracks(File driveFile, String folderId) {
|
||||
if (driveFile == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -279,6 +251,44 @@ public class SyncUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a drive file is a KML or KMZ file in the My Tracks folder
|
||||
* and not trashed.
|
||||
*
|
||||
* @param driveFile the drive file
|
||||
* @param folderId the My Tracks folder id
|
||||
*/
|
||||
public static boolean isInMyTracksAndValid(File driveFile, String folderId) {
|
||||
return isInMyTracks(driveFile, folderId) && !driveFile.getLabels().getTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a drive file is a KML or KMZ file in the Shared with me
|
||||
* directory.
|
||||
*
|
||||
* @param driveFile the drive file
|
||||
*/
|
||||
public static boolean isInSharedWithMe(File driveFile) {
|
||||
if (driveFile == null) {
|
||||
return false;
|
||||
}
|
||||
String mimeType = driveFile.getMimeType();
|
||||
if (!SyncUtils.KML_MIME_TYPE.equals(mimeType) && !SyncUtils.KMZ_MIME_TYPE.equals(mimeType)) {
|
||||
return false;
|
||||
}
|
||||
return driveFile.getSharedWithMeDate() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a drive file is a KML or KMZ file in the Shared with me
|
||||
* directory and is not trashed.
|
||||
*
|
||||
* @param driveFile the drive file
|
||||
*/
|
||||
public static boolean isInSharedWithMeAndValid(File driveFile) {
|
||||
return isInSharedWithMe(driveFile) && !driveFile.getLabels().getTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a drive file using info from a track.
|
||||
*
|
||||
@@ -372,25 +382,14 @@ public class SyncUtils {
|
||||
|
||||
try {
|
||||
file = SyncUtils.getTempFile(context, myTracksProviderUtils, track, true);
|
||||
|
||||
if (file == null) {
|
||||
Log.e(TAG, "Unable to update drive file. File is null for track " + track.getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
String title = track.getName() + "." + KmzTrackExporter.KMZ_EXTENSION;
|
||||
File updatedFile;
|
||||
String digest = md5(file);
|
||||
if (digest != null && digest.equals(driveFile.getMd5Checksum())) {
|
||||
if (title.equals(driveFile.getTitle())) {
|
||||
updatedFile = driveFile;
|
||||
} else {
|
||||
// Only update the title
|
||||
updatedFile = updateDriveFile(drive, driveFile, title, null, canRetry);
|
||||
}
|
||||
} else {
|
||||
updatedFile = updateDriveFile(drive, driveFile, title, file, canRetry);
|
||||
}
|
||||
File updatedFile = updateDriveFile(drive, driveFile, title, file, canRetry);
|
||||
|
||||
if (updatedFile == null) {
|
||||
Log.e(
|
||||
TAG, "Unable to update drive file. Updated file is null for track " + track.getName());
|
||||
@@ -513,52 +512,4 @@ public class SyncUtils {
|
||||
: "");
|
||||
myTracksProviderUtils.updateTrack(track);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the md5 digest for a file.
|
||||
*
|
||||
* @param file the file
|
||||
*/
|
||||
public static String md5(java.io.File file) {
|
||||
if (file == null) {
|
||||
return null;
|
||||
}
|
||||
InputStream in = null;
|
||||
byte[] digest;
|
||||
try {
|
||||
in = new FileInputStream(file);
|
||||
MessageDigest digester = MessageDigest.getInstance("MD5");
|
||||
byte[] bytes = new byte[8192];
|
||||
int byteCount;
|
||||
while ((byteCount = in.read(bytes)) > 0) {
|
||||
digester.update(bytes, 0, byteCount);
|
||||
}
|
||||
digest = digester.digest();
|
||||
|
||||
StringBuilder builder = new StringBuilder(digest.length * 2);
|
||||
for (byte b : digest) {
|
||||
if ((b & 0xFF) < 0x10) {
|
||||
builder.append("0");
|
||||
}
|
||||
builder.append(Integer.toHexString(b & 0xFF));
|
||||
}
|
||||
return builder.toString();
|
||||
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "IOException", e);
|
||||
return null;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
Log.e(TAG, "NoSuchAlgorithmException", e);
|
||||
return null;
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Unable to close inputstream", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ public class CalorieUtils {
|
||||
double power = earthGravity * weight * speed * (K1 + grade) + K2 * (speed * speed * speed);
|
||||
|
||||
// Get the calories in kcal
|
||||
return power * timeUsed / UnitConversions.KCAL_TO_J;
|
||||
return power * timeUsed * UnitConversions.J_TO_KCAL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
@@ -94,6 +95,7 @@ public class EulaUtils {
|
||||
return sharedPreferences.getBoolean(key, defaultValue);
|
||||
}
|
||||
|
||||
@SuppressLint("CommitPrefEdits")
|
||||
private static void setValue(Context context, String key, boolean value) {
|
||||
SharedPreferences sharedPreferences = context.getSharedPreferences(
|
||||
EULA_PREFERENCE_FILE, Context.MODE_PRIVATE);
|
||||
|
||||
@@ -26,6 +26,7 @@ import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.text.TextUtils;
|
||||
|
||||
/**
|
||||
* Utilities to access preferences stored in {@link SharedPreferences}.
|
||||
@@ -60,6 +61,7 @@ public class PreferencesUtils {
|
||||
public static final String DEFAULT_ACTIVITY_DEFAULT = "";
|
||||
|
||||
public static final String DRIVE_DELETED_LIST_DEFAULT = "";
|
||||
public static final String DRIVE_EDITED_LIST_DEFAULT = "";
|
||||
public static final long DRIVE_LARGEST_CHANGE_ID_DEFAULT = -1L;
|
||||
public static final boolean DRIVE_SYNC_DEFAULT = false;
|
||||
|
||||
@@ -278,4 +280,27 @@ public class PreferencesUtils {
|
||||
return PreferencesUtils.CHART_X_AXIS_DEFAULT.equals(
|
||||
getString(context, R.string.chart_x_axis_key, PreferencesUtils.CHART_X_AXIS_DEFAULT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value to a list.
|
||||
*
|
||||
* @param context the context
|
||||
* @param keyId the key id
|
||||
* @param defaultValue the default value
|
||||
* @param value the value
|
||||
*/
|
||||
public static void addToList(Context context, int keyId, String defaultValue, String value) {
|
||||
String list = getString(context, keyId, defaultValue);
|
||||
if (defaultValue.equals(list)) {
|
||||
setString(context, keyId, value);
|
||||
return;
|
||||
}
|
||||
String[] items = TextUtils.split(list, ";");
|
||||
for (String item : items) {
|
||||
if (value.equals(item)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
setString(context, keyId, list + ";" + value);
|
||||
}
|
||||
}
|
||||
|
||||
+12
-13
@@ -46,7 +46,7 @@ public class ChartFragmentTest extends AndroidTestCase {
|
||||
|
||||
/**
|
||||
* Tests the logic to get the incorrect values of sensor in
|
||||
* {@link ChartFragment#fillDataPoint(android.content.Context, Location, double[])}
|
||||
* {@link ChartFragment#fillDataPoint(Location, double[])}
|
||||
*/
|
||||
public void testFillDataPoint_sensorIncorrect() {
|
||||
MyTracksLocation myTracksLocation = TrackStubUtils.createMyTracksLocation();
|
||||
@@ -83,7 +83,7 @@ public class ChartFragmentTest extends AndroidTestCase {
|
||||
|
||||
/**
|
||||
* Tests the logic to get the correct values of sensor in
|
||||
* {@link ChartFragment#fillDataPoint(android.content.Context, Location, double[])}.
|
||||
* {@link ChartFragment#fillDataPoint(Location, double[])}.
|
||||
*/
|
||||
public void testFillDataPoint_sensorCorrect() {
|
||||
MyTracksLocation myTracksLocation = TrackStubUtils.createMyTracksLocation();
|
||||
@@ -118,7 +118,7 @@ public class ChartFragmentTest extends AndroidTestCase {
|
||||
|
||||
/**
|
||||
* Tests the logic to get the value of metric Distance in
|
||||
* {@link ChartFragment#fillDataPoint(android.content.Context, Location, double[])}.
|
||||
* {@link ChartFragment#fillDataPoint(Location, double[])}.
|
||||
*/
|
||||
public void testFillDataPoint_distanceMetric() {
|
||||
// By distance.
|
||||
@@ -159,7 +159,7 @@ public class ChartFragmentTest extends AndroidTestCase {
|
||||
|
||||
/**
|
||||
* Tests the logic to get the value of imperial Distance in
|
||||
* {@link ChartFragment#fillDataPoint(android.content.Context, Location, double[])}.
|
||||
* {@link ChartFragment#fillDataPoint(Location, double[])}.
|
||||
*/
|
||||
public void testFillDataPoint_distanceImperial() {
|
||||
// By distance.
|
||||
@@ -204,7 +204,7 @@ public class ChartFragmentTest extends AndroidTestCase {
|
||||
|
||||
/**
|
||||
* Tests the logic to get the values of time in
|
||||
* {@link ChartFragment#fillDataPoint(android.content.Context, Location, double[])}.
|
||||
* {@link ChartFragment#fillDataPoint(Location, double[])}.
|
||||
*/
|
||||
public void testFillDataPoint_time() {
|
||||
// By time
|
||||
@@ -220,9 +220,9 @@ public class ChartFragmentTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the logic to get the value of elevation in
|
||||
* {@link ChartFragment#fillDataPoint(android.content.Context,
|
||||
* Location, double[])} by one and two points.
|
||||
* Tests the logic to get the value of elevation in
|
||||
* {@link ChartFragment#fillDataPoint(Location, double[])} by one and two
|
||||
* points.
|
||||
*/
|
||||
public void testFillDataPoint_elevation() {
|
||||
MyTracksLocation myTracksLocation1 = TrackStubUtils.createMyTracksLocation();
|
||||
@@ -247,10 +247,9 @@ public class ChartFragmentTest extends AndroidTestCase {
|
||||
|
||||
/**
|
||||
* Tests the logic to get the value of speed in
|
||||
* {@link ChartFragment#fillDataPoint(android.content.Context, Location, double[])}. In this test,
|
||||
* firstly remove all points in memory,
|
||||
* and then fill in two points one by one. The speed values of these points
|
||||
* are 129, 130.
|
||||
* {@link ChartFragment#fillDataPoint(Location, double[])}. In this test,
|
||||
* firstly remove all points in memory, and then fill in two points one by
|
||||
* one. The speed values of these points are 129, 130.
|
||||
*/
|
||||
public void testFillDataPoint_speed() {
|
||||
/*
|
||||
@@ -359,7 +358,7 @@ public class ChartFragmentTest extends AndroidTestCase {
|
||||
*/
|
||||
private double[] fillDataPointTestHelper(Location location) {
|
||||
double[] point = new double[ChartView.NUM_SERIES + 1];
|
||||
chartFragment.fillDataPoint(location, point);
|
||||
chartFragment.fillDataPoint(location, point, getContext());
|
||||
return point;
|
||||
}
|
||||
|
||||
|
||||
+14
-5
@@ -20,7 +20,8 @@ import static com.google.android.testing.mocking.AndroidMock.eq;
|
||||
import static com.google.android.testing.mocking.AndroidMock.expect;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.io.file.importer.GpxFileTrackImporter;
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
import com.google.android.testing.mocking.AndroidMock;
|
||||
|
||||
import android.location.Location;
|
||||
@@ -97,7 +98,9 @@ public class GpxFileTrackImporterTest extends AbstractTestFileTrackImporter {
|
||||
expect(myTracksProviderUtils.bulkInsertTrackPoint(
|
||||
LocationsMatcher.eqLoc(location1), eq(1), eq(TRACK_ID_0))).andReturn(1);
|
||||
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID_0)).andReturn(TRACK_POINT_ID_1);
|
||||
|
||||
expect(
|
||||
myTracksProviderUtils.getTrack(PreferencesUtils.getLong(getContext(),
|
||||
R.string.recording_track_id_key))).andStubReturn(null);
|
||||
expectUpdateTrack(track, true, TRACK_ID_0);
|
||||
AndroidMock.replay(myTracksProviderUtils);
|
||||
|
||||
@@ -125,12 +128,13 @@ public class GpxFileTrackImporterTest extends AbstractTestFileTrackImporter {
|
||||
expect(myTracksProviderUtils.insertTrack((Track) AndroidMock.anyObject()))
|
||||
.andReturn(TRACK_ID_0_URI);
|
||||
expectFirstTrackPoint(location0, TRACK_ID_0, TRACK_POINT_ID_0);
|
||||
|
||||
// A flush happens at the end
|
||||
expect(myTracksProviderUtils.bulkInsertTrackPoint(
|
||||
(Location[]) AndroidMock.anyObject(), eq(5), eq(TRACK_ID_0))).andStubReturn(5);
|
||||
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID_0)).andReturn(TRACK_POINT_ID_3);
|
||||
|
||||
expect(
|
||||
myTracksProviderUtils.getTrack(PreferencesUtils.getLong(getContext(),
|
||||
R.string.recording_track_id_key))).andStubReturn(null);
|
||||
expectUpdateTrack(track, true, TRACK_ID_0);
|
||||
AndroidMock.replay(myTracksProviderUtils);
|
||||
|
||||
@@ -166,7 +170,9 @@ public class GpxFileTrackImporterTest extends AbstractTestFileTrackImporter {
|
||||
expect(myTracksProviderUtils.bulkInsertTrackPoint(
|
||||
(Location[]) AndroidMock.anyObject(), eq(5), eq(TRACK_ID_0))).andStubReturn(5);
|
||||
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID_0)).andReturn(TRACK_POINT_ID_3);
|
||||
|
||||
expect(
|
||||
myTracksProviderUtils.getTrack(PreferencesUtils.getLong(getContext(),
|
||||
R.string.recording_track_id_key))).andStubReturn(null);
|
||||
expectUpdateTrack(track, true, TRACK_ID_0);
|
||||
AndroidMock.replay(myTracksProviderUtils);
|
||||
|
||||
@@ -235,6 +241,9 @@ public class GpxFileTrackImporterTest extends AbstractTestFileTrackImporter {
|
||||
.andStubReturn(1);
|
||||
expect(myTracksProviderUtils.getFirstTrackPointId(TRACK_ID_0)).andStubReturn(TRACK_POINT_ID_0);
|
||||
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID_0)).andStubReturn(TRACK_POINT_ID_0);
|
||||
expect(
|
||||
myTracksProviderUtils.getTrack(PreferencesUtils.getLong(getContext(),
|
||||
R.string.recording_track_id_key))).andStubReturn(null);
|
||||
myTracksProviderUtils.deleteTrack(TRACK_ID_0);
|
||||
AndroidMock.replay(myTracksProviderUtils);
|
||||
|
||||
|
||||
+8
-2
@@ -20,6 +20,8 @@ import static com.google.android.testing.mocking.AndroidMock.eq;
|
||||
import static com.google.android.testing.mocking.AndroidMock.expect;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
import com.google.android.testing.mocking.AndroidMock;
|
||||
|
||||
import android.location.Location;
|
||||
@@ -79,7 +81,9 @@ public class KmlFileTrackImporterTest extends AbstractTestFileTrackImporter {
|
||||
expect(myTracksProviderUtils.bulkInsertTrackPoint(
|
||||
LocationsMatcher.eqLoc(location1), eq(1), eq(TRACK_ID_0))).andReturn(1);
|
||||
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID_0)).andReturn(TRACK_POINT_ID_1);
|
||||
|
||||
expect(
|
||||
myTracksProviderUtils.getTrack(PreferencesUtils.getLong(getContext(),
|
||||
R.string.recording_track_id_key))).andStubReturn(null);
|
||||
expectUpdateTrack(track, true, TRACK_ID_0);
|
||||
AndroidMock.replay(myTracksProviderUtils);
|
||||
|
||||
@@ -111,7 +115,9 @@ public class KmlFileTrackImporterTest extends AbstractTestFileTrackImporter {
|
||||
expect(myTracksProviderUtils.bulkInsertTrackPoint(
|
||||
(Location[]) AndroidMock.anyObject(), eq(5), eq(TRACK_ID_0))).andStubReturn(5);
|
||||
expect(myTracksProviderUtils.getLastTrackPointId(TRACK_ID_0)).andReturn(TRACK_POINT_ID_3);
|
||||
|
||||
expect(
|
||||
myTracksProviderUtils.getTrack(PreferencesUtils.getLong(getContext(),
|
||||
R.string.recording_track_id_key))).andStubReturn(null);
|
||||
expectUpdateTrack(track, true, TRACK_ID_0);
|
||||
AndroidMock.replay(myTracksProviderUtils);
|
||||
|
||||
|
||||
@@ -95,15 +95,18 @@ public class CalorieUtilsTest extends TestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks calculating cycling calorie.
|
||||
* Checks calculating cycling calorie. 175 is the watt usage for a 90 kg bike
|
||||
* + rider to go 9 m/s (20 mph or 32 km/h) on the flat. <a href=
|
||||
* "http://www.ideafit.com/fitness-library/calculating-caloric-expenditure-0"
|
||||
* >Reference</a>
|
||||
*/
|
||||
public void testCalculateCalorieCycling() {
|
||||
grade = 0;
|
||||
weight = 90;
|
||||
start.setSpeed(9);
|
||||
stop.setSpeed(9);
|
||||
double expected = 175 / 1000 / UnitConversions.KCAL_TO_J;
|
||||
double expected = 175.0 * (TIME_INTERVAL / 1000) * UnitConversions.J_TO_KCAL;
|
||||
double actual = CalorieUtils.calculateCalorieCycling(start, stop, grade, weight);
|
||||
assertEquals(expected, actual);
|
||||
assertTrue((actual - expected) / expected < 0.02);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user