mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-07 03:53:05 +02:00
Merging my own changes.
This commit is contained in:
@@ -298,13 +298,13 @@ public class ChartActivity extends Activity implements
|
||||
public void onChange(boolean selfChange) {
|
||||
Log.d(MyTracksConstants.TAG, "ChartActivity: ContentObserver.onChange");
|
||||
// Check for any new locations and append them to the currently
|
||||
// recording track:
|
||||
if (!MyTracks.getInstance().isRecording()) {
|
||||
// recording track.
|
||||
if (recordingTrackId < 0) {
|
||||
// No track is being recorded. We should not be here.
|
||||
return;
|
||||
}
|
||||
if (selectedTrackId != recordingTrackId) {
|
||||
// no track, or one other than the recording track is selected, don't
|
||||
// No track, or one other than the recording track is selected, don't
|
||||
// bother.
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -26,9 +26,9 @@ import com.google.android.apps.mytracks.io.AuthManagerFactory;
|
||||
import com.google.android.apps.mytracks.io.GpxImporter;
|
||||
import com.google.android.apps.mytracks.io.SendToDocs;
|
||||
import com.google.android.apps.mytracks.io.SendToMyMaps;
|
||||
import com.google.android.apps.mytracks.io.SendToMyMaps.OnSendCompletedListener;
|
||||
import com.google.android.apps.mytracks.io.TrackWriter;
|
||||
import com.google.android.apps.mytracks.io.TrackWriterFactory;
|
||||
import com.google.android.apps.mytracks.io.SendToMyMaps.OnSendCompletedListener;
|
||||
import com.google.android.apps.mytracks.io.TrackWriterFactory.TrackFileFormat;
|
||||
import com.google.android.apps.mytracks.services.ITrackRecordingService;
|
||||
import com.google.android.apps.mytracks.services.StatusAnnouncerFactory;
|
||||
@@ -65,9 +65,9 @@ import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.View.OnTouchListener;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager.BadTokenException;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TabHost;
|
||||
@@ -97,9 +97,10 @@ public class MyTracks extends TabActivity implements OnTouchListener,
|
||||
/**
|
||||
* Singleton instance
|
||||
*/
|
||||
private static MyTracks instance = null;
|
||||
private ChartActivity chartActivity = null;
|
||||
private static MyTracks instance;
|
||||
|
||||
private ChartActivity chartActivity;
|
||||
|
||||
public ChartActivity getChartActivity() {
|
||||
return chartActivity;
|
||||
}
|
||||
@@ -178,6 +179,8 @@ public class MyTracks extends TabActivity implements OnTouchListener,
|
||||
* Utilities to deal with the database.
|
||||
*/
|
||||
private MyTracksProviderUtils providerUtils;
|
||||
|
||||
private SharedPreferences sharedPreferences;
|
||||
|
||||
/**
|
||||
* The connection to the track recording service.
|
||||
@@ -233,20 +236,35 @@ public class MyTracks extends TabActivity implements OnTouchListener,
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether we have a track recording session in progress.
|
||||
* In some cases, when the service has crashed or has been restarted
|
||||
* by the system, we fall back to the shared preferences.
|
||||
*
|
||||
* @return true if the activity is bound to the track recording service and
|
||||
* the service is recording a track.
|
||||
* the service is recording a track or in case the service is down,
|
||||
* based on settings from the shared preferences.
|
||||
*/
|
||||
public boolean isRecording() {
|
||||
if (trackRecordingService == null) {
|
||||
return false;
|
||||
// Fall back to alternative check method.
|
||||
return isRecordingBasedOnSharedPreferences();
|
||||
}
|
||||
try {
|
||||
return trackRecordingService.isRecording();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(MyTracksConstants.TAG, "MyTracks: Remote exception.", e);
|
||||
return false;
|
||||
|
||||
// Fall back to alternative check method.
|
||||
return isRecordingBasedOnSharedPreferences();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRecordingBasedOnSharedPreferences() {
|
||||
// TrackRecordingServices guarantees that recordingTrackId is set to
|
||||
// -1 if the track has been stopped.
|
||||
// TODO: Refresh recordingTrackId.
|
||||
return recordingTrackId >= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Application lifetime events:
|
||||
@@ -260,6 +278,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
|
||||
instance = this;
|
||||
providerUtils = MyTracksProviderUtils.Factory.get(this);
|
||||
menuManager = new MenuManager(this);
|
||||
sharedPreferences = getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
|
||||
|
||||
// The volume we want to control is the Text-To-Speech volume
|
||||
int volumeStream =
|
||||
@@ -295,14 +314,18 @@ public class MyTracks extends TabActivity implements OnTouchListener,
|
||||
tabHost.addView(layout);
|
||||
layout.setOnTouchListener(this);
|
||||
|
||||
SharedPreferences prefs =
|
||||
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
|
||||
if (prefs != null) {
|
||||
if (sharedPreferences != null) {
|
||||
selectedTrackId =
|
||||
prefs.getLong(getString(R.string.selected_track_key), -1);
|
||||
recordingTrackId =
|
||||
prefs.getLong(getString(R.string.recording_track_key), -1);
|
||||
prefs.registerOnSharedPreferenceChangeListener(this);
|
||||
sharedPreferences.getLong(getString(R.string.selected_track_key), -1);
|
||||
recordingTrackId = sharedPreferences.getLong(
|
||||
getString(R.string.recording_track_key), -1);
|
||||
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
|
||||
Log.d(MyTracksConstants.TAG, "recordingTrackId: " + recordingTrackId
|
||||
+ ", selectedTrackId: " + selectedTrackId);
|
||||
if (recordingTrackId > 0) {
|
||||
Intent startIntent = new Intent(this, TrackRecordingService.class);
|
||||
startService(startIntent);
|
||||
}
|
||||
}
|
||||
|
||||
// This will show the eula until the user accepts or quits the app.
|
||||
@@ -1008,20 +1031,15 @@ public class MyTracks extends TabActivity implements OnTouchListener,
|
||||
shareIntent.putExtra(Intent.EXTRA_SUBJECT,
|
||||
getResources().getText(R.string.share_map_subject).toString());
|
||||
|
||||
SharedPreferences prefs =
|
||||
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
|
||||
boolean shareUrlOnly = true;
|
||||
if (prefs != null) {
|
||||
shareUrlOnly =
|
||||
prefs.getBoolean(getString(R.string.share_url_only_key), false);
|
||||
if (sharedPreferences != null) {
|
||||
shareUrlOnly = sharedPreferences.getBoolean(
|
||||
getString(R.string.share_url_only_key), false);
|
||||
}
|
||||
|
||||
String url = MyMapsConstants.MAPSHOP_BASE_URL + "?msa=0&msid=" + mapId;
|
||||
String msg = (shareUrlOnly
|
||||
? url
|
||||
: String.format(
|
||||
getResources().getText(R.string.share_map_body_format).toString(),
|
||||
url));
|
||||
String msg = shareUrlOnly ? url : String.format(
|
||||
getResources().getText(R.string.share_map_body_format).toString(), url);
|
||||
shareIntent.putExtra(Intent.EXTRA_TEXT, msg);
|
||||
startActivity(Intent.createChooser(shareIntent,
|
||||
getResources().getText(R.string.share_map).toString()));
|
||||
@@ -1235,9 +1253,10 @@ public class MyTracks extends TabActivity implements OnTouchListener,
|
||||
private void startRecordingNewTrack() {
|
||||
try {
|
||||
recordingTrackId = trackRecordingService.startNewTrack();
|
||||
// Select the recording track.
|
||||
setSelectedTrack(recordingTrackId);
|
||||
Toast.makeText(this, getString(R.string.status_now_recording),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
setSelectedAndRecordingTrack(recordingTrackId, recordingTrackId);
|
||||
} catch (RemoteException e) {
|
||||
Toast.makeText(this,
|
||||
getString(R.string.error_unable_to_start_recording),
|
||||
@@ -1272,7 +1291,6 @@ public class MyTracks extends TabActivity implements OnTouchListener,
|
||||
} catch (RemoteException e) {
|
||||
Log.e(MyTracksConstants.TAG, "Unable to stop recording.", e);
|
||||
}
|
||||
setRecordingTrack(-1);
|
||||
Intent intent = new Intent(MyTracks.this, MyTracksDetails.class);
|
||||
intent.putExtra("trackid", recordingTrackId);
|
||||
intent.putExtra("hasCancelButton", false);
|
||||
@@ -1327,9 +1345,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
|
||||
public void setSelectedTrack(final long trackId) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
SharedPreferences prefs =
|
||||
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putLong(getString(R.string.selected_track_key), trackId);
|
||||
editor.commit();
|
||||
}
|
||||
@@ -1340,44 +1356,6 @@ public class MyTracks extends TabActivity implements OnTouchListener,
|
||||
return selectedTrackId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the recording track id to the shared preferences.
|
||||
* Executed on the UI thread.
|
||||
*
|
||||
* @param trackId the id of the track
|
||||
*/
|
||||
private void setRecordingTrack(final long trackId) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
SharedPreferences prefs =
|
||||
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putLong(getString(R.string.recording_track_key), trackId);
|
||||
editor.commit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the selected and the recording track id to the shared preferences.
|
||||
* Executed on UI thread.
|
||||
*/
|
||||
private void setSelectedAndRecordingTrack(final long theSelectedTrackId,
|
||||
final long theRecordingTrackId) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
SharedPreferences prefs =
|
||||
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
|
||||
if (prefs != null) {
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putLong(getString(R.string.selected_track_key), theSelectedTrackId);
|
||||
editor.putLong(getString(R.string.recording_track_key), theRecordingTrackId);
|
||||
editor.commit();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds to track recording service if it is running.
|
||||
*/
|
||||
|
||||
@@ -118,7 +118,7 @@ public class MyTracksMap extends MapActivity
|
||||
private double variation;
|
||||
|
||||
/**
|
||||
* From the shared preferences:
|
||||
* From the shared preferences.
|
||||
*/
|
||||
private int minRequiredAccuracy =
|
||||
MyTracksSettings.DEFAULT_MIN_REQUIRED_ACCURACY;
|
||||
@@ -135,8 +135,8 @@ public class MyTracksMap extends MapActivity
|
||||
private Location currentLocation;
|
||||
|
||||
/**
|
||||
* A thread with a looper. Post to updateTrackHandler to execute Runnables on
|
||||
* this thread.
|
||||
* A thread with a looper. Post to updateTrackHandler to execute
|
||||
* {@link Runnable}s on this thread.
|
||||
*/
|
||||
private HandlerThread updateTrackThread;
|
||||
|
||||
@@ -146,6 +146,8 @@ public class MyTracksMap extends MapActivity
|
||||
private Handler updateTrackHandler;
|
||||
|
||||
private MyTracksProviderUtils providerUtils;
|
||||
|
||||
private SharedPreferences sharedPreferences;
|
||||
|
||||
/**
|
||||
* A runnable that updates the track from the provider (looking for points
|
||||
@@ -331,12 +333,6 @@ public class MyTracksMap extends MapActivity
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
Log.d(MyTracksConstants.TAG, "MyTracksMap: ContentObserver.onChange");
|
||||
// Check for any new locations and append them to the currently
|
||||
// recording track:
|
||||
if (!MyTracks.getInstance().isRecording()) {
|
||||
// No track is being recorded. We should not be here.
|
||||
return;
|
||||
}
|
||||
if (!isRecordingSelected()) {
|
||||
// No track, or one other than the recording track is selected,
|
||||
// don't bother.
|
||||
@@ -361,30 +357,25 @@ public class MyTracksMap extends MapActivity
|
||||
}
|
||||
};
|
||||
|
||||
// Read shared preferences and register change listener:
|
||||
SharedPreferences preferences =
|
||||
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
|
||||
if (preferences != null) {
|
||||
minRequiredAccuracy = preferences.getInt(
|
||||
getString(R.string.min_required_accuracy_key),
|
||||
MyTracksSettings.DEFAULT_MIN_REQUIRED_ACCURACY);
|
||||
recordingTrackId =
|
||||
preferences.getLong(getString(R.string.recording_track_key), -1);
|
||||
long selectedTrackId =
|
||||
preferences.getLong(getString(R.string.selected_track_key), -1);
|
||||
if (selectedTrackId >= 0) {
|
||||
setSelectedTrack(selectedTrackId);
|
||||
}
|
||||
// Read shared preferences and register change listener.
|
||||
sharedPreferences = getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
|
||||
if (sharedPreferences != null) {
|
||||
reloadSharedPreferences(sharedPreferences, null);
|
||||
updateOptionsButton();
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
Log.d(MyTracksConstants.TAG, "MyTracksMap.onDestroy");
|
||||
|
||||
if (updateTrackThread != null) {
|
||||
updateTrackThread.quit();
|
||||
ApiFeatures.getInstance().getApiPlatformAdapter().stopHandlerThread(
|
||||
updateTrackThread);
|
||||
}
|
||||
if (sharedPreferences != null) {
|
||||
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
super.onDestroy();
|
||||
@@ -451,6 +442,9 @@ public class MyTracksMap extends MapActivity
|
||||
Log.d(MyTracksConstants.TAG, "MyTracksMap.onResume");
|
||||
super.onResume();
|
||||
|
||||
// Reload all preferences as they might have changed since last run.
|
||||
reloadSharedPreferences(sharedPreferences, null);
|
||||
|
||||
// Make sure any updates that might have happened are propagated to the
|
||||
// Map overlay:
|
||||
observer.onChange(false);
|
||||
@@ -707,11 +701,14 @@ public class MyTracksMap extends MapActivity
|
||||
* @param trackId a given track id
|
||||
*/
|
||||
public void setSelectedTrack(final long trackId) {
|
||||
Log.d(MyTracksConstants.TAG, "MyTracksMap.setSelectedTrack: "
|
||||
+ "selectedtTrackId = " + selectedTrackId + ", trackId = " + trackId);
|
||||
|
||||
if (selectedTrackId == trackId) {
|
||||
// Selected track did not change, nothing to do.
|
||||
mapOverlay.setTrackDrawingEnabled(isATrackSelected());
|
||||
mapView.invalidate();
|
||||
updateOptionsButton();
|
||||
mapView.invalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -786,7 +783,7 @@ public class MyTracksMap extends MapActivity
|
||||
menu.setHeaderTitle(R.string.tracklist_this_track);
|
||||
menu.add(0, MyTracksConstants.MENU_EDIT, 0,
|
||||
R.string.tracklist_edit_track);
|
||||
if (!MyTracks.getInstance().isRecording() || !isRecordingSelected()) {
|
||||
if (!isRecordingSelected()) {
|
||||
menu.add(0, MyTracksConstants.MENU_SEND_TO_GOOGLE, 0,
|
||||
R.string.tracklist_send_to_google);
|
||||
SubMenu share = menu.addSubMenu(0, MyTracksConstants.MENU_SHARE, 0,
|
||||
@@ -906,30 +903,13 @@ public class MyTracksMap extends MapActivity
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(
|
||||
final SharedPreferences sharedPreferences, final String key) {
|
||||
Log.d(MyTracksConstants.TAG,
|
||||
"MyTracksMap.onSharedPreferenceChanged: " + key);
|
||||
if (key != null) {
|
||||
uiHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (key.equals(getString(R.string.min_required_accuracy_key))) {
|
||||
minRequiredAccuracy = sharedPreferences.getInt(
|
||||
getString(R.string.min_required_accuracy_key),
|
||||
MyTracksSettings.DEFAULT_MIN_REQUIRED_ACCURACY);
|
||||
} else if (key.equals(getString(R.string.selected_track_key))) {
|
||||
long selectedTrackId =
|
||||
sharedPreferences.getLong(
|
||||
getString(R.string.selected_track_key),
|
||||
-1);
|
||||
setSelectedTrack(selectedTrackId);
|
||||
} else if (key.equals(getString(R.string.recording_track_key))) {
|
||||
recordingTrackId =
|
||||
sharedPreferences.getLong(
|
||||
getString(R.string.recording_track_key),
|
||||
-1);
|
||||
if (isATrackSelected()) {
|
||||
mapOverlay.setShowEndMarker(!isRecordingSelected());
|
||||
mapView.postInvalidate();
|
||||
}
|
||||
}
|
||||
reloadSharedPreferences(sharedPreferences, key);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1009,6 +989,31 @@ public class MyTracksMap extends MapActivity
|
||||
}
|
||||
};
|
||||
|
||||
private void reloadSharedPreferences(SharedPreferences sharedPreferences,
|
||||
String key) {
|
||||
if (key == null ||
|
||||
key.equals(getString(R.string.min_required_accuracy_key))) {
|
||||
minRequiredAccuracy = sharedPreferences.getInt(
|
||||
getString(R.string.min_required_accuracy_key),
|
||||
MyTracksSettings.DEFAULT_MIN_REQUIRED_ACCURACY);
|
||||
}
|
||||
if (key == null || key.equals(getString(R.string.recording_track_key))) {
|
||||
recordingTrackId = sharedPreferences.getLong(
|
||||
getString(R.string.recording_track_key), -1);
|
||||
}
|
||||
if (key == null || key.equals(getString(R.string.selected_track_key))) {
|
||||
setSelectedTrack(sharedPreferences.getLong(
|
||||
getString(R.string.selected_track_key), -1));
|
||||
}
|
||||
|
||||
// Show end marker if the track has been selected and is not recording.
|
||||
// Note: This check must be *after* a call to setSelectedTrack(...) above.
|
||||
if (isATrackSelected()) {
|
||||
mapOverlay.setShowEndMarker(!isRecordingSelected());
|
||||
mapView.postInvalidate();
|
||||
}
|
||||
}
|
||||
|
||||
private void readAllNewTrackPoints() {
|
||||
int numPoints = mapOverlay.getNumLocations();
|
||||
if (numPoints >= MyTracksConstants.MAX_DISPLAYED_TRACK_POINTS) {
|
||||
|
||||
@@ -52,7 +52,7 @@ import android.widget.Toast;
|
||||
public class StatsActivity extends Activity
|
||||
implements OnSharedPreferenceChangeListener {
|
||||
|
||||
private final StatsUtilities utils;
|
||||
private StatsUtilities utils;
|
||||
private UIUpdateThread thread;
|
||||
|
||||
private ContentObserver observer;
|
||||
@@ -94,7 +94,7 @@ public class StatsActivity extends Activity
|
||||
*/
|
||||
private boolean showCurrentSegment = false;
|
||||
|
||||
private final MyTracksProviderUtils providerUtils;
|
||||
private MyTracksProviderUtils providerUtils;
|
||||
|
||||
/**
|
||||
* A runnable for posting to the UI thread. Will update the total time field.
|
||||
@@ -133,16 +133,14 @@ public class StatsActivity extends Activity
|
||||
}
|
||||
}
|
||||
|
||||
public StatsActivity() {
|
||||
utils = new StatsUtilities(this);
|
||||
providerUtils = new MyTracksProviderUtilsImpl(this);
|
||||
}
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
utils = new StatsUtilities(this);
|
||||
providerUtils = new MyTracksProviderUtilsImpl(getContentResolver());
|
||||
|
||||
// The volume we want to control is the Text-To-Speech volume
|
||||
int volumeStream =
|
||||
new StatusAnnouncerFactory(ApiFeatures.getInstance()).getVolumeStream();
|
||||
|
||||
@@ -345,7 +345,7 @@ public interface MyTracksProviderUtils {
|
||||
* Creates an instance of {@link MyTracksProviderUtils}.
|
||||
*/
|
||||
protected MyTracksProviderUtils newForContext(Context context) {
|
||||
return new MyTracksProviderUtilsImpl(context);
|
||||
return new MyTracksProviderUtilsImpl(context.getContentResolver());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+31
-34
@@ -17,8 +17,8 @@ package com.google.android.apps.mytracks.content;
|
||||
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.location.Location;
|
||||
import android.net.Uri;
|
||||
@@ -35,10 +35,10 @@ import java.util.List;
|
||||
*/
|
||||
public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
|
||||
private final Context context;
|
||||
private final ContentResolver contentResolver;
|
||||
|
||||
public MyTracksProviderUtilsImpl(Context context) {
|
||||
this.context = context;
|
||||
public MyTracksProviderUtilsImpl(ContentResolver contentResolver) {
|
||||
this.contentResolver = contentResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -448,25 +448,22 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
|
||||
@Override
|
||||
public void deleteAllTracks() {
|
||||
context.getContentResolver().delete(TracksColumns.CONTENT_URI, null, null);
|
||||
context.getContentResolver().delete(TrackPointsColumns.CONTENT_URI,
|
||||
null, null);
|
||||
context.getContentResolver().delete(
|
||||
WaypointsColumns.CONTENT_URI, null, null);
|
||||
contentResolver.delete(TracksColumns.CONTENT_URI, null, null);
|
||||
contentResolver.delete(TrackPointsColumns.CONTENT_URI, null, null);
|
||||
contentResolver.delete(WaypointsColumns.CONTENT_URI, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteTrack(long trackId) {
|
||||
Track track = getTrack(trackId);
|
||||
if (track != null) {
|
||||
context.getContentResolver().delete(TrackPointsColumns.CONTENT_URI,
|
||||
contentResolver.delete(TrackPointsColumns.CONTENT_URI,
|
||||
"_id>=" + track.getStartId() + " AND _id<=" + track.getStopId(),
|
||||
null);
|
||||
}
|
||||
context.getContentResolver().delete(WaypointsColumns.CONTENT_URI,
|
||||
contentResolver.delete(WaypointsColumns.CONTENT_URI,
|
||||
WaypointsColumns.TRACKID + "=" + trackId, null);
|
||||
context.getContentResolver().delete(
|
||||
TracksColumns.CONTENT_URI, "_id=" + trackId, null);
|
||||
contentResolver.delete(TracksColumns.CONTENT_URI, "_id=" + trackId, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -491,7 +488,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
"No statistics marker after the deleted one was found.");
|
||||
}
|
||||
}
|
||||
context.getContentResolver().delete(
|
||||
contentResolver.delete(
|
||||
WaypointsColumns.CONTENT_URI, "_id=" + waypointId, null);
|
||||
}
|
||||
|
||||
@@ -503,7 +500,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
final String sortOrder = WaypointsColumns._ID + " LIMIT 1";
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = context.getContentResolver().query(
|
||||
cursor = contentResolver.query(
|
||||
WaypointsColumns.CONTENT_URI,
|
||||
null /*projection*/,
|
||||
selection,
|
||||
@@ -525,7 +522,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
@Override
|
||||
public boolean updateWaypoint(Waypoint waypoint) {
|
||||
try {
|
||||
final int rows = context.getContentResolver().update(
|
||||
final int rows = contentResolver.update(
|
||||
WaypointsColumns.CONTENT_URI,
|
||||
createContentValues(waypoint),
|
||||
"_id=" + waypoint.getId(),
|
||||
@@ -546,7 +543,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
private Location findLocationBy(String select) {
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = context.getContentResolver().query(
|
||||
cursor = contentResolver.query(
|
||||
TrackPointsColumns.CONTENT_URI, null, select, null, null);
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
return createLocation(cursor);
|
||||
@@ -570,7 +567,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
private Track findTrackBy(String select) {
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = context.getContentResolver().query(
|
||||
cursor = contentResolver.query(
|
||||
TracksColumns.CONTENT_URI, null, select, null, null);
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
return createTrack(cursor);
|
||||
@@ -592,7 +589,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
|
||||
@Override
|
||||
public Waypoint getFirstWaypoint(long trackId) {
|
||||
Cursor cursor = context.getContentResolver().query(
|
||||
Cursor cursor = contentResolver.query(
|
||||
WaypointsColumns.CONTENT_URI,
|
||||
null /*projection*/,
|
||||
"trackid=" + trackId,
|
||||
@@ -614,7 +611,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
|
||||
@Override
|
||||
public Waypoint getWaypoint(long waypointId) {
|
||||
Cursor cursor = context.getContentResolver().query(
|
||||
Cursor cursor = contentResolver.query(
|
||||
WaypointsColumns.CONTENT_URI,
|
||||
null /*projection*/,
|
||||
"_id=" + waypointId,
|
||||
@@ -637,7 +634,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
@Override
|
||||
public long getLastLocationId(long trackId) {
|
||||
final String[] projection = {"_id"};
|
||||
Cursor cursor = context.getContentResolver().query(
|
||||
Cursor cursor = contentResolver.query(
|
||||
TrackPointsColumns.CONTENT_URI,
|
||||
projection,
|
||||
"_id=(select max(_id) from trackpoints WHERE trackid=" + trackId + ")",
|
||||
@@ -661,7 +658,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
@Override
|
||||
public long getFirstWaypointId(long trackId) {
|
||||
final String[] projection = {"_id"};
|
||||
Cursor cursor = context.getContentResolver().query(
|
||||
Cursor cursor = contentResolver.query(
|
||||
WaypointsColumns.CONTENT_URI,
|
||||
projection,
|
||||
"trackid=" + trackId,
|
||||
@@ -685,7 +682,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
@Override
|
||||
public long getLastWaypointId(long trackId) {
|
||||
final String[] projection = {"_id"};
|
||||
Cursor cursor = context.getContentResolver().query(
|
||||
Cursor cursor = contentResolver.query(
|
||||
WaypointsColumns.CONTENT_URI,
|
||||
projection,
|
||||
WaypointsColumns.TRACKID + "=" + trackId,
|
||||
@@ -710,7 +707,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
public Track getLastTrack() {
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = context.getContentResolver().query(
|
||||
cursor = contentResolver.query(
|
||||
TracksColumns.CONTENT_URI, null, "_id=(select max(_id) from tracks)",
|
||||
null, null);
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
@@ -729,7 +726,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
@Override
|
||||
public long getLastTrackId() {
|
||||
String[] proj = { TracksColumns._ID };
|
||||
Cursor cursor = context.getContentResolver().query(
|
||||
Cursor cursor = contentResolver.query(
|
||||
TracksColumns.CONTENT_URI, proj, "_id=(select max(_id) from tracks)",
|
||||
null, null);
|
||||
if (cursor != null) {
|
||||
@@ -769,7 +766,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
sortOrder += " LIMIT " + maxLocations;
|
||||
}
|
||||
|
||||
return context.getContentResolver().query(
|
||||
return contentResolver.query(
|
||||
TrackPointsColumns.CONTENT_URI, null, selection, null, sortOrder);
|
||||
}
|
||||
|
||||
@@ -791,7 +788,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
sortOrder += " LIMIT " + maxWaypoints;
|
||||
}
|
||||
|
||||
return context.getContentResolver().query(
|
||||
return contentResolver.query(
|
||||
WaypointsColumns.CONTENT_URI, null, selection, null, sortOrder);
|
||||
}
|
||||
|
||||
@@ -847,7 +844,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
|
||||
@Override
|
||||
public Cursor getTracksCursor(String selection) {
|
||||
Cursor cursor = context.getContentResolver().query(
|
||||
Cursor cursor = contentResolver.query(
|
||||
TracksColumns.CONTENT_URI, null, selection, null, "_id");
|
||||
return cursor;
|
||||
}
|
||||
@@ -855,14 +852,14 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
@Override
|
||||
public Uri insertTrack(Track track) {
|
||||
Log.d(MyTracksProvider.TAG, "MyTracksProviderUtilsImpl.insertTrack");
|
||||
return context.getContentResolver().insert(TracksColumns.CONTENT_URI,
|
||||
return contentResolver.insert(TracksColumns.CONTENT_URI,
|
||||
createContentValues(track));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri insertTrackPoint(Location location, long trackId) {
|
||||
Log.d(MyTracksProvider.TAG, "MyTracksProviderUtilsImpl.insertTrackPoint");
|
||||
return context.getContentResolver().insert(TrackPointsColumns.CONTENT_URI,
|
||||
return contentResolver.insert(TrackPointsColumns.CONTENT_URI,
|
||||
createContentValues(location, trackId));
|
||||
}
|
||||
|
||||
@@ -875,14 +872,14 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
values[i] = createContentValues(locations[i], trackId);
|
||||
}
|
||||
|
||||
return context.getContentResolver().bulkInsert(TrackPointsColumns.CONTENT_URI, values);
|
||||
return contentResolver.bulkInsert(TrackPointsColumns.CONTENT_URI, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri insertWaypoint(Waypoint waypoint) {
|
||||
Log.d(MyTracksProvider.TAG, "MyTracksProviderUtilsImpl.insertWaypoint");
|
||||
waypoint.setId(-1);
|
||||
return context.getContentResolver().insert(WaypointsColumns.CONTENT_URI,
|
||||
return contentResolver.insert(WaypointsColumns.CONTENT_URI,
|
||||
createContentValues(waypoint));
|
||||
}
|
||||
|
||||
@@ -891,7 +888,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
final String[] projection = { TracksColumns._ID };
|
||||
cursor = context.getContentResolver().query(
|
||||
cursor = contentResolver.query(
|
||||
TracksColumns.CONTENT_URI,
|
||||
projection,
|
||||
TracksColumns._ID + "=" + id/*selection*/,
|
||||
@@ -911,7 +908,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
|
||||
@Override
|
||||
public void updateTrack(Track track) {
|
||||
Log.d(MyTracksProvider.TAG, "MyTracksProviderUtilsImpl.updateTrack");
|
||||
context.getContentResolver().update(TracksColumns.CONTENT_URI,
|
||||
contentResolver.update(TracksColumns.CONTENT_URI,
|
||||
createContentValues(track), "_id=" + track.getId(), null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,8 +468,7 @@ public class GpxImporter extends DefaultHandler {
|
||||
|
||||
// initialize start time with time of first track point
|
||||
if (statsBuilder == null) {
|
||||
statsBuilder = new TripStatisticsBuilder();
|
||||
statsBuilder.resumeAt(time);
|
||||
statsBuilder = new TripStatisticsBuilder(time);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2010 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.services;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracksSettings;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.text.format.Time;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Creates a default track name based on the current default track name policy.
|
||||
*
|
||||
* @author Matthew Simmons
|
||||
*/
|
||||
class DefaultTrackNameFactory {
|
||||
private static final String TIMESTAMP_DATE_FORMAT = "yyyy-MM-dd HH:mm";
|
||||
|
||||
private final Context context;
|
||||
|
||||
DefaultTrackNameFactory(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new track name.
|
||||
*
|
||||
* @param trackId The ID for the current track.
|
||||
* @param startTime The start time, in milliseconds since the epoch, of the
|
||||
* current track.
|
||||
* @return The new track name.
|
||||
*/
|
||||
String newTrackName(long trackId, long startTime) {
|
||||
if (useTimestampTrackName()) {
|
||||
SimpleDateFormat formatter = new SimpleDateFormat(TIMESTAMP_DATE_FORMAT);
|
||||
return formatter.format(new Date(startTime));
|
||||
} else {
|
||||
return String.format(context.getString(R.string.new_track), trackId);
|
||||
}
|
||||
}
|
||||
|
||||
/** Determines whether the preferences allow a timestamp-based track name */
|
||||
protected boolean useTimestampTrackName() {
|
||||
SharedPreferences prefs =
|
||||
context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
|
||||
return prefs.getBoolean(
|
||||
context.getString(R.string.timestamp_track_name_key), true);
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import com.google.android.apps.mytracks.MyTracksSettings;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
@@ -30,6 +31,7 @@ import android.util.Log;
|
||||
public class PreferenceManager {
|
||||
private TrackRecordingService service;
|
||||
private final String announcementFrequencyKey;
|
||||
private final String autoResumeTrackCurrentRetryKey;
|
||||
private final String autoResumeTrackTimeoutKey;
|
||||
private final String maxRecordingDistanceKey;
|
||||
private final String metricUnitsKey;
|
||||
@@ -40,11 +42,22 @@ public class PreferenceManager {
|
||||
private final String signalSamplingFrequencyKey;
|
||||
private final String splitFrequencyKey;
|
||||
|
||||
private final SharedPreferences sharedPreferences;
|
||||
|
||||
public PreferenceManager(TrackRecordingService service) {
|
||||
this.service = service;
|
||||
|
||||
this.sharedPreferences =
|
||||
service.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
|
||||
if (sharedPreferences == null) {
|
||||
Log.w(MyTracksConstants.TAG,
|
||||
"TrackRecordingService: Couldn't get shared preferences.");
|
||||
throw new IllegalStateException("Couldn't get shared preferences");
|
||||
}
|
||||
|
||||
announcementFrequencyKey =
|
||||
service.getString(R.string.announcement_frequency_key);
|
||||
autoResumeTrackCurrentRetryKey =
|
||||
service.getString(R.string.auto_resume_track_current_retry_key);
|
||||
autoResumeTrackTimeoutKey =
|
||||
service.getString(R.string.auto_resume_track_timeout_key);
|
||||
maxRecordingDistanceKey =
|
||||
@@ -57,12 +70,12 @@ public class PreferenceManager {
|
||||
service.getString(R.string.min_recording_interval_key);
|
||||
minRequiredAccuracyKey =
|
||||
service.getString(R.string.min_required_accuracy_key);
|
||||
splitFrequencyKey =
|
||||
service.getString(R.string.split_frequency_key);
|
||||
signalSamplingFrequencyKey =
|
||||
service.getString(R.string.signal_sampling_frequency_key);
|
||||
recordingTrackKey =
|
||||
service.getString(R.string.recording_track_key);
|
||||
signalSamplingFrequencyKey =
|
||||
service.getString(R.string.signal_sampling_frequency_key);
|
||||
splitFrequencyKey =
|
||||
service.getString(R.string.split_frequency_key);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,14 +85,6 @@ public class PreferenceManager {
|
||||
* @param key the key that changed (may be null to update all preferences)
|
||||
*/
|
||||
public void onSharedPreferenceChanged(String key) {
|
||||
SharedPreferences sharedPreferences =
|
||||
service.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
|
||||
if (sharedPreferences == null) {
|
||||
Log.w(MyTracksConstants.TAG,
|
||||
"TrackRecordingService: Couldn't get shared preferences.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == null || key.equals(minRecordingDistanceKey)) {
|
||||
service.setMinRecordingDistance(
|
||||
sharedPreferences.getInt(
|
||||
@@ -156,4 +161,16 @@ public class PreferenceManager {
|
||||
sharedPreferences.getBoolean(metricUnitsKey, true));
|
||||
}
|
||||
}
|
||||
|
||||
public void setAutoResumeTrackCurrentRetry(int retryAttempts) {
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putInt(autoResumeTrackCurrentRetryKey, retryAttempts);
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
public void setRecordingTrack(long id) {
|
||||
Editor editor = sharedPreferences.edit();
|
||||
editor.putLong(recordingTrackKey, id);
|
||||
editor.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.google.android.apps.mytracks.content.WaypointsColumns;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
|
||||
import com.google.android.apps.mytracks.util.ApiFeatures;
|
||||
import com.google.android.apps.mytracks.util.ApiPlatformAdapter;
|
||||
import com.google.android.apps.mytracks.util.MyTracksUtils;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
@@ -51,8 +52,10 @@ import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import android.os.PowerManager.WakeLock;
|
||||
import android.text.format.DateFormat;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
@@ -67,7 +70,7 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
private static final String STATISTICS_ICON_URL =
|
||||
"http://maps.google.com/mapfiles/ms/micons/ylw-pushpin.png";
|
||||
|
||||
private static final int MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS = 3;
|
||||
static final int MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS = 3;
|
||||
|
||||
private NotificationManager notificationManager;
|
||||
private LocationManager locationManager;
|
||||
@@ -94,8 +97,8 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
*/
|
||||
private MyTracksProviderUtils providerUtils;
|
||||
|
||||
private TripStatisticsBuilder statsBuilder = new TripStatisticsBuilder();
|
||||
private TripStatisticsBuilder waypointStatsBuilder = new TripStatisticsBuilder();
|
||||
private TripStatisticsBuilder statsBuilder;
|
||||
private TripStatisticsBuilder waypointStatsBuilder;
|
||||
|
||||
/**
|
||||
* Current length of the recorded track. This length is calculated from the
|
||||
@@ -329,6 +332,8 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
* Shows the notification message and icon in the notification bar.
|
||||
*/
|
||||
public void showNotification() {
|
||||
final ApiPlatformAdapter apiPlatformAdapter =
|
||||
ApiFeatures.getInstance().getApiPlatformAdapter();
|
||||
if (isRecording) {
|
||||
Notification notification = new Notification(
|
||||
R.drawable.arrow_320, null /* tickerText */,
|
||||
@@ -339,9 +344,10 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
notification.setLatestEventInfo(this, getString(R.string.app_name),
|
||||
getString(R.string.recording_your_track), contentIntent);
|
||||
notification.flags += Notification.FLAG_NO_CLEAR;
|
||||
notificationManager.notify(1, notification);
|
||||
apiPlatformAdapter.startForeground(this, notificationManager, 1,
|
||||
notification);
|
||||
} else {
|
||||
notificationManager.cancelAll();
|
||||
apiPlatformAdapter.stopForeground(this, notificationManager, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,9 +396,11 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
}
|
||||
|
||||
private void restoreStats(Track track) {
|
||||
Log.d(MyTracksConstants.TAG,
|
||||
"Restoring stats of track with ID: " + track.getId());
|
||||
|
||||
TripStatistics stats = track.getStatistics();
|
||||
statsBuilder = new TripStatisticsBuilder();
|
||||
statsBuilder.resumeAt(stats.getStartTime());
|
||||
statsBuilder = new TripStatisticsBuilder(stats.getStartTime());
|
||||
setUpAnnouncer();
|
||||
|
||||
signalManager.restore();
|
||||
@@ -403,11 +411,11 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
Waypoint waypoint = providerUtils.getFirstWaypoint(recordingTrackId);
|
||||
if (waypoint != null) {
|
||||
currentWaypointId = waypoint.getId();
|
||||
waypointStatsBuilder = new TripStatisticsBuilder(waypoint.getStatistics());
|
||||
waypointStatsBuilder = new TripStatisticsBuilder(
|
||||
waypoint.getStatistics());
|
||||
} else {
|
||||
// This should never happen, but we got to do something so life goes on:
|
||||
waypointStatsBuilder = new TripStatisticsBuilder();
|
||||
waypointStatsBuilder.resumeAt(stats.getStartTime());
|
||||
waypointStatsBuilder = new TripStatisticsBuilder(stats.getStartTime());
|
||||
currentWaypointId = -1;
|
||||
}
|
||||
|
||||
@@ -431,7 +439,7 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
}
|
||||
statsBuilder.getStatistics().setMovingTime(stats.getMovingTime());
|
||||
statsBuilder.pauseAt(stats.getStopTime());
|
||||
statsBuilder.resume();
|
||||
statsBuilder.resumeAt(System.currentTimeMillis());
|
||||
} else {
|
||||
Log.e(MyTracksConstants.TAG, "Could not get track points cursor.");
|
||||
}
|
||||
@@ -656,6 +664,11 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
if (recordingTrack != null) {
|
||||
restoreStats(recordingTrack);
|
||||
isRecording = true;
|
||||
} else {
|
||||
// Make sure we have consistent state in shared preferences.
|
||||
Log.w(MyTracksConstants.TAG, "TrackRecordingService.onCreate: Resetting "
|
||||
+ "an orphaned recording track: " + recordingTrackId);
|
||||
prefManager.setRecordingTrack(recordingTrackId = -1);
|
||||
}
|
||||
showNotification();
|
||||
}
|
||||
@@ -739,8 +752,10 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
// Make sure that the current track exists and is fresh enough.
|
||||
if (recordingTrack == null || !shouldResumeTrack(recordingTrack)) {
|
||||
Log.i(MyTracksConstants.TAG,
|
||||
"TrackRecordingService: Not resuming because the previous track "
|
||||
+ "doesn't exist or is too old");
|
||||
"TrackRecordingService: Not resuming, because the previous track ("
|
||||
+ recordingTrack + ") doesn't exist or is too old");
|
||||
isRecording = false;
|
||||
prefManager.setRecordingTrack(recordingTrackId = -1);
|
||||
stopSelfResult(startId);
|
||||
return;
|
||||
}
|
||||
@@ -753,16 +768,12 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
SharedPreferences sharedPreferences, int retryAttempts) {
|
||||
Log.d(MyTracksConstants.TAG,
|
||||
"Updating auto-resume retry attempts to: " + retryAttempts);
|
||||
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putInt(
|
||||
getString(R.string.auto_resume_track_current_retry_key), retryAttempts);
|
||||
editor.commit();
|
||||
prefManager.setAutoResumeTrackCurrentRetry(retryAttempts);
|
||||
}
|
||||
|
||||
private boolean shouldResumeTrack(Track track) {
|
||||
Log.d(MyTracksConstants.TAG,
|
||||
"maybeResumeTrack: autoResumeTrackTimeout = " + autoResumeTrackTimeout);
|
||||
Log.d(MyTracksConstants.TAG, "shouldResumeTrack: autoResumeTrackTimeout = "
|
||||
+ autoResumeTrackTimeout);
|
||||
|
||||
// Check if we haven't exceeded the maximum number of retry attempts.
|
||||
SharedPreferences sharedPreferences =
|
||||
@@ -770,11 +781,11 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
int retries = sharedPreferences.getInt(
|
||||
getString(R.string.auto_resume_track_current_retry_key), 0);
|
||||
Log.d(MyTracksConstants.TAG,
|
||||
"TrackRecordingService: Attempting to auto-resume the track ("
|
||||
"shouldResumeTrack: Attempting to auto-resume the track ("
|
||||
+ (retries + 1) + "/" + MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS + ")");
|
||||
if (retries >= MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS) {
|
||||
Log.i(MyTracksConstants.TAG,
|
||||
"TrackRecordingService: Not resuming because exceeded the maximum "
|
||||
"shouldResumeTrack: Not resuming because exceeded the maximum "
|
||||
+ "number of auto-resume retries");
|
||||
return false;
|
||||
}
|
||||
@@ -785,9 +796,13 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
// Check for special cases.
|
||||
if (autoResumeTrackTimeout == 0) {
|
||||
// Never resume.
|
||||
Log.d(MyTracksConstants.TAG,
|
||||
"shouldResumeTrack: Auto-resume disabled (never resume)");
|
||||
return false;
|
||||
} else if (autoResumeTrackTimeout == -1) {
|
||||
// Always resume.
|
||||
Log.d(MyTracksConstants.TAG,
|
||||
"shouldResumeTrack: Auto-resume forced (always resume)");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -795,7 +810,8 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
long lastModified =
|
||||
track.getStatistics() != null ? track.getStatistics().getStopTime() : 0;
|
||||
Log.d(MyTracksConstants.TAG,
|
||||
"maybeResumeTrack: lastModified = " + lastModified);
|
||||
"shouldResumeTrack: lastModified = " + lastModified
|
||||
+ ", autoResumeTrackTimeout: " + autoResumeTrackTimeout);
|
||||
return lastModified > 0 && System.currentTimeMillis() - lastModified <=
|
||||
autoResumeTrackTimeout * 60 * 1000;
|
||||
}
|
||||
@@ -805,6 +821,11 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
}
|
||||
|
||||
public long insertWaypointMarker(Waypoint waypoint) {
|
||||
if (!isRecording()) {
|
||||
throw new IllegalStateException(
|
||||
"Unable to insert waypoint marker while not recording!");
|
||||
}
|
||||
|
||||
if (waypoint.getLocation() != null) {
|
||||
waypoint.setLength(length);
|
||||
waypoint.setDuration(waypoint.getLocation().getTime()
|
||||
@@ -823,6 +844,11 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
* @return the unique id of the inserted marker
|
||||
*/
|
||||
public long insertStatisticsMarker(Location location) {
|
||||
if (!isRecording()) {
|
||||
throw new IllegalStateException(
|
||||
"Unable to insert statistics marker while not recording!");
|
||||
}
|
||||
|
||||
StringUtils utils = new StringUtils(TrackRecordingService.this);
|
||||
|
||||
// Create a new waypoint to save
|
||||
@@ -850,8 +876,7 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
Uri uri = providerUtils.insertWaypoint(waypoint);
|
||||
|
||||
// Create a new stats keeper for the next marker
|
||||
waypointStatsBuilder = new TripStatisticsBuilder();
|
||||
waypointStatsBuilder.resumeAt(time);
|
||||
waypointStatsBuilder = new TripStatisticsBuilder(time);
|
||||
updateCurrentWaypoint();
|
||||
return Long.parseLong(uri.getLastPathSegment());
|
||||
}
|
||||
@@ -908,6 +933,10 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
@Override
|
||||
public void endCurrentTrack() {
|
||||
Log.d(MyTracksConstants.TAG, "TrackRecordingService.endCurrentTrack");
|
||||
if (recordingTrackId == -1 || !isRecording) {
|
||||
throw new IllegalStateException("No recording track in progress!");
|
||||
}
|
||||
|
||||
isRecording = false;
|
||||
Track recordingTrack = providerUtils.getTrack(recordingTrackId);
|
||||
if (recordingTrack != null) {
|
||||
@@ -927,12 +956,15 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
"_id=" + recordingTrack.getId(), null);
|
||||
}
|
||||
showNotification();
|
||||
recordingTrackId = -1;
|
||||
prefManager.setRecordingTrack(recordingTrackId = -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAllTracks() {
|
||||
endCurrentTrack();
|
||||
if (isRecording()) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot delete all tracks while recording!");
|
||||
}
|
||||
providerUtils.deleteAllTracks();
|
||||
}
|
||||
|
||||
@@ -951,32 +983,41 @@ public class TrackRecordingService extends Service implements LocationListener {
|
||||
|
||||
public long startNewTrack() {
|
||||
Log.d(MyTracksConstants.TAG, "TrackRecordingService.startNewTrack");
|
||||
if (recordingTrackId != -1 || isRecording) {
|
||||
throw new IllegalStateException("A track is already in progress!");
|
||||
}
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
Track track = new Track();
|
||||
TripStatistics trackStats = track.getStatistics();
|
||||
track.setName("new");
|
||||
long startTime = System.currentTimeMillis();
|
||||
trackStats.setStartTime(startTime);
|
||||
track.setStartId(-1);
|
||||
Uri trackUri = providerUtils.insertTrack(track);
|
||||
recordingTrackId = Long.parseLong(trackUri.getLastPathSegment());
|
||||
track.setId(recordingTrackId);
|
||||
track.setName(String.format(getString(R.string.new_track), recordingTrackId));
|
||||
providerUtils.updateTrack(track);
|
||||
currentWaypointId = insertStatisticsMarker(null);
|
||||
track.setName(new DefaultTrackNameFactory(this).newTrackName(
|
||||
recordingTrackId, startTime));
|
||||
isRecording = true;
|
||||
isMoving = true;
|
||||
statsBuilder = new TripStatisticsBuilder();
|
||||
statsBuilder.resumeAt(startTime);
|
||||
|
||||
providerUtils.updateTrack(track);
|
||||
statsBuilder = new TripStatisticsBuilder(startTime);
|
||||
waypointStatsBuilder = new TripStatisticsBuilder(startTime);
|
||||
currentWaypointId = insertStatisticsMarker(null);
|
||||
setUpAnnouncer();
|
||||
length = 0;
|
||||
showNotification();
|
||||
registerLocationListener();
|
||||
splitManager.restore();
|
||||
signalManager.restore();
|
||||
|
||||
// Reset the number of auto-resume retries.
|
||||
SharedPreferences sharedPreferences =
|
||||
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
|
||||
setAutoResumeTrackRetries(sharedPreferences, 0);
|
||||
setAutoResumeTrackRetries(
|
||||
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0), 0);
|
||||
// Persist the current recording track.
|
||||
prefManager.setRecordingTrack(recordingTrackId);
|
||||
|
||||
return recordingTrackId;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,13 +36,13 @@ public class TripStatisticsBuilder {
|
||||
/**
|
||||
* The last location that the gps reported.
|
||||
*/
|
||||
private Location lastLocation = null;
|
||||
private Location lastLocation;
|
||||
|
||||
/**
|
||||
* The last location that contributed to the stats. It is also the last
|
||||
* location the user was found to be moving.
|
||||
*/
|
||||
private Location lastMovingLocation = null;
|
||||
private Location lastMovingLocation;
|
||||
|
||||
/**
|
||||
* The current speed in meters/second as reported by the gps.
|
||||
@@ -90,10 +90,13 @@ public class TripStatisticsBuilder {
|
||||
private long totalLocations = 0;
|
||||
|
||||
/**
|
||||
* Creates a new trip starting at the current system time.
|
||||
* Creates a new trip starting at the given time.
|
||||
*
|
||||
* @param startTime the start time.
|
||||
*/
|
||||
public TripStatisticsBuilder() {
|
||||
public TripStatisticsBuilder(long startTime) {
|
||||
data = new TripStatistics();
|
||||
resumeAt(startTime);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,6 +106,9 @@ public class TripStatisticsBuilder {
|
||||
*/
|
||||
public TripStatisticsBuilder(TripStatistics statsData) {
|
||||
data = new TripStatistics(statsData);
|
||||
if (data.getStartTime() > 0) {
|
||||
resumeAt(data.getStartTime());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,8 +146,8 @@ public class TripStatisticsBuilder {
|
||||
|
||||
// Don't do anything if we didn't move since last fix:
|
||||
double distance = lastLocation.distanceTo(currentLocation);
|
||||
if (distance < MyTracksConstants.MAX_NO_MOVEMENT_DISTANCE
|
||||
&& currentSpeed < MyTracksConstants.MAX_NO_MOVEMENT_SPEED) {
|
||||
if (distance < MyTracksConstants.MAX_NO_MOVEMENT_DISTANCE &&
|
||||
currentSpeed < MyTracksConstants.MAX_NO_MOVEMENT_SPEED) {
|
||||
lastLocation = currentLocation;
|
||||
return false;
|
||||
}
|
||||
@@ -291,13 +297,6 @@ public class TripStatisticsBuilder {
|
||||
data.updateGradeExtremities(gradeBuffer.getAverage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the track at the current time.
|
||||
*/
|
||||
public void pause() {
|
||||
pauseAt(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the track at the given time.
|
||||
*
|
||||
@@ -312,13 +311,6 @@ public class TripStatisticsBuilder {
|
||||
paused = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the current track at the current time.
|
||||
*/
|
||||
public void resume() {
|
||||
resumeAt(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the current track at the given time.
|
||||
*
|
||||
@@ -364,8 +356,7 @@ public class TripStatisticsBuilder {
|
||||
}
|
||||
|
||||
public TripStatistics getStatistics() {
|
||||
// Take a snapshot - we do't want anyone messing with our internals
|
||||
// Take a snapshot - we don't want anyone messing with our internals
|
||||
return new TripStatistics(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.util;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracksConstants;
|
||||
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Utility class for determining if newer-API features are available on the
|
||||
@@ -28,9 +31,15 @@ public class ApiFeatures {
|
||||
/**
|
||||
* The API level of the Android version we're being run under.
|
||||
*/
|
||||
public static final int ANDROID_API_LEVEL = Integer.parseInt(Build.VERSION.SDK);
|
||||
|
||||
public static final int ANDROID_API_LEVEL = Integer.parseInt(
|
||||
Build.VERSION.SDK);
|
||||
|
||||
private static ApiFeatures instance;
|
||||
|
||||
/**
|
||||
* The API platform adapter supported by this system.
|
||||
*/
|
||||
private ApiPlatformAdapter apiPlatformAdapter;
|
||||
|
||||
/**
|
||||
* Returns the singleton instance of this class.
|
||||
@@ -52,7 +61,28 @@ public class ApiFeatures {
|
||||
/**
|
||||
* Allow subclasses for mocking, but no direct instantiation.
|
||||
*/
|
||||
protected ApiFeatures() {}
|
||||
protected ApiFeatures() {
|
||||
if (getApiLevel() >= 5) {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(
|
||||
"com.google.android.apps.mytracks.util.EclairPlatformAdapter");
|
||||
apiPlatformAdapter = (ApiPlatformAdapter) clazz.newInstance();
|
||||
} catch (Exception e) {
|
||||
Log.i(MyTracksConstants.TAG, "ApiFeatures: Unable to instantiate Eclair"
|
||||
+ " platform adapter", e);
|
||||
}
|
||||
}
|
||||
if (apiPlatformAdapter == null) {
|
||||
Log.i(MyTracksConstants.TAG,
|
||||
"ApiFeatures: Using default platform adapter");
|
||||
// Cupcake adapter is always supported, so it's safe to do static linkage.
|
||||
apiPlatformAdapter = new CupcakePlatformAdapter();
|
||||
}
|
||||
}
|
||||
|
||||
public ApiPlatformAdapter getApiPlatformAdapter() {
|
||||
return apiPlatformAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether cloud backup (a.k.a. Froyo backup) is available.
|
||||
@@ -81,7 +111,7 @@ public class ApiFeatures {
|
||||
public boolean hasModernSignalStrength() {
|
||||
return getApiLevel() >= 7;
|
||||
}
|
||||
|
||||
|
||||
// Visible for testing.
|
||||
protected int getApiLevel() {
|
||||
return ANDROID_API_LEVEL;
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2010 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.util;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Service;
|
||||
import android.os.HandlerThread;
|
||||
|
||||
/**
|
||||
* A set of methods that may be implemented in a platform specific way.
|
||||
*
|
||||
* @author Bartlomiej Niechwiej
|
||||
*/
|
||||
public interface ApiPlatformAdapter {
|
||||
|
||||
/**
|
||||
* Puts the specified service into foreground.
|
||||
*
|
||||
* @param service the service to be put in foreground.
|
||||
* @param notificationManager the notification manager used to post the given
|
||||
* notification.
|
||||
* @param id the ID of the notification, unique within the application.
|
||||
* @param notification the notification to post.
|
||||
*/
|
||||
void startForeground(Service service, NotificationManager notificationManager,
|
||||
int id, Notification notification);
|
||||
|
||||
/**
|
||||
* Puts the given service into background.
|
||||
* @param service the service to put into background.
|
||||
* @param notificationManager the notification manager to user when removing
|
||||
* notifications.
|
||||
* @param id the ID of the notification to be remove, or -1 if the
|
||||
* notification shouldn't be removed.
|
||||
*/
|
||||
void stopForeground(Service service, NotificationManager notificationManager,
|
||||
int id);
|
||||
|
||||
/**
|
||||
* Terminates the given handler thread.
|
||||
*
|
||||
* @param handlerThread the thread to be terminated.
|
||||
* @return true whether the handler has been stopped or not.
|
||||
*/
|
||||
boolean stopHandlerThread(HandlerThread handlerThread);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2010 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.util;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Service;
|
||||
import android.os.HandlerThread;
|
||||
|
||||
/**
|
||||
* The Cupcake (API level 3) specific implementation of the
|
||||
* {@link ApiPlatformAdapter}.
|
||||
*
|
||||
* @author Bartlomiej Niechwiej
|
||||
*/
|
||||
public class CupcakePlatformAdapter implements ApiPlatformAdapter {
|
||||
|
||||
@Override
|
||||
public void startForeground(Service service,
|
||||
NotificationManager notificationManager, int id,
|
||||
Notification notification) {
|
||||
service.setForeground(true);
|
||||
notificationManager.notify(id, notification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopForeground(Service service,
|
||||
NotificationManager notificationManager, int id) {
|
||||
service.setForeground(false);
|
||||
if (id != -1) {
|
||||
notificationManager.cancel(id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stopHandlerThread(HandlerThread handlerThread) {
|
||||
// Do nothing, as Cupcake doesn't provide quit().
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2010 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.util;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Service;
|
||||
import android.os.HandlerThread;
|
||||
|
||||
/**
|
||||
* The Eclair (API level 5) specific implementation of the
|
||||
* {@link ApiPlatformAdapter}.
|
||||
*
|
||||
* @author Bartlomiej Niechwiej
|
||||
*/
|
||||
public class EclairPlatformAdapter implements ApiPlatformAdapter {
|
||||
|
||||
@Override
|
||||
public void startForeground(Service service,
|
||||
NotificationManager notificationManager, int id,
|
||||
Notification notification) {
|
||||
service.startForeground(id, notification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopForeground(Service service,
|
||||
NotificationManager notificationManager, int id) {
|
||||
service.stopForeground(id != -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stopHandlerThread(HandlerThread handlerThread) {
|
||||
return handlerThread.quit();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user