diff --git a/MyTracks/AndroidManifest.xml b/MyTracks/AndroidManifest.xml
index 3b9270fa0..40c852901 100755
--- a/MyTracks/AndroidManifest.xml
+++ b/MyTracks/AndroidManifest.xml
@@ -52,7 +52,7 @@ limitations under the License.
-
@@ -61,19 +61,19 @@ limitations under the License.
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|fontScale"
android:exported="false" />
-
-
-
-
-
-
+
diff --git a/MyTracks/src/com/google/android/apps/mytracks/AccountChooser.java b/MyTracks/src/com/google/android/apps/mytracks/AccountChooser.java
index cfd1cda39..7a648a304 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/AccountChooser.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/AccountChooser.java
@@ -59,7 +59,7 @@ public class AccountChooser {
public void chooseAccount(final Activity activity,
final AccountHandler handler) {
final Account[] accounts = AccountManager.get(activity)
- .getAccountsByType(MyTracksConstants.ACCOUNT_TYPE);
+ .getAccountsByType(Constants.ACCOUNT_TYPE);
if (accounts.length < 1) {
alertNoAccounts(activity, handler);
return;
@@ -76,7 +76,7 @@ public class AccountChooser {
}
// Let the user choose.
- Log.e(MyTracksConstants.TAG, "Multiple matching accounts found.");
+ Log.e(Constants.TAG, "Multiple matching accounts found.");
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(R.string.choose_account_title);
builder.setCancelable(false);
@@ -112,7 +112,7 @@ public class AccountChooser {
*/
private void alertNoAccounts(final Activity activity,
final AccountHandler handler) {
- Log.e(MyTracksConstants.TAG, "No matching accounts found.");
+ Log.e(Constants.TAG, "No matching accounts found.");
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(R.string.no_account_found_title);
builder.setMessage(R.string.no_account_found);
diff --git a/MyTracks/src/com/google/android/apps/mytracks/AggregatedStatsActivity.java b/MyTracks/src/com/google/android/apps/mytracks/AggregatedStatsActivity.java
index c4e4e0728..cb385f35c 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/AggregatedStatsActivity.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/AggregatedStatsActivity.java
@@ -40,7 +40,7 @@ public class AggregatedStatsActivity extends Activity implements
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
- Log.d(MyTracksConstants.TAG, "StatsActivity: onSharedPreferences changed "
+ Log.d(Constants.TAG, "StatsActivity: onSharedPreferences changed "
+ key);
if (key != null) {
if (key.equals(R.string.metric_units_key)) {
@@ -67,7 +67,7 @@ public class AggregatedStatsActivity extends Activity implements
sv.setScrollBarStyle(ScrollView.SCROLLBARS_OUTSIDE_INSET);
SharedPreferences preferences = getSharedPreferences(
- MyTracksSettings.SETTINGS_NAME, 0);
+ Constants.SETTINGS_NAME, 0);
if (preferences != null) {
metricUnits = preferences.getBoolean(getString(R.string.metric_units_key), true);
preferences.registerOnSharedPreferenceChangeListener(this);
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracksReceiver.java b/MyTracks/src/com/google/android/apps/mytracks/BootReceiver.java
similarity index 84%
rename from MyTracks/src/com/google/android/apps/mytracks/MyTracksReceiver.java
rename to MyTracks/src/com/google/android/apps/mytracks/BootReceiver.java
index 9847ab2ee..3ed021fb8 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracksReceiver.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/BootReceiver.java
@@ -16,8 +16,8 @@
package com.google.android.apps.mytracks;
import static android.content.Intent.ACTION_BOOT_COMPLETED;
-import static com.google.android.apps.mytracks.MyTracksConstants.RESUME_TRACK_EXTRA_NAME;
-import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
+import static com.google.android.apps.mytracks.Constants.RESUME_TRACK_EXTRA_NAME;
+import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.services.TrackRecordingService;
@@ -41,17 +41,17 @@ import android.util.Log;
*
* @author Bartlomiej Niechwiej
*/
-public class MyTracksReceiver extends BroadcastReceiver {
+public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- Log.d(TAG, "MyTracksReceiver.onReceive: " + intent.getAction());
+ Log.d(TAG, "BootReceiver.onReceive: " + intent.getAction());
if (ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
Intent startIntent = new Intent(context, TrackRecordingService.class);
startIntent.putExtra(RESUME_TRACK_EXTRA_NAME, true);
context.startService(startIntent);
} else {
- Log.w(TAG, "MyTracksReceiver: unsupported action");
+ Log.w(TAG, "BootReceiver: unsupported action");
}
}
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/ChartActivity.java b/MyTracks/src/com/google/android/apps/mytracks/ChartActivity.java
index 73f201776..d62b1e2dc 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/ChartActivity.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/ChartActivity.java
@@ -15,31 +15,25 @@
*/
package com.google.android.apps.mytracks;
+import static com.google.android.apps.mytracks.Constants.TAG;
+
import com.google.android.apps.mytracks.ChartView.Mode;
import com.google.android.apps.mytracks.content.MyTracksLocation;
-import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Sensor;
-import com.google.android.apps.mytracks.content.Track;
-import com.google.android.apps.mytracks.content.TrackPointsColumns;
-import com.google.android.apps.mytracks.content.Waypoint;
-import com.google.android.apps.mytracks.content.WaypointsColumns;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
+import com.google.android.apps.mytracks.content.Track;
+import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.services.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.stats.DoubleBuffer;
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
import com.google.android.apps.mytracks.util.ApiFeatures;
-import com.google.android.apps.mytracks.util.MyTracksUtils;
+import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
-import android.content.SharedPreferences;
-import android.database.ContentObserver;
-import android.database.Cursor;
import android.location.Location;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -56,48 +50,28 @@ import java.util.ArrayList;
* An activity that displays a chart from the track point provider.
*
* @author Sandor Dornbush
+ * @author Rodrigo Damazio
*/
-public class ChartActivity extends Activity implements
- SharedPreferences.OnSharedPreferenceChangeListener {
-
- private final static int BUFFER_SIZE = 1024;
- private double profileLength = 0;
-
- private boolean metricUnits = true;
- private boolean reportSpeed = true;
-
- /**
- * The track id that is displayed.
- */
- private long selectedTrackId = -1;
-
- /**
- * Id of the last location that was seen when reading tracks from the
- * provider. This is used to determine which locations are new compared to the
- * last time the chart was updated.
- */
- private long lastSeenLocationId = -1;
-
- private long startTime = -1;
-
- private Location lastLocation;
-
- /**
- * The id of the track currently being recorded.
- */
- private long recordingTrackId = -1;
+public class ChartActivity extends Activity implements TrackDataListener {
private final DoubleBuffer elevationBuffer =
- new DoubleBuffer(MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
+ new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR);
private final DoubleBuffer speedBuffer =
- new DoubleBuffer(MyTracksConstants.SPEED_SMOOTHING_FACTOR);
+ new DoubleBuffer(Constants.SPEED_SMOOTHING_FACTOR);
+ private final ArrayList pendingPoints = new ArrayList();
+ private TrackDataHub dataHub;
+
+ // Stats gathered from received data.
+ private double profileLength = 0;
+ private long startTime = -1;
+ private Location lastLocation;
+ private double trackMaxSpeed;
+
+ // Modes of operation
private Mode mode = Mode.BY_DISTANCE;
-
- /**
- * Utilities to deal with the database.
- */
- private MyTracksProviderUtils providerUtils;
+ private boolean metricUnits;
+ private boolean reportSpeed;
/*
* UI elements:
@@ -107,9 +81,6 @@ public class ChartActivity extends Activity implements
private LinearLayout busyPane;
private ZoomControls zoomControls;
- /** Handler for callbacks to the UI thread */
- private final Handler uiHandler = new Handler();
-
/**
* A runnable that can be posted to the UI thread. It will remove the spinner
* (if any), enable/disable zoom controls and orange pointer as appropriate
@@ -121,89 +92,17 @@ public class ChartActivity extends Activity implements
busyPane.setVisibility(View.GONE);
zoomControls.setIsZoomInEnabled(chartView.canZoomIn());
zoomControls.setIsZoomOutEnabled(chartView.canZoomOut());
- chartView.setShowPointer(selectedTrackIsRecording());
+ chartView.setShowPointer(dataHub.isRecordingSelected());
chartView.invalidate();
}
};
- /**
- * A runnable that can be posted to the UI thread. It will show the spinner.
- */
- private final Runnable showSpinner = new Runnable() {
- @Override
- public void run() {
- busyPane.setVisibility(View.VISIBLE);
- }
- };
-
- /**
- * An observer for the tracks provider. Will listen to new track points being
- * added and update the chart if necessary.
- */
- private ContentObserver observer;
-
- /**
- * An observer for the waypoints provider. Will listen to new way points being
- * added and update the chart if necessary.
- */
- private ContentObserver waypointObserver;
-
- /**
- * A thread with a looper. Post to updateTrackHandler to execute Runnables on
- * this thread.
- */
- private final HandlerThread updateTrackThread =
- new HandlerThread("updateTrackThread");
-
- /** Handler for updateTrackThread */
- private Handler updateTrackHandler;
-
- /**
- * A runnable that updates the profile from the provider.
- */
- private final Runnable updateTrackRunnable = new Runnable() {
- @Override
- public void run() {
- readNewTrackPoints();
- }
- };
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
- String key) {
- if (key != null) {
- if (key.equals(getString(R.string.selected_track_key))) {
- selectedTrackId =
- sharedPreferences.getLong(getString(R.string.selected_track_key),
- -1);
- readProfileAsync();
- } else if (key.equals(getString(R.string.metric_units_key))) {
- metricUnits =
- sharedPreferences.getBoolean(getString(R.string.metric_units_key),
- true);
- chartView.setMetricUnits(metricUnits);
- readProfileAsync();
- } else if (key.equals(getString(R.string.report_speed_key))) {
- reportSpeed =
- sharedPreferences.getBoolean(getString(R.string.report_speed_key),
- true);
- chartView.setReportSpeed(reportSpeed, this);
- readProfileAsync();
- } else if (key.equals(getString(R.string.recording_track_key))) {
- recordingTrackId =
- sharedPreferences.getLong(getString(R.string.recording_track_key),
- -1);
- runOnUiThread(updateChart);
- }
- }
- }
-
@Override
protected void onCreate(Bundle savedInstanceState) {
- Log.w(MyTracksConstants.TAG, "ChartActivity.onCreate");
+ Log.w(TAG, "ChartActivity.onCreate");
super.onCreate(savedInstanceState);
MyTracks.getInstance().setChartActivity(this);
- providerUtils = MyTracksProviderUtils.Factory.get(this);
+ dataHub = MyTracks.getInstance().getDataHub();
// The volume we want to control is the Text-To-Speech volume
int volumeStream =
@@ -219,22 +118,6 @@ public class ChartActivity extends Activity implements
new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
layout.addView(chartView, params);
- SharedPreferences preferences =
- getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
- if (preferences != null) {
- selectedTrackId =
- preferences.getLong(getString(R.string.selected_track_key), -1);
- recordingTrackId =
- preferences.getLong(getString(R.string.recording_track_key), -1);
- metricUnits = preferences.getBoolean(getString(R.string.metric_units_key),
- true);
- chartView.setMetricUnits(metricUnits);
- reportSpeed = preferences.getBoolean(getString(R.string.report_speed_key),
- true);
- chartView.setReportSpeed(reportSpeed, this);
- preferences.registerOnSharedPreferenceChangeListener(this);
- }
-
busyPane = (LinearLayout) findViewById(R.id.elevation_busypane);
zoomControls = (ZoomControls) findViewById(R.id.elevation_zoom);
zoomControls.setOnZoomInClickListener(new View.OnClickListener() {
@@ -249,97 +132,20 @@ public class ChartActivity extends Activity implements
zoomOut();
}
});
-
- updateTrackThread.start();
- updateTrackHandler = new Handler(updateTrackThread.getLooper());
-
- // Register observer for the track point provider:
- Handler contentHandler = new Handler();
- observer = new ContentObserver(contentHandler) {
- @Override
- 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 (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
- // bother.
- return;
- }
- // Update can potentially be lengthy, put it in its own thread:
- updateTrackHandler.post(updateTrackRunnable);
- super.onChange(selfChange);
- }
- };
-
- waypointObserver = new ContentObserver(contentHandler) {
- @Override
- public void onChange(boolean selfChange) {
- Log.d(MyTracksConstants.TAG,
- "MyTracksMap: ContentObserver.onChange waypoints");
- if (selectedTrackId < 0) {
- return;
- }
- Thread t = new Thread() {
- @Override
- public void run() {
- readWaypoints();
- ChartActivity.this.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- chartView.invalidate();
- }
- });
- }
- };
- t.start();
- super.onChange(selfChange);
- }
- };
-
- readProfileAsync();
}
@Override
- protected void onPause() {
- super.onPause();
- unregisterContentObservers();
+ protected void onStart() {
+ super.onStart();
+
+ dataHub.registerTrackDataListener(this);
}
@Override
- protected void onResume() {
- super.onResume();
- // Make sure any updates that might have happened are propagated to this
- // activity:
- observer.onChange(false);
- waypointObserver.onChange(false);
- registerContentObservers();
- }
+ protected void onStop() {
+ dataHub.unregisterTrackDataListener(this);
- /**
- * Register the content observer for the map overlay.
- */
- private void registerContentObservers() {
- getContentResolver().registerContentObserver(TrackPointsColumns.CONTENT_URI,
- false/* notifyForDescendents */, observer);
- getContentResolver().registerContentObserver(WaypointsColumns.CONTENT_URI,
- false/* notifyForDescendents */, waypointObserver);
- }
-
- /**
- * Unregister the content observer for the map overlay.
- */
- private void unregisterContentObservers() {
- getContentResolver().unregisterContentObserver(observer);
- getContentResolver().unregisterContentObserver(waypointObserver);
- }
-
- private boolean selectedTrackIsRecording() {
- return selectedTrackId == recordingTrackId;
+ super.onStop();
}
private void zoomIn() {
@@ -358,7 +164,7 @@ public class ChartActivity extends Activity implements
if (this.mode != newMode) {
this.mode = newMode;
chartView.setMode(this.mode);
- readProfileAsync();
+ dataHub.reloadDataFor(this);
}
}
@@ -375,39 +181,11 @@ public class ChartActivity extends Activity implements
return chartView.getChartValueSeries(index).isEnabled();
}
- private void readWaypoints() {
- if (selectedTrackId < 0) {
- return;
- }
- Cursor cursor = null;
- chartView.clearWaypoints();
- try {
- // We will silently drop extra waypoints to make the app responsive.
- cursor =
- providerUtils.getWaypointsCursor(selectedTrackId, 0,
- MyTracksConstants.MAX_DISPLAYED_TRACK_POINTS);
- if (cursor != null) {
- if (cursor.moveToFirst()) {
- do {
- Waypoint wpt = providerUtils.createWaypoint(cursor);
- chartView.addWaypoint(wpt);
- } while (cursor.moveToNext());
- }
- }
- } catch (RuntimeException e) {
- Log.w(MyTracksConstants.TAG, "Caught an unexpected exception.", e);
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
chartSettingsMenuItem =
- menu.add(0, MyTracksConstants.MENU_CHART_SETTINGS, 0,
+ menu.add(0, Constants.MENU_CHART_SETTINGS, 0,
R.string.chart_settings);
chartSettingsMenuItem.setIcon(R.drawable.chart_settings);
return true;
@@ -416,7 +194,7 @@ public class ChartActivity extends Activity implements
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case MyTracksConstants.MENU_CHART_SETTINGS:
+ case Constants.MENU_CHART_SETTINGS:
MyTracks.getInstance().getDialogManager().showDialogSafely(
DialogManager.DIALOG_CHART_SETTINGS);
return true;
@@ -438,43 +216,41 @@ public class ChartActivity extends Activity implements
* This must be called in order for each point.
*
* @param location the location to get data for (this method takes ownership of that location)
- * @param track the track to get data from
* @param result the resulting point to fill out
* @return the previous location, now available for reuse
*/
- private Location getDataPoint(Location location, Track track, double[] result) {
+ private void fillDataPoint(Location location, double result[]) {
+ double timeOrDistance = Double.NaN,
+ elevation = Double.NaN,
+ speed = Double.NaN,
+ power = Double.NaN,
+ cadence = Double.NaN,
+ heartRate = Double.NaN;
+
if (location instanceof MyTracksLocation &&
((MyTracksLocation) location).getSensorDataSet() != null) {
SensorDataSet sensorData = ((MyTracksLocation) location).getSensorDataSet();
if (sensorData.hasPower()
&& sensorData.getPower().getState() == Sensor.SensorState.SENDING
&& sensorData.getPower().hasValue()) {
- result[3] = sensorData.getPower().getValue();
- } else {
- result[3] = Double.NaN;
+ power = sensorData.getPower().getValue();
}
if (sensorData.hasCadence()
&& sensorData.getCadence().getState() == Sensor.SensorState.SENDING
&& sensorData.getCadence().hasValue()) {
- result[4] = sensorData.getCadence().getValue();
- } else {
- result[4] = Double.NaN;
+ cadence = sensorData.getCadence().getValue();
}
if (sensorData.hasHeartRate()
&& sensorData.getHeartRate().getState() == Sensor.SensorState.SENDING
&& sensorData.getHeartRate().hasValue()) {
- result[5] = sensorData.getHeartRate().getValue();
- } else {
- result[5] = Double.NaN;
+ heartRate = sensorData.getHeartRate().getValue();
}
- } else {
- result[3] = Double.NaN;
- result[4] = Double.NaN;
- result[5] = Double.NaN;
}
+
+ // TODO: Account for segment splits?
switch (mode) {
case BY_DISTANCE:
- result[0] = profileLength;
+ timeOrDistance = profileLength;
if (lastLocation != null) {
double d = lastLocation.distanceTo(location);
if (metricUnits) {
@@ -489,16 +265,16 @@ public class ChartActivity extends Activity implements
// Base case
startTime = location.getTime();
}
- result[0] = (location.getTime() - startTime);
+ timeOrDistance = (location.getTime() - startTime);
break;
default:
- Log.w(MyTracksConstants.TAG, "ChartActivity unknown mode: " + mode);
+ Log.w(TAG, "ChartActivity unknown mode: " + mode);
}
elevationBuffer.setNext(metricUnits
? location.getAltitude()
: location.getAltitude() * UnitConversions.M_TO_FT);
- result[1] = elevationBuffer.getAverage();
+ elevation = elevationBuffer.getAverage();
if (lastLocation == null) {
if (Math.abs(location.getSpeed() - 128) > 1) {
@@ -507,151 +283,134 @@ public class ChartActivity extends Activity implements
} else if (TripStatisticsBuilder.isValidSpeed(
location.getTime(), location.getSpeed(), lastLocation.getTime(),
lastLocation.getSpeed(), speedBuffer)
- && (location.getSpeed() <= track.getStatistics().getMaxSpeed())) {
+ && (location.getSpeed() <= trackMaxSpeed)) {
speedBuffer.setNext(location.getSpeed());
}
- result[2] = speedBuffer.getAverage() * 3.6;
+ speed = speedBuffer.getAverage() * 3.6;
if (!metricUnits) {
- result[2] *= UnitConversions.KM_TO_MI;
+ speed *= UnitConversions.KM_TO_MI;
}
- if (!reportSpeed && (result[2] != 0)) {
- // Format as hours per unit
- result[2] = (60.0 / result[2]);
+ if (!reportSpeed) {
+ if (speed != 0) {
+ // Format as hours per unit
+ speed = (60.0 / speed);
+ } else {
+ speed = Double.NaN;
+ }
}
- Location oldLastLocation = lastLocation;
+ // Keep a copy so the location can be reused.
lastLocation = location;
- if (oldLastLocation == null) {
- // No previous location, but return a blank one for reuse
- return new MyTracksLocation("");
+ if (result != null) {
+ result[0] = timeOrDistance;
+ result[1] = elevation;
+ result[2] = speed;
+ result[3] = power;
+ result[4] = cadence;
+ result[5] = heartRate;
}
-
- return oldLastLocation;
}
- /**
- * Sets the chart data points reading from the provider. This is non-blocking.
- */
- private void readProfileAsync() {
- chartView.reset();
- updateTrackHandler.post(new Runnable() {
+ @Override
+ public void onProviderStateChange(ProviderState state) {
+ // We don't care.
+ }
+
+ @Override
+ public void onCurrentLocationChanged(Location loc) {
+ // We don't care.
+ }
+
+ @Override
+ public void onCurrentHeadingChanged(double heading) {
+ // We don't care.
+ }
+
+ @Override
+ public void onSelectedTrackChanged(Track track, boolean isRecording) {
+ Log.e(TAG, "Visible", new Throwable());
+ runOnUiThread(new Runnable() {
+ @Override
public void run() {
- runOnUiThread(showSpinner);
- readProfile();
- readWaypoints();
- runOnUiThread(updateChart);
+ busyPane.setVisibility(View.VISIBLE);
}
});
}
- /**
- * Reads the track profile from the provider. This is a blocking function and
- * should not be run from the UI thread.
- */
- private void readProfile() {
+ @Override
+ public void onTrackUpdated(Track track) {
+ trackMaxSpeed = track.getStatistics().getMaxSpeed();
+ }
+
+ @Override
+ public void clearTrackPoints() {
profileLength = 0;
lastLocation = null;
startTime = -1;
- if (selectedTrackId < 0) {
- return;
- }
- Track track = providerUtils.getTrack(selectedTrackId);
- if (track == null) {
- return;
- }
- lastSeenLocationId = track.getStartId();
- final ArrayList theData = readPointsToList(track);
- runOnUiThread(new Runnable() {
- public void run() {
- chartView.setDataPoints(theData);
- }
- });
+ elevationBuffer.reset();
+ speedBuffer.reset();
+ chartView.reset();
+ pendingPoints.clear();
}
- /**
- * Read all new track points.
- */
- private void readNewTrackPoints() {
- Log.i(MyTracksConstants.TAG, "MyTracks: Updating chart last seen: " + lastSeenLocationId);
- Track track = providerUtils.getTrack(recordingTrackId);
- if (track == null) {
- Log.w(MyTracksConstants.TAG, "MyTracks: track not found");
- return;
+ @Override
+ public void onNewTrackPoint(Location loc) {
+ if (LocationUtils.isValidLocation(loc)) {
+ double[] point = new double[6];
+ fillDataPoint(loc, point);
+ pendingPoints.add(point);
}
- chartView.addDataPoints(readPointsToList(track));
- uiHandler.post(new Runnable() {
- public void run() {
- chartView.invalidate();
- }
- });
- Log.i(MyTracksConstants.TAG, "MyTracks: Updated chart last seen: " + lastSeenLocationId);
}
- /**
- * Get the frequency at which points should be displayed.
- * Limit the number of chart readings. Ideally we would want around 1024.
- * @param track The track which will be displayed.
- * @return The inverse of the frequency of points to be displayed.
- */
- private int getSamplingFrequency(Track track) {
- long totalLocations = track.getStopId() - track.getStartId();
- return Math.max(1, (int) (totalLocations / 1024.0));
+ @Override
+ public void onSampledOutTrackPoint(Location loc) {
+ // Still account for the point in the smoothing buffers.
+ fillDataPoint(loc, null);
}
- private Cursor getLocationsCursor(long lastLocationRead) {
- return providerUtils.getLocationsCursor(selectedTrackId, lastLocationRead, BUFFER_SIZE, false);
+ @Override
+ public void onSegmentSplit() {
+ // Do nothing.
}
- /**
- * Read all of the points to a list.
- * @param track The track which will be displayed.
- * @return
- */
- private ArrayList readPointsToList(Track track) {
- Cursor cursor = null;
- long lastLocationRead = lastSeenLocationId;
- int points = 0;
- int chartSamplingFrequency = getSamplingFrequency(track);
- ArrayList result = new ArrayList();
- // Need two locations so we can keep track of the last location.
- Location location = new MyTracksLocation("");
- try {
- while (lastSeenLocationId < track.getStopId()) {
- cursor = getLocationsCursor(lastLocationRead);
- if (cursor != null) {
- elevationBuffer.reset();
- speedBuffer.reset();
- if (cursor.moveToFirst()) {
- final int idColumnIdx = cursor.getColumnIndexOrThrow(TrackPointsColumns._ID);
- while (cursor.moveToNext()) {
- points++;
- providerUtils.fillLocation(cursor, location);
- if (MyTracksUtils.isValidLocation(location)) {
- lastLocationRead = lastSeenLocationId =
- cursor.getLong(idColumnIdx);
- // TODO Can we be smarter about choosing 3 or 6 entries?
- double[] point = new double[6];
- location = getDataPoint(location, track, point);
- if (points % chartSamplingFrequency == 0) {
- result.add(point);
- }
- }
- }
- } else {
- lastLocationRead += BUFFER_SIZE;
- }
- } else {
- lastLocationRead += BUFFER_SIZE;
- }
- cursor.close();
- cursor = null;
- }
- return result;
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
+ @Override
+ public void onNewTrackPointsDone() {
+ chartView.addDataPoints(pendingPoints);
+ pendingPoints.clear();
+ runOnUiThread(updateChart);
+ }
+
+ @Override
+ public void clearWaypoints() {
+ chartView.clearWaypoints();
+ }
+
+ @Override
+ public void onNewWaypoint(Waypoint wpt) {
+ chartView.addWaypoint(wpt);
+ }
+
+ @Override
+ public void onNewWaypointsDone() {
+ runOnUiThread(updateChart);
+ }
+
+ @Override
+ public boolean onUnitsChanged(boolean metric) {
+ this.metricUnits = metric;
+
+ chartView.setMetricUnits(metric);
+
+ return true; // Reload data
+ }
+
+ @Override
+ public boolean onReportSpeedChanged(boolean reportSpeed) {
+ this.reportSpeed = reportSpeed;
+
+ chartView.setReportSpeed(reportSpeed, this);
+
+ return true; // Reload data
}
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/ChartView.java b/MyTracks/src/com/google/android/apps/mytracks/ChartView.java
index 753a4a753..a3153d014 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/ChartView.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/ChartView.java
@@ -527,7 +527,7 @@ public class ChartView extends View {
}
if (nearestWaypoint != null && dmin < 100) {
Intent intent =
- new Intent(getContext(), MyTracksWaypointDetails.class);
+ new Intent(getContext(), WaypointDetails.class);
intent.putExtra("waypointid", nearestWaypoint.getId());
getContext().startActivity(intent);
return true;
diff --git a/MyTracks/src/com/google/android/apps/mytracks/CheckUnits.java b/MyTracks/src/com/google/android/apps/mytracks/CheckUnits.java
index d1fc56029..556ad8f7d 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/CheckUnits.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/CheckUnits.java
@@ -78,7 +78,7 @@ class CheckUnits {
private static void accept(Context context, SharedPreferences preferences) {
recordCheckPerformed(preferences);
- Intent startIntent = new Intent(context, MyTracksSettings.class);
+ Intent startIntent = new Intent(context, SettingsActivity.class);
context.startActivity(startIntent);
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracksConstants.java b/MyTracks/src/com/google/android/apps/mytracks/Constants.java
similarity index 76%
rename from MyTracks/src/com/google/android/apps/mytracks/MyTracksConstants.java
rename to MyTracks/src/com/google/android/apps/mytracks/Constants.java
index 083e3f35e..46a9db348 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracksConstants.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/Constants.java
@@ -20,7 +20,7 @@ package com.google.android.apps.mytracks;
*
* @author Leif Hendrik Wilden
*/
-public abstract class MyTracksConstants {
+public abstract class Constants {
/**
* Should be used by all log statements
@@ -140,6 +140,12 @@ public abstract class MyTracksConstants {
*/
public static final int MAX_LOADED_TRACK_POINTS = 20000;
+ /**
+ * Maximum number of track points ever loaded at once from the provider into
+ * memory in a single call to read points.
+ */
+ public static final int MAX_LOADED_TRACK_POINTS_PER_BATCH = 1000;
+
/**
* Maximum number of way points displayed by the map overlay.
*/
@@ -182,32 +188,32 @@ public abstract class MyTracksConstants {
public static int getActionFromMenuId(int menuId) {
switch (menuId) {
- case MyTracksConstants.MENU_SEND_TO_GOOGLE:
- return MyTracksConstants.SEND_TO_GOOGLE_DIALOG;
- case MyTracksConstants.MENU_EDIT:
- return MyTracksConstants.EDIT_DETAILS;
- case MyTracksConstants.MENU_DELETE:
- return MyTracksConstants.DELETE_TRACK;
- case MyTracksConstants.MENU_SHARE_LINK:
- return MyTracksConstants.SHARE_LINK;
- case MyTracksConstants.MENU_SHARE_KML_FILE:
- return MyTracksConstants.SHARE_KML_FILE;
- case MyTracksConstants.MENU_SHARE_GPX_FILE:
- return MyTracksConstants.SHARE_GPX_FILE;
- case MyTracksConstants.MENU_SHARE_CSV_FILE:
- return MyTracksConstants.SHARE_CSV_FILE;
- case MyTracksConstants.MENU_SHARE_TCX_FILE:
- return MyTracksConstants.SHARE_TCX_FILE;
- case MyTracksConstants.MENU_SAVE_GPX_FILE:
- return MyTracksConstants.SAVE_GPX_FILE;
- case MyTracksConstants.MENU_SAVE_KML_FILE:
- return MyTracksConstants.SAVE_KML_FILE;
- case MyTracksConstants.MENU_SAVE_CSV_FILE:
- return MyTracksConstants.SAVE_CSV_FILE;
- case MyTracksConstants.MENU_SAVE_TCX_FILE:
- return MyTracksConstants.SAVE_TCX_FILE;
- case MyTracksConstants.MENU_CLEAR_MAP:
- return MyTracksConstants.CLEAR_MAP;
+ case Constants.MENU_SEND_TO_GOOGLE:
+ return Constants.SEND_TO_GOOGLE_DIALOG;
+ case Constants.MENU_EDIT:
+ return Constants.EDIT_DETAILS;
+ case Constants.MENU_DELETE:
+ return Constants.DELETE_TRACK;
+ case Constants.MENU_SHARE_LINK:
+ return Constants.SHARE_LINK;
+ case Constants.MENU_SHARE_KML_FILE:
+ return Constants.SHARE_KML_FILE;
+ case Constants.MENU_SHARE_GPX_FILE:
+ return Constants.SHARE_GPX_FILE;
+ case Constants.MENU_SHARE_CSV_FILE:
+ return Constants.SHARE_CSV_FILE;
+ case Constants.MENU_SHARE_TCX_FILE:
+ return Constants.SHARE_TCX_FILE;
+ case Constants.MENU_SAVE_GPX_FILE:
+ return Constants.SAVE_GPX_FILE;
+ case Constants.MENU_SAVE_KML_FILE:
+ return Constants.SAVE_KML_FILE;
+ case Constants.MENU_SAVE_CSV_FILE:
+ return Constants.SAVE_CSV_FILE;
+ case Constants.MENU_SAVE_TCX_FILE:
+ return Constants.SAVE_TCX_FILE;
+ case Constants.MENU_CLEAR_MAP:
+ return Constants.CLEAR_MAP;
default:
return -1;
}
@@ -216,8 +222,22 @@ public abstract class MyTracksConstants {
public static final String MAPSHOP_BASE_URL =
"http://maps.google.com/maps/ms";
+ /*
+ * Default values - keep in sync with those in preferences.xml.
+ */
+
+ public static final int DEFAULT_ANNOUNCEMENT_FREQUENCY = -1;
+ public static final int DEFAULT_AUTO_RESUME_TRACK_TIMEOUT = 10; // In min.
+ public static final int DEFAULT_MAX_RECORDING_DISTANCE = 200;
+ public static final int DEFAULT_MIN_RECORDING_DISTANCE = 5;
+ public static final int DEFAULT_MIN_RECORDING_INTERVAL = 0;
+ public static final int DEFAULT_MIN_REQUIRED_ACCURACY = 200;
+ public static final int DEFAULT_SPLIT_FREQUENCY = 0;
+
+ public static final String SETTINGS_NAME = "SettingsActivity";
+
/**
* This is an abstract utility class.
*/
- protected MyTracksConstants() { }
+ protected Constants() { }
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracksDeleteAllTracks.java b/MyTracks/src/com/google/android/apps/mytracks/DeleteAllTracks.java
similarity index 90%
rename from MyTracks/src/com/google/android/apps/mytracks/MyTracksDeleteAllTracks.java
rename to MyTracks/src/com/google/android/apps/mytracks/DeleteAllTracks.java
index 1e939b144..13c1598ed 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracksDeleteAllTracks.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/DeleteAllTracks.java
@@ -34,12 +34,12 @@ import android.util.Log;
*
* @author Leif Hendrik Wilden
*/
-public class MyTracksDeleteAllTracks extends Handler {
+public class DeleteAllTracks extends Handler {
private final Context context;
private final Runnable done;
- public MyTracksDeleteAllTracks(Context context, Runnable done) {
+ public DeleteAllTracks(Context context, Runnable done) {
this.context = context;
this.done = done;
}
@@ -58,11 +58,12 @@ public class MyTracksDeleteAllTracks extends Handler {
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int i) {
dialog.dismiss();
- Log.w(MyTracksConstants.TAG, "deleting all!");
+ Log.w(Constants.TAG, "deleting all!");
MyTracksProviderUtils.Factory.get(context).deleteAllTracks();
SharedPreferences prefs =
- context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
+ context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
SharedPreferences.Editor editor = prefs.edit();
+ // TODO: Go through data manager
editor.putLong(context.getString(R.string.selected_track_key), -1);
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(editor);
if (done != null) {
diff --git a/MyTracks/src/com/google/android/apps/mytracks/DialogManager.java b/MyTracks/src/com/google/android/apps/mytracks/DialogManager.java
index 5dec3e5dd..57c107a97 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/DialogManager.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/DialogManager.java
@@ -15,6 +15,8 @@
*/
package com.google.android.apps.mytracks;
+import static com.google.android.apps.mytracks.Constants.TAG;
+
import com.google.android.apps.mytracks.io.sendtogoogle.SendDialog;
import com.google.android.maps.mytracks.R;
@@ -96,7 +98,7 @@ public class DialogManager {
activity.resetSendToGoogleStatus();
break;
case DIALOG_CHART_SETTINGS:
- Log.d(MyTracksConstants.TAG, "MyTracks.onPrepare chart dialog");
+ Log.d(TAG, "MyTracks.onPrepare chart dialog");
chartSettingsDialog.setup(activity.getChartActivity());
break;
}
@@ -170,11 +172,9 @@ public class DialogManager {
try {
activity.showDialog(id);
} catch (BadTokenException e) {
- Log.w(MyTracksConstants.TAG,
- "Could not display dialog with id " + id, e);
+ Log.w(TAG, "Could not display dialog with id " + id, e);
} catch (IllegalStateException e) {
- Log.w(MyTracksConstants.TAG,
- "Could not display dialog with id " + id, e);
+ Log.w(TAG, "Could not display dialog with id " + id, e);
}
}
});
@@ -190,9 +190,9 @@ public class DialogManager {
try {
dialog.show();
} catch (BadTokenException e) {
- Log.w(MyTracksConstants.TAG, "Could not display dialog", e);
+ Log.w(TAG, "Could not display dialog", e);
} catch (IllegalStateException e) {
- Log.w(MyTracksConstants.TAG, "Could not display dialog", e);
+ Log.w(TAG, "Could not display dialog", e);
}
}
});
diff --git a/MyTracks/src/com/google/android/apps/mytracks/Eula.java b/MyTracks/src/com/google/android/apps/mytracks/Eula.java
index aed5a40a0..c54926795 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/Eula.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/Eula.java
@@ -98,7 +98,7 @@ class Eula {
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
preferences.edit().putBoolean(PREFERENCE_EULA_ACCEPTED, true));
Intent startIntent = new Intent(activity, WelcomeActivity.class);
- activity.startActivityForResult(startIntent, MyTracksConstants.WELCOME);
+ activity.startActivityForResult(startIntent, Constants.WELCOME);
}
private static void refuse(Activity activity) {
diff --git a/MyTracks/src/com/google/android/apps/mytracks/ExportAllTracks.java b/MyTracks/src/com/google/android/apps/mytracks/ExportAllTracks.java
index 86c5bc9cf..8bad978c7 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/ExportAllTracks.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/ExportAllTracks.java
@@ -20,7 +20,7 @@ import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.io.TrackWriter;
import com.google.android.apps.mytracks.io.TrackWriterFactory;
import com.google.android.apps.mytracks.io.TrackWriterFactory.TrackFileFormat;
-import com.google.android.apps.mytracks.util.MyTracksUtils;
+import com.google.android.apps.mytracks.util.SystemUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
@@ -71,14 +71,14 @@ public class ExportAllTracks {
format = TrackFileFormat.TCX;
break;
default:
- Log.w(MyTracksConstants.TAG, "Unknown export format: " + which);
+ Log.w(Constants.TAG, "Unknown export format: " + which);
}
}
};
public ExportAllTracks(Activity activity) {
this.activity = activity;
- Log.i(MyTracksConstants.TAG, "ExportAllTracks: Starting");
+ Log.i(Constants.TAG, "ExportAllTracks: Starting");
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setSingleChoiceItems(R.array.export_formats, 0, itemClick);
@@ -113,14 +113,14 @@ public class ExportAllTracks {
*/
private void aquireLocksAndExport() {
SharedPreferences prefs =
- activity.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
+ activity.getSharedPreferences(Constants.SETTINGS_NAME, 0);
long recordingTrackId = -1;
if (prefs != null) {
recordingTrackId =
prefs.getLong(activity.getString(R.string.recording_track_key), -1);
}
if (recordingTrackId != -1) {
- wakeLock = MyTracksUtils.acquireWakeLock(activity, wakeLock);
+ wakeLock = SystemUtils.acquireWakeLock(activity, wakeLock);
}
// Now we can safely export everything.
@@ -130,9 +130,9 @@ public class ExportAllTracks {
// TODO check what happens if we started recording after getting this lock.
if (wakeLock != null && wakeLock.isHeld()) {
wakeLock.release();
- Log.i(MyTracksConstants.TAG, "ExportAllTracks: Releasing wake lock.");
+ Log.i(Constants.TAG, "ExportAllTracks: Releasing wake lock.");
}
- Log.i(MyTracksConstants.TAG, "ExportAllTracks: Done");
+ Log.i(Constants.TAG, "ExportAllTracks: Done");
Toast.makeText(activity, R.string.export_done, Toast.LENGTH_SHORT).show();
}
@@ -163,7 +163,7 @@ public class ExportAllTracks {
}
final int trackCount = cursor.getCount();
- Log.i(MyTracksConstants.TAG,
+ Log.i(Constants.TAG,
"ExportAllTracks: Exporting: " + cursor.getCount() + " tracks.");
int idxTrackId = cursor.getColumnIndexOrThrow(TracksColumns._ID);
activity.runOnUiThread(new Runnable() {
@@ -186,7 +186,7 @@ public class ExportAllTracks {
});
long id = cursor.getLong(idxTrackId);
- Log.i(MyTracksConstants.TAG, "ExportAllTracks: exporting: " + id);
+ Log.i(Constants.TAG, "ExportAllTracks: exporting: " + id);
TrackWriter writer =
TrackWriterFactory.newWriter(activity, providerUtils, id, format);
writer.writeTrack();
diff --git a/MyTracks/src/com/google/android/apps/mytracks/ImportAllTracks.java b/MyTracks/src/com/google/android/apps/mytracks/ImportAllTracks.java
index 799a91d5a..f64c372ab 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/ImportAllTracks.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/ImportAllTracks.java
@@ -18,7 +18,7 @@ package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.io.GpxImporter;
import com.google.android.apps.mytracks.util.FileUtils;
-import com.google.android.apps.mytracks.util.MyTracksUtils;
+import com.google.android.apps.mytracks.util.SystemUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
@@ -60,7 +60,7 @@ public class ImportAllTracks {
public ImportAllTracks(Activity activity) {
this.activity = activity;
- Log.i(MyTracksConstants.TAG, "ImportAllTracks: Starting");
+ Log.i(Constants.TAG, "ImportAllTracks: Starting");
fileUtils = new FileUtils();
gpxPath = fileUtils.buildExternalDirectoryPath("gpx");
HandlerThread handlerThread;
@@ -82,13 +82,13 @@ public class ImportAllTracks {
* track. Acquire a wake lock if there is no current track.
*/
private void aquireLocksAndImport() {
- SharedPreferences prefs = activity.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
+ SharedPreferences prefs = activity.getSharedPreferences(Constants.SETTINGS_NAME, 0);
long recordingTrackId = -1;
if (prefs != null) {
recordingTrackId = prefs.getLong(activity.getString(R.string.recording_track_key), -1);
}
if (recordingTrackId != -1) {
- wakeLock = MyTracksUtils.acquireWakeLock(activity, wakeLock);
+ wakeLock = SystemUtils.acquireWakeLock(activity, wakeLock);
}
// Now we can safely import everything.
@@ -98,10 +98,10 @@ public class ImportAllTracks {
// TODO check what happens if we started recording after getting this lock.
if (wakeLock != null && wakeLock.isHeld()) {
wakeLock.release();
- Log.i(MyTracksConstants.TAG, "ImportAllTracks: Releasing wake lock.");
+ Log.i(Constants.TAG, "ImportAllTracks: Releasing wake lock.");
}
- Log.i(MyTracksConstants.TAG, "ImportAllTracks: Done");
+ Log.i(Constants.TAG, "ImportAllTracks: Done");
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
if (gpxFileCount == 0) {
builder.setMessage(activity.getString(R.string.import_empty, gpxPath + "/"));
@@ -141,7 +141,7 @@ public class ImportAllTracks {
return;
}
- Log.i(MyTracksConstants.TAG, "ImportAllTracks: Importing: " + gpxFileCount + " tracks.");
+ Log.i(Constants.TAG, "ImportAllTracks: Importing: " + gpxFileCount + " tracks.");
activity.runOnUiThread(new Runnable() {
public void run() {
makeProgressDialog(gpxFileCount);
@@ -180,19 +180,19 @@ public class ImportAllTracks {
* notifications and returns false on failure.
*/
private boolean importFile(File gpxFile, MyTracksProviderUtils providerUtils) {
- Log.i(MyTracksConstants.TAG, "ImportAllTracks: importing: " + gpxFile.getName());
+ Log.i(Constants.TAG, "ImportAllTracks: importing: " + gpxFile.getName());
try {
GpxImporter.importGPXFile(new FileInputStream(gpxFile), providerUtils);
return true;
} catch (FileNotFoundException e) {
- Log.w(MyTracksConstants.TAG, "GPX file wasn't found/went missing: "
+ Log.w(Constants.TAG, "GPX file wasn't found/went missing: "
+ gpxFile.getAbsolutePath(), e);
} catch (ParserConfigurationException e) {
- Log.w(MyTracksConstants.TAG, "Error parsing file: " + gpxFile.getAbsolutePath(), e);
+ Log.w(Constants.TAG, "Error parsing file: " + gpxFile.getAbsolutePath(), e);
} catch (SAXException e) {
- Log.w(MyTracksConstants.TAG, "Error parsing file: " + gpxFile.getAbsolutePath(), e);
+ Log.w(Constants.TAG, "Error parsing file: " + gpxFile.getAbsolutePath(), e);
} catch (IOException e) {
- Log.w(MyTracksConstants.TAG, "Error reading file: " + gpxFile.getAbsolutePath(), e);
+ Log.w(Constants.TAG, "Error reading file: " + gpxFile.getAbsolutePath(), e);
}
Toast.makeText(activity, activity.getString(R.string.import_error, gpxFile.getName()),
Toast.LENGTH_LONG).show();
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MapActivity.java b/MyTracks/src/com/google/android/apps/mytracks/MapActivity.java
new file mode 100644
index 000000000..e3430bc80
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/MapActivity.java
@@ -0,0 +1,571 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.android.apps.mytracks;
+
+import static com.google.android.apps.mytracks.Constants.TAG;
+
+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.services.StatusAnnouncerFactory;
+import com.google.android.apps.mytracks.stats.TripStatistics;
+import com.google.android.apps.mytracks.util.ApiFeatures;
+import com.google.android.apps.mytracks.util.GeoRect;
+import com.google.android.apps.mytracks.util.LocationUtils;
+import com.google.android.maps.GeoPoint;
+import com.google.android.maps.MapController;
+import com.google.android.maps.MapView;
+import com.google.android.maps.mytracks.R;
+
+import android.content.Intent;
+import android.location.Location;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.SubMenu;
+import android.view.View;
+import android.view.View.OnCreateContextMenuListener;
+import android.view.Window;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+/**
+ * The map view activity of the MyTracks application.
+ *
+ * @author Leif Hendrik Wilden
+ * @author Rodrigo Damazio
+ */
+public class MapActivity extends com.google.android.maps.MapActivity
+ implements View.OnTouchListener, View.OnClickListener,
+ TrackDataListener {
+
+ // Saved instance state keys:
+ // ---------------------------
+
+ private static final String KEY_CURRENT_LOCATION = "currentLocation";
+ private static final String KEY_KEEP_MY_LOCATION_VISIBLE = "keepMyLocationVisible";
+
+ private TrackDataHub dataHub;
+
+ /**
+ * True if the map should be scrolled so that the pointer is always in the
+ * visible area.
+ */
+ private boolean keepMyLocationVisible;
+
+ /**
+ * The current pointer location.
+ * This is kept to quickly center on it when the user requests.
+ */
+ private Location currentLocation;
+
+ // UI elements:
+ // -------------
+
+ private RelativeLayout screen;
+ private MapView mapView;
+ private MapOverlay mapOverlay;
+ private LinearLayout messagePane;
+ private TextView messageText;
+ private LinearLayout busyPane;
+ private ImageButton optionsBtn;
+
+ private MenuItem myLocation;
+ private MenuItem toggleLayers;
+
+ /**
+ * We are not displaying driving directions. Just an arbitrary track that is
+ * not associated to any licensed mapping data. Therefore it should be okay to
+ * return false here and still comply with the terms of service.
+ */
+ @Override
+ protected boolean isRouteDisplayed() {
+ return false;
+ }
+
+ /**
+ * We are displaying a location. This needs to return true in order to comply
+ * with the terms of service.
+ */
+ @Override
+ protected boolean isLocationDisplayed() {
+ return true;
+ }
+
+ // Application life cycle:
+ // ------------------------
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ Log.d(TAG, "MapActivity.onCreate");
+ super.onCreate(bundle);
+
+ // The volume we want to control is the Text-To-Speech volume
+ int volumeStream =
+ new StatusAnnouncerFactory(ApiFeatures.getInstance()).getVolumeStream();
+ setVolumeControlStream(volumeStream);
+
+ dataHub = MyTracks.getInstance().getDataHub();
+
+ // We don't need a window title bar:
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+ // Inflate the layout:
+ setContentView(R.layout.mytracks_layout);
+
+ // Remove the window's background because the MapView will obscure it
+ getWindow().setBackgroundDrawable(null);
+
+ // Set up a map overlay:
+ screen = (RelativeLayout) findViewById(R.id.screen);
+ mapView = (MapView) findViewById(R.id.map);
+ mapView.requestFocus();
+ mapOverlay = new MapOverlay(this);
+ mapView.getOverlays().add(mapOverlay);
+ mapView.setOnTouchListener(this);
+ mapView.setBuiltInZoomControls(true);
+ messagePane = (LinearLayout) findViewById(R.id.messagepane);
+ messageText = (TextView) findViewById(R.id.messagetext);
+ busyPane = (LinearLayout) findViewById(R.id.busypane);
+ optionsBtn = (ImageButton) findViewById(R.id.showOptions);
+
+ optionsBtn.setOnCreateContextMenuListener(contextMenuListener);
+ optionsBtn.setOnClickListener(this);
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle bundle) {
+ Log.d(TAG, "MapActivity.onRestoreInstanceState");
+ if (bundle != null) {
+ super.onRestoreInstanceState(bundle);
+ keepMyLocationVisible =
+ bundle.getBoolean(KEY_KEEP_MY_LOCATION_VISIBLE, false);
+ if (bundle.containsKey(KEY_CURRENT_LOCATION)) {
+ currentLocation = (Location) bundle.getParcelable(KEY_CURRENT_LOCATION);
+ if (currentLocation != null) {
+ showCurrentLocation();
+ }
+ } else {
+ currentLocation = null;
+ }
+ }
+ }
+
+ @Override
+ protected void onStart() {
+ Log.d(TAG, "MapActivity.onStart");
+ super.onStart();
+
+ dataHub.registerTrackDataListener(this);
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ Log.d(TAG, "MapActivity.onSaveInstanceState");
+ outState.putBoolean(KEY_KEEP_MY_LOCATION_VISIBLE, keepMyLocationVisible);
+ if (currentLocation != null) {
+ outState.putParcelable(KEY_CURRENT_LOCATION, currentLocation);
+ }
+ super.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onStop() {
+ Log.d(TAG, "MapActivity.onStop");
+
+ dataHub.unregisterTrackDataListener(this);
+
+ super.onStop();
+ }
+
+ // Utility functions:
+ // -------------------
+
+ /**
+ * Shows the options button if a track is selected, or hide it if not.
+ */
+ private void updateOptionsButton(boolean trackSelected) {
+ optionsBtn.setVisibility(
+ trackSelected ? View.VISIBLE : View.INVISIBLE);
+ }
+
+ /**
+ * Tests if a location is visible.
+ *
+ * @param location a given location
+ * @return true if the given location is within the visible map area
+ */
+ private boolean locationIsVisible(Location location) {
+ if (location == null || mapView == null) {
+ return false;
+ }
+ GeoPoint center = mapView.getMapCenter();
+ int latSpan = mapView.getLatitudeSpan();
+ int lonSpan = mapView.getLongitudeSpan();
+
+ // Bottom of map view is obscured by zoom controls/buttons.
+ // Subtract a margin from the visible area:
+ GeoPoint marginBottom = mapView.getProjection().fromPixels(
+ 0, mapView.getHeight());
+ GeoPoint marginTop = mapView.getProjection().fromPixels(0,
+ mapView.getHeight()
+ - mapView.getZoomButtonsController().getZoomControls().getHeight());
+ int margin =
+ Math.abs(marginTop.getLatitudeE6() - marginBottom.getLatitudeE6());
+ GeoRect r = new GeoRect(center, latSpan, lonSpan);
+ r.top += margin;
+
+ GeoPoint geoPoint = LocationUtils.getGeoPoint(location);
+ return r.contains(geoPoint);
+ }
+
+ /**
+ * Moves the location pointer to the current location and center the map if
+ * the current location is outside the visible area.
+ */
+ private void showCurrentLocation() {
+ if (currentLocation == null || mapOverlay == null || mapView == null) {
+ return;
+ }
+ mapOverlay.setMyLocation(currentLocation);
+ mapView.postInvalidate();
+ if (keepMyLocationVisible && !locationIsVisible(currentLocation)) {
+ GeoPoint geoPoint = LocationUtils.getGeoPoint(currentLocation);
+ MapController controller = mapView.getController();
+ controller.animateTo(geoPoint);
+ }
+
+ }
+
+ @Override
+ public void onTrackUpdated(Track track) {
+ // We don't care.
+ }
+
+ /**
+ * Zooms and pans the map so that the given track is visible.
+ *
+ * @param track the track
+ */
+ private void zoomMapToBoundaries(Track track) {
+ if (mapView == null) {
+ return;
+ }
+
+ if (track == null || track.getNumberOfPoints() < 2) {
+ return;
+ }
+
+ TripStatistics stats = track.getStatistics();
+ int bottom = stats.getBottom();
+ int left = stats.getLeft();
+ int latSpanE6 = stats.getTop() - bottom;
+ int lonSpanE6 = stats.getRight() - left;
+ if (latSpanE6 > 0
+ && latSpanE6 < 180E6
+ && lonSpanE6 > 0
+ && lonSpanE6 < 360E6) {
+ keepMyLocationVisible = false;
+ GeoPoint center = new GeoPoint(
+ bottom + latSpanE6 / 2,
+ left + lonSpanE6 / 2);
+ if (LocationUtils.isValidGeoPoint(center)) {
+ mapView.getController().setCenter(center);
+ mapView.getController().zoomToSpan(latSpanE6, lonSpanE6);
+ }
+ }
+ }
+
+ /**
+ * Zooms and pans the map so that the given waypoint is visible.
+ */
+ public void showWaypoint(long waypointId) {
+ MyTracksProviderUtils providerUtils = MyTracksProviderUtils.Factory.get(this);
+ Waypoint wpt = providerUtils.getWaypoint(waypointId);
+ if (wpt != null && wpt.getLocation() != null) {
+ keepMyLocationVisible = false;
+ GeoPoint center = new GeoPoint(
+ (int) (wpt.getLocation().getLatitude() * 1E6),
+ (int) (wpt.getLocation().getLongitude() * 1E6));
+ mapView.getController().setCenter(center);
+ mapView.getController().setZoom(20);
+ mapView.invalidate();
+ }
+ }
+
+ @Override
+ public void onSelectedTrackChanged(final Track track, final boolean isRecording) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ boolean trackSelected = track != null;
+ updateOptionsButton(trackSelected);
+
+ mapOverlay.setTrackDrawingEnabled(trackSelected);
+
+ if (trackSelected) {
+ busyPane.setVisibility(View.VISIBLE);
+
+ zoomMapToBoundaries(track);
+
+ mapOverlay.setShowEndMarker(!isRecording);
+ busyPane.setVisibility(View.GONE);
+ }
+ mapView.invalidate();
+ }
+ });
+ }
+
+ private final OnCreateContextMenuListener contextMenuListener =
+ new OnCreateContextMenuListener() {
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v,
+ ContextMenuInfo menuInfo) {
+ menu.setHeaderTitle(R.string.tracklist_this_track);
+ menu.add(0, Constants.MENU_EDIT, 0,
+ R.string.tracklist_edit_track);
+ if (!dataHub.isRecordingSelected()) {
+ menu.add(0, Constants.MENU_SEND_TO_GOOGLE, 0,
+ R.string.tracklist_send_to_google);
+ SubMenu share = menu.addSubMenu(0, Constants.MENU_SHARE, 0,
+ R.string.tracklist_share_track);
+ share.add(0, Constants.MENU_SHARE_LINK, 0,
+ R.string.tracklist_share_link);
+ share.add(0, Constants.MENU_SHARE_GPX_FILE, 0,
+ R.string.tracklist_share_gpx_file);
+ share.add(0, Constants.MENU_SHARE_KML_FILE, 0,
+ R.string.tracklist_share_kml_file);
+ share.add(0, Constants.MENU_SHARE_CSV_FILE, 0,
+ R.string.tracklist_share_csv_file);
+ share.add(0, Constants.MENU_SHARE_TCX_FILE, 0,
+ R.string.tracklist_share_tcx_file);
+ SubMenu save = menu.addSubMenu(0,
+ Constants.MENU_WRITE_TO_SD_CARD, 0,
+ R.string.tracklist_write_to_sd);
+ save.add(0, Constants.MENU_SAVE_GPX_FILE, 0,
+ R.string.tracklist_save_as_gpx);
+ save.add(0, Constants.MENU_SAVE_KML_FILE, 0,
+ R.string.tracklist_save_as_kml);
+ save.add(0, Constants.MENU_SAVE_CSV_FILE, 0,
+ R.string.tracklist_save_as_csv);
+ save.add(0, Constants.MENU_SAVE_TCX_FILE, 0,
+ R.string.tracklist_save_as_tcx);
+ menu.add(0, Constants.MENU_CLEAR_MAP, 0,
+ R.string.tracklist_clear_map);
+ menu.add(0, Constants.MENU_DELETE, 0,
+ R.string.tracklist_delete_track);
+ }
+ }
+ };
+
+ @Override
+ public boolean onMenuItemSelected(int featureId, MenuItem item) {
+ if (!super.onMenuItemSelected(featureId, item)) {
+ MyTracks.getInstance().onActivityResult(
+ Constants.getActionFromMenuId(item.getItemId()), RESULT_OK,
+ new Intent());
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ myLocation = menu.add(0, Constants.MENU_MY_LOCATION, 0,
+ R.string.mylocation);
+ myLocation.setIcon(android.R.drawable.ic_menu_mylocation);
+ toggleLayers = menu.add(0, Constants.MENU_TOGGLE_LAYERS, 0,
+ R.string.switch_to_sat);
+ toggleLayers.setIcon(android.R.drawable.ic_menu_mapmode);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ toggleLayers.setTitle(mapView.isSatellite() ?
+ R.string.switch_to_map : R.string.switch_to_sat);
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case Constants.MENU_MY_LOCATION: {
+ dataHub.forceUpdateLocation();
+ keepMyLocationVisible = true;
+ if (mapView.getZoomLevel() < 18) {
+ mapView.getController().setZoom(18);
+ }
+ return true;
+ }
+ case Constants.MENU_TOGGLE_LAYERS: {
+ mapView.setSatellite(!mapView.isSatellite());
+ return true;
+ }
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == messagePane) {
+ startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
+ } else if (v == optionsBtn) {
+ optionsBtn.performLongClick();
+ }
+ }
+
+ /**
+ * We want the pointer to become visible again in case of the next location
+ * update:
+ */
+ @Override
+ public boolean onTouch(View view, MotionEvent event) {
+ if (keepMyLocationVisible && event.getAction() == MotionEvent.ACTION_MOVE) {
+ if (!locationIsVisible(currentLocation)) {
+ keepMyLocationVisible = false;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void onProviderStateChange(ProviderState state) {
+ final int messageId;
+ final boolean bindClick;
+ switch (state) {
+ case DISABLED:
+ messageId = R.string.status_enable_gps;
+ bindClick = true;
+ break;
+ case NO_FIX:
+ case BAD_FIX:
+ messageId = R.string.wait_for_fix;
+ bindClick = false;
+ break;
+ case GOOD_FIX:
+ // Nothing to show.
+ messageId = -1;
+ bindClick = false;
+ break;
+ default:
+ throw new IllegalArgumentException("Unexpected state: " + state);
+ }
+
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (messageId != -1) {
+ messageText.setText(messageId);
+ messagePane.setVisibility(View.VISIBLE);
+
+ if (bindClick) {
+ messagePane.setOnClickListener(MapActivity.this);
+ } else {
+ messagePane.setOnClickListener(null);
+ }
+ } else {
+ messagePane.setVisibility(View.GONE);
+ }
+
+ screen.requestLayout();
+ }
+ });
+ }
+
+ @Override
+ public void onCurrentLocationChanged(Location location) {
+ if (!location.getProvider().equals(Constants.GPS_PROVIDER)) {
+ Log.d(TAG,
+ "MapActivity: Network location update received (provider '" + location.getProvider() + "'.");
+ }
+
+ currentLocation = location;
+ showCurrentLocation();
+ }
+
+ @Override
+ public void onCurrentHeadingChanged(double heading) {
+ synchronized (this) {
+ if (mapOverlay.setHeading((float) heading)) {
+ mapView.postInvalidate();
+ }
+ }
+ }
+
+ @Override
+ public void clearWaypoints() {
+ mapOverlay.clearWaypoints();
+ }
+
+ @Override
+ public void onNewWaypoint(Waypoint waypoint) {
+ if (LocationUtils.isValidLocation(waypoint.getLocation())) {
+ // TODO: Optimize locking inside addWaypoint
+ mapOverlay.addWaypoint(waypoint);
+ }
+ }
+
+ @Override
+ public void onNewWaypointsDone() {
+ mapView.postInvalidate();
+ }
+
+ @Override
+ public void clearTrackPoints() {
+ mapOverlay.clearPoints();
+ }
+
+ @Override
+ public void onNewTrackPoint(Location loc) {
+ mapOverlay.addLocation(loc);
+ }
+
+ @Override
+ public void onSegmentSplit() {
+ mapOverlay.addSegmentSplit();
+ }
+
+ @Override
+ public void onSampledOutTrackPoint(Location loc) {
+ // We don't care.
+ }
+
+ @Override
+ public void onNewTrackPointsDone() {
+ mapView.postInvalidate();
+ }
+
+ @Override
+ public boolean onUnitsChanged(boolean metric) {
+ // We don't care.
+ return false;
+ }
+
+ @Override
+ public boolean onReportSpeedChanged(boolean reportSpeed) {
+ // We don't care.
+ return false;
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracksOverlay.java b/MyTracks/src/com/google/android/apps/mytracks/MapOverlay.java
similarity index 93%
rename from MyTracks/src/com/google/android/apps/mytracks/MyTracksOverlay.java
rename to MyTracks/src/com/google/android/apps/mytracks/MapOverlay.java
index 95abbc93b..c72abc5d2 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracksOverlay.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/MapOverlay.java
@@ -16,7 +16,7 @@
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.Waypoint;
-import com.google.android.apps.mytracks.util.MyTracksUtils;
+import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
@@ -45,7 +45,7 @@ import java.util.concurrent.BlockingQueue;
*
* @author Leif Hendrik Wilden
*/
-public class MyTracksOverlay extends Overlay {
+public class MapOverlay extends Overlay {
private final Drawable[] arrows;
private final int arrowWidth, arrowHeight;
@@ -79,20 +79,31 @@ public class MyTracksOverlay extends Overlay {
private static class CachedLocation {
public final boolean valid;
public final GeoPoint geoPoint;
-
+
+ /**
+ * Constructor for an invalid cached location.
+ */
+ public CachedLocation() {
+ this.valid = false;
+ this.geoPoint = null;
+ }
+
+ /**
+ * Constructor for a potentially valid cached location.
+ */
public CachedLocation(Location location) {
- this.valid = MyTracksUtils.isValidLocation(location);
- this.geoPoint = valid ? MyTracksUtils.getGeoPoint(location) : null;
+ this.valid = LocationUtils.isValidLocation(location);
+ this.geoPoint = valid ? LocationUtils.getGeoPoint(location) : null;
}
};
-
- public MyTracksOverlay(Context context) {
+
+ public MapOverlay(Context context) {
this.context = context;
this.waypoints = new ArrayList();
this.points = new ArrayList(1024);
this.pendingPoints = new ArrayBlockingQueue(
- MyTracksConstants.MAX_DISPLAYED_TRACK_POINTS, true);
+ Constants.MAX_DISPLAYED_TRACK_POINTS, true);
// TODO: Can we use a FrameAnimation or similar here rather
// than individual resources for each arrow direction?
@@ -164,6 +175,13 @@ public class MyTracksOverlay extends Overlay {
pendingPoints.offer(new CachedLocation(l));
}
+ /**
+ * Adds a segment split to the map overlay.
+ */
+ public void addSegmentSplit() {
+ pendingPoints.offer(new CachedLocation());
+ }
+
public void addWaypoint(Waypoint wpt) {
// Note: We don't cache waypoints, because it's not worth the effort.
if (wpt != null && wpt.getLocation() != null) {
@@ -172,7 +190,7 @@ public class MyTracksOverlay extends Overlay {
}
}
}
-
+
public int getNumLocations() {
synchronized (points) {
return points.size() + pendingPoints.size();
@@ -260,7 +278,7 @@ public class MyTracksOverlay extends Overlay {
synchronized (waypoints) {;
for (Waypoint wpt : waypoints) {
Location loc = wpt.getLocation();
- drawElement(canvas, projection, MyTracksUtils.getGeoPoint(loc),
+ drawElement(canvas, projection, LocationUtils.getGeoPoint(loc),
wpt.getType() == Waypoint.TYPE_STATISTICS ? statsMarker
: waypointMarker, -(markerWidth / 2) + 3, -markerHeight);
}
@@ -274,7 +292,7 @@ public class MyTracksOverlay extends Overlay {
}
Point pt = drawElement(canvas, projection,
- MyTracksUtils.getGeoPoint(myLocation), arrows[lastHeading],
+ LocationUtils.getGeoPoint(myLocation), arrows[lastHeading],
-(arrowWidth / 2) + 3, -(arrowHeight / 2));
// Draw the error circle.
float radius = projection.metersToEquatorPixels(myLocation.getAccuracy());
@@ -423,7 +441,7 @@ public class MyTracksOverlay extends Overlay {
return false;
}
- final Location tapLocation = MyTracksUtils.getLocation(p);
+ final Location tapLocation = LocationUtils.getLocation(p);
double dmin = Double.MAX_VALUE;
Waypoint waypoint = null;
synchronized (waypoints) {
@@ -442,7 +460,7 @@ public class MyTracksOverlay extends Overlay {
if (waypoint != null &&
dmin < 15000000 / Math.pow(2, mapView.getZoomLevel())) {
- Intent intent = new Intent(context, MyTracksWaypointDetails.class);
+ Intent intent = new Intent(context, WaypointDetails.class);
intent.putExtra("waypointid", waypoint.getId());
context.startActivity(intent);
return true;
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MenuManager.java b/MyTracks/src/com/google/android/apps/mytracks/MenuManager.java
index ded2aae1b..97ef2adae 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MenuManager.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/MenuManager.java
@@ -64,21 +64,21 @@ class MenuManager {
return true;
}
case R.id.menu_list_tracks: {
- activity.startActivityForResult(new Intent(activity, MyTracksList.class),
- MyTracksConstants.SHOW_TRACK);
+ activity.startActivityForResult(new Intent(activity, TrackList.class),
+ Constants.SHOW_TRACK);
return true;
}
case R.id.menu_list_markers: {
- Intent startIntent = new Intent(activity, MyTracksWaypointsList.class);
+ Intent startIntent = new Intent(activity, WaypointsList.class);
startIntent.putExtra("trackid", activity.getSelectedTrackId());
- activity.startActivityForResult(startIntent, MyTracksConstants.SHOW_WAYPOINT);
+ activity.startActivityForResult(startIntent, Constants.SHOW_WAYPOINT);
return true;
}
case R.id.menu_sensor_state: {
return startActivity(SensorStateActivity.class);
}
case R.id.menu_settings: {
- return startActivity(MyTracksSettings.class);
+ return startActivity(SettingsActivity.class);
}
case R.id.menu_aggregated_stats: {
return startActivity(AggregatedStatsActivity.class);
@@ -86,8 +86,8 @@ class MenuManager {
case R.id.menu_help: {
return startActivity(WelcomeActivity.class);
}
- case MyTracksConstants.MENU_CLEAR_MAP: {
- activity.setSelectedTrackId(-1);
+ case Constants.MENU_CLEAR_MAP: {
+ activity.clearSelectedTrack();
return true;
}
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java b/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java
index 64db86daf..106e9429c 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java
@@ -15,6 +15,7 @@
*/
package com.google.android.apps.mytracks;
+import static com.google.android.apps.mytracks.Constants.TAG;
import static com.google.android.apps.mytracks.DialogManager.DIALOG_IMPORT_PROGRESS;
import static com.google.android.apps.mytracks.DialogManager.DIALOG_PROGRESS;
import static com.google.android.apps.mytracks.DialogManager.DIALOG_SEND_TO_GOOGLE;
@@ -46,7 +47,7 @@ import com.google.android.apps.mytracks.services.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.services.TrackRecordingService;
import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.apps.mytracks.util.FileUtils;
-import com.google.android.apps.mytracks.util.MyTracksUtils;
+import com.google.android.apps.mytracks.util.SystemUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
@@ -54,15 +55,11 @@ import android.app.AlertDialog;
import android.app.Dialog;
import android.app.TabActivity;
import android.content.ComponentName;
-import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Resources;
-import android.location.Location;
-import android.location.LocationManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -100,12 +97,13 @@ import org.xml.sax.SAXException;
* @author Leif Hendrik Wilden
*/
public class MyTracks extends TabActivity implements OnTouchListener,
- OnSharedPreferenceChangeListener, ProgressIndicator {
+ ProgressIndicator {
/**
* Singleton instance
*/
private static MyTracks instance;
+ private TrackDataHub dataHub;
private ChartActivity chartActivity;
/*
@@ -149,16 +147,6 @@ public class MyTracks extends TabActivity implements OnTouchListener,
private ITrackRecordingService trackRecordingService;
- /**
- * The id of the currently recording track.
- */
- private long recordingTrackId = -1;
-
- /**
- * The id of the currently selected track.
- */
- private long selectedTrackId = -1;
-
/**
* Does the user want to share the current track.
*/
@@ -177,7 +165,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
private final ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
- Log.d(MyTracksConstants.TAG, "MyTracks: Service now connected.");
+ Log.d(Constants.TAG, "MyTracks: Service now connected.");
// Delay setting the service until we are done with initialization.
ITrackRecordingService trackRecordingService =
ITrackRecordingService.Stub.asInterface(service);
@@ -195,7 +183,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
@Override
public void onServiceDisconnected(ComponentName className) {
- Log.d(MyTracksConstants.TAG, "MyTracks: Service now disconnected.");
+ Log.d(TAG, "MyTracks: Service now disconnected.");
trackRecordingService = null;
}
};
@@ -233,26 +221,20 @@ public class MyTracks extends TabActivity implements OnTouchListener,
public boolean isRecording() {
if (trackRecordingService == null) {
// Fall back to alternative check method.
- return isRecordingBasedOnSharedPreferences();
+ return dataHub.isRecording();
}
try {
return trackRecordingService.isRecording();
// TODO: We catch Exception, because after eliminating the service process
// all exceptions it may throw are no longer wrapped in a RemoteException.
} catch (Exception e) {
- Log.e(MyTracksConstants.TAG, "MyTracks: Remote exception.", e);
+ Log.e(TAG, "MyTracks: Remote exception.", e);
// Fall back to alternative check method.
- return isRecordingBasedOnSharedPreferences();
+ return dataHub.isRecording();
}
}
- private boolean isRecordingBasedOnSharedPreferences() {
- // TrackRecordingService guarantees that recordingTrackId is set to
- // -1 if the track has been stopped.
- return recordingTrackId >= 0;
- }
-
/*
* Application lifetime events:
* ============================
@@ -260,17 +242,18 @@ public class MyTracks extends TabActivity implements OnTouchListener,
@Override
protected void onCreate(Bundle savedInstanceState) {
- Log.d(MyTracksConstants.TAG, "MyTracks.onCreate");
+ Log.d(TAG, "MyTracks.onCreate");
super.onCreate(savedInstanceState);
instance = this;
ApiFeatures apiFeatures = ApiFeatures.getInstance();
- if (!MyTracksUtils.isRelease(this)) {
+ if (!SystemUtils.isRelease(this)) {
apiFeatures.getApiPlatformAdapter().enableStrictMode();
}
providerUtils = MyTracksProviderUtils.Factory.get(this);
+ dataHub = new TrackDataHub(this, providerUtils);
menuManager = new MenuManager(this);
- sharedPreferences = getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
+ sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
dialogManager = new DialogManager(this);
// The volume we want to control is the Text-To-Speech volume
@@ -286,7 +269,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
tabHost.addTab(tabHost.newTabSpec("tab1")
.setIndicator("Map", res.getDrawable(
android.R.drawable.ic_menu_mapmode))
- .setContent(new Intent(this, MyTracksMap.class)));
+ .setContent(new Intent(this, MapActivity.class)));
tabHost.addTab(tabHost.newTabSpec("tab2")
.setIndicator("Stats", res.getDrawable(R.drawable.menu_stats))
.setContent(new Intent(this, StatsActivity.class)));
@@ -311,20 +294,6 @@ public class MyTracks extends TabActivity implements OnTouchListener,
tabHost.addView(layout);
layout.setOnTouchListener(this);
- if (sharedPreferences != null) {
- selectedTrackId =
- 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.
Eula.showEulaRequireAcceptance(this);
@@ -336,35 +305,45 @@ public class MyTracks extends TabActivity implements OnTouchListener,
// Do nothing.
} else if (action.equals(Intent.ACTION_VIEW)) {
if (intent.getScheme() != null && intent.getScheme().equals("file")) {
- Log.w(MyTracksConstants.TAG,
- "Received a VIEW intent with file scheme. Importing.");
+ Log.w(TAG, "Received a VIEW intent with file scheme. Importing.");
importGpxFile(intent.getData().getPath());
} else {
- Log.w(MyTracksConstants.TAG,
- "Received a VIEW intent with unsupported scheme "
- + intent.getScheme());
+ Log.w(TAG, "Received a VIEW intent with unsupported scheme " + intent.getScheme());
}
} else {
- Log.w(MyTracksConstants.TAG,
- "Received an intent with unsupported action " + action);
+ Log.w(TAG, "Received an intent with unsupported action " + action);
}
} else {
- Log.d(MyTracksConstants.TAG, "Received an intent with no action.");
+ Log.d(TAG, "Received an intent with no action.");
}
}
@Override
protected void onDestroy() {
- Log.d(MyTracksConstants.TAG, "MyTracks.onDestroy");
+ Log.d(TAG, "MyTracks.onDestroy");
+
+ dataHub.destroy();
+
tryUnbindTrackRecordingService();
super.onDestroy();
}
+ @Override
+ protected void onStop() {
+ Log.d(TAG, "MyTracks.onStop");
+
+ dataHub.stop();
+
+ // Clean up any temporary track files.
+ TempFileCleaner.clean();
+ super.onStop();
+ }
+
@Override
protected void onPause() {
// Called when activity is going into the background, but has not (yet) been
// killed. Shouldn't block longer than approx. 2 seconds.
- Log.d(MyTracksConstants.TAG, "MyTracks.onPause");
+ Log.d(TAG, "MyTracks.onPause");
tryUnbindTrackRecordingService();
super.onPause();
}
@@ -373,17 +352,16 @@ public class MyTracks extends TabActivity implements OnTouchListener,
protected void onResume() {
// Called when the current activity is being displayed or re-displayed
// to the user.
- Log.d(MyTracksConstants.TAG, "MyTracks.onResume");
+ Log.d(TAG, "MyTracks.onResume");
tryBindTrackRecordingService();
super.onResume();
}
@Override
- protected void onStop() {
- Log.d(MyTracksConstants.TAG, "MyTracks.onStop");
- // Clean up any temporary track files.
- TempFileCleaner.clean();
- super.onStop();
+ protected void onStart() {
+ Log.d(TAG, "MyTracks.onStart");
+ super.onStart();
+ dataHub.start();
}
/*
@@ -400,7 +378,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
menuManager.onPrepareOptionsMenu(menu, providerUtils.getLastTrack() != null,
- isRecording(), selectedTrackId >= 0);
+ isRecording(), dataHub.isATrackSelected());
return super.onPrepareOptionsMenu(menu);
}
@@ -444,9 +422,9 @@ public class MyTracks extends TabActivity implements OnTouchListener,
try {
insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS);
} catch (RemoteException e) {
- Log.e(MyTracksConstants.TAG, "Cannot insert statistics marker.", e);
+ Log.e(TAG, "Cannot insert statistics marker.", e);
} catch (IllegalStateException e) {
- Log.e(MyTracksConstants.TAG, "Cannot insert statistics marker.", e);
+ Log.e(TAG, "Cannot insert statistics marker.", e);
}
return true;
}
@@ -458,33 +436,34 @@ public class MyTracks extends TabActivity implements OnTouchListener,
public void onActivityResult(int requestCode, int resultCode,
final Intent results) {
TrackFileFormat exportFormat = null;
+ final long trackId = results.getLongExtra("trackid", dataHub.getSelectedTrackId());
switch (requestCode) {
- case MyTracksConstants.GET_LOGIN: {
+ case Constants.GET_LOGIN: {
if (resultCode != RESULT_OK || auth == null || !auth.authResult(resultCode, results)) {
dialogManager.dismissDialogSafely(DIALOG_PROGRESS);
}
break;
}
- case MyTracksConstants.SHOW_TRACK: {
+ case Constants.SHOW_TRACK: {
if (results != null) {
- final long trackId = results.getLongExtra("trackid", -1);
if (trackId >= 0) {
- setSelectedTrackId(trackId);
+ dataHub.loadTrack(trackId);
+
// The track list passed the requested action as result code. Hand
// it off to the onAcitivtyResult for further processing:
- if (resultCode != MyTracksConstants.SHOW_TRACK) {
+ if (resultCode != Constants.SHOW_TRACK) {
onActivityResult(resultCode, Activity.RESULT_OK, results);
}
}
}
break;
}
- case MyTracksConstants.SHOW_WAYPOINT: {
+ case Constants.SHOW_WAYPOINT: {
if (results != null) {
final long waypointId = results.getLongExtra("waypointid", -1);
if (waypointId >= 0) {
- MyTracksMap map =
- (MyTracksMap) getLocalActivityManager().getActivity("tab1");
+ MapActivity map =
+ (MapActivity) getLocalActivityManager().getActivity("tab1");
if (map != null) {
getTabHost().setCurrentTab(0);
map.showWaypoint(waypointId);
@@ -493,31 +472,29 @@ public class MyTracks extends TabActivity implements OnTouchListener,
}
break;
}
- case MyTracksConstants.DELETE_TRACK: {
+ case Constants.DELETE_TRACK: {
if (results != null && resultCode == RESULT_OK) {
- final long trackId = results.getLongExtra("trackid", selectedTrackId);
deleteTrack(trackId);
}
break;
}
- case MyTracksConstants.EDIT_DETAILS: {
+ case Constants.EDIT_DETAILS: {
if (results != null && resultCode == RESULT_OK) {
- final long trackId = results.getLongExtra("trackid", selectedTrackId);
- Intent intent = new Intent(this, MyTracksDetails.class);
+ Intent intent = new Intent(this, TrackDetails.class);
intent.putExtra("trackid", trackId);
startActivity(intent);
}
break;
}
- case MyTracksConstants.SEND_TO_GOOGLE_DIALOG: {
+ case Constants.SEND_TO_GOOGLE_DIALOG: {
shareRequested = false;
dialogManager.showDialogSafely(DIALOG_SEND_TO_GOOGLE);
break;
}
- case MyTracksConstants.GET_MAP: {
+ case Constants.GET_MAP: {
// User picked a map to upload to
if (resultCode == RESULT_OK) {
- results.putExtra("trackid", selectedTrackId);
+ results.putExtra("trackid", dataHub.getSelectedTrackId());
if (results.hasExtra("mapid")) {
sendToMyMapsMapId = results.getStringExtra("mapid");
}
@@ -527,21 +504,15 @@ public class MyTracks extends TabActivity implements OnTouchListener,
}
break;
}
- case MyTracksConstants.AUTHENTICATE_TO_MY_MAPS: {
+ case Constants.AUTHENTICATE_TO_MY_MAPS: {
// Authenticated with Google My Maps
if (results != null && resultCode == RESULT_OK) {
final String mapId;
- final long trackId;
if (results.hasExtra("mapid")) {
mapId = results.getStringExtra("mapid");
} else {
mapId = "new";
}
- if (results.hasExtra("trackid")) {
- trackId = results.getLongExtra("trackid", -1);
- } else {
- trackId = selectedTrackId;
- }
sendToGoogleMaps(trackId, mapId);
} else {
@@ -549,23 +520,16 @@ public class MyTracks extends TabActivity implements OnTouchListener,
}
break;
}
- case MyTracksConstants.AUTHENTICATE_TO_FUSION_TABLES: {
+ case Constants.AUTHENTICATE_TO_FUSION_TABLES: {
// Authenticated with Google Fusion Tables
if (results != null && resultCode == RESULT_OK) {
- final long trackId;
- if (results.hasExtra("trackid")) {
- trackId = results.getLongExtra("trackid", -1);
- } else {
- trackId = selectedTrackId;
- }
-
sendToFusionTables(trackId);
} else {
onSendToGoogleDone();
}
break;
}
- case MyTracksConstants.AUTHENTICATE_TO_DOCLIST: {
+ case Constants.AUTHENTICATE_TO_DOCLIST: {
// Authenticated with Google Docs
if (resultCode == RESULT_OK) {
authenticateToGoogleTrix();
@@ -574,42 +538,40 @@ public class MyTracks extends TabActivity implements OnTouchListener,
}
break;
}
- case MyTracksConstants.AUTHENTICATE_TO_TRIX: {
+ case Constants.AUTHENTICATE_TO_TRIX: {
// Authenticated with Trix
if (resultCode == RESULT_OK) {
- final long trackId = results.getLongExtra("trackid", selectedTrackId);
sendToGoogleDocs(trackId);
} else {
onSendToGoogleDone();
}
break;
}
- case MyTracksConstants.SAVE_GPX_FILE:
+ case Constants.SAVE_GPX_FILE:
if (exportFormat == null) { exportFormat = TrackFileFormat.GPX; }
//$FALL-THROUGH$
- case MyTracksConstants.SAVE_KML_FILE:
+ case Constants.SAVE_KML_FILE:
if (exportFormat == null) { exportFormat = TrackFileFormat.KML; }
//$FALL-THROUGH$
- case MyTracksConstants.SAVE_CSV_FILE:
+ case Constants.SAVE_CSV_FILE:
if (exportFormat == null) { exportFormat = TrackFileFormat.CSV; }
//$FALL-THROUGH$
- case MyTracksConstants.SAVE_TCX_FILE:
+ case Constants.SAVE_TCX_FILE:
if (exportFormat == null) { exportFormat = TrackFileFormat.TCX; }
if (results != null && resultCode == Activity.RESULT_OK) {
- final long trackId = results.getLongExtra("trackid", selectedTrackId);
if (trackId >= 0) {
saveTrack(trackId, exportFormat);
}
}
break;
- case MyTracksConstants.SHARE_LINK: {
- Track selectedTrack = providerUtils.getTrack(selectedTrackId);
+ case Constants.SHARE_LINK: {
+ Track selectedTrack = providerUtils.getTrack(dataHub.getSelectedTrackId());
if (selectedTrack != null) {
if (!TextUtils.isEmpty(selectedTrack.getMapId())) {
shareLinkToMap(MapsFacade.buildMapUrl(selectedTrack.getMapId()));
} else if (!TextUtils.isEmpty(selectedTrack.getTableId())) {
- shareLinkToMap(getFusionTablesUrl(selectedTrackId));
+ shareLinkToMap(getFusionTablesUrl(dataHub.getSelectedTrackId()));
} else {
shareRequested = true;
dialogManager.showDialogSafely(DIALOG_SEND_TO_GOOGLE);
@@ -617,38 +579,36 @@ public class MyTracks extends TabActivity implements OnTouchListener,
}
break;
}
- case MyTracksConstants.SHARE_GPX_FILE:
+ case Constants.SHARE_GPX_FILE:
if (exportFormat == null) { exportFormat = TrackFileFormat.GPX; }
//$FALL-THROUGH$
- case MyTracksConstants.SHARE_KML_FILE:
+ case Constants.SHARE_KML_FILE:
if (exportFormat == null) { exportFormat = TrackFileFormat.KML; }
//$FALL-THROUGH$
- case MyTracksConstants.SHARE_CSV_FILE:
+ case Constants.SHARE_CSV_FILE:
if (exportFormat == null) { exportFormat = TrackFileFormat.CSV; }
//$FALL-THROUGH$
- case MyTracksConstants.SHARE_TCX_FILE: {
+ case Constants.SHARE_TCX_FILE: {
if (exportFormat == null) { exportFormat = TrackFileFormat.TCX; }
if (results != null && resultCode == Activity.RESULT_OK) {
- final long trackId = results.getLongExtra("trackid", selectedTrackId);
if (trackId >= 0) {
sendTrack(trackId, exportFormat);
}
}
break;
}
- case MyTracksConstants.CLEAR_MAP: {
- setSelectedTrackId(-1);
+ case Constants.CLEAR_MAP: {
+ dataHub.unloadCurrentTrack();
break;
}
- case MyTracksConstants.WELCOME: {
+ case Constants.WELCOME: {
CheckUnits.check(this);
break;
}
default: {
- Log.w(MyTracksConstants.TAG,
- "Warning unhandled request code: " + requestCode);
+ Log.w(TAG, "Warning unhandled request code: " + requestCode);
}
}
}
@@ -661,19 +621,6 @@ public class MyTracks extends TabActivity implements OnTouchListener,
return false;
}
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
- String key) {
- if (key != null && key.equals(getString(R.string.selected_track_key))) {
- selectedTrackId = sharedPreferences.getLong(
- getString(R.string.selected_track_key), -1);
- }
- if (key != null && key.equals(getString(R.string.recording_track_key))) {
- recordingTrackId = sharedPreferences.getLong(
- getString(R.string.recording_track_key), -1);
- }
- }
-
/**
* Resets status information for sending to MyMaps/Docs.
*/
@@ -702,24 +649,24 @@ public class MyTracks extends TabActivity implements OnTouchListener,
InputStream is = new FileInputStream(fileName);
trackIdsImported = GpxImporter.importGPXFile(is, providerUtils);
} catch (SAXException e) {
- Log.e(MyTracksConstants.TAG, "Caught an unexpected exception.", e);
+ Log.e(TAG, "Caught an unexpected exception.", e);
message = R.string.error_generic;
} catch (ParserConfigurationException e) {
- Log.e(MyTracksConstants.TAG, "Caught an unexpected exception.", e);
+ Log.e(TAG, "Caught an unexpected exception.", e);
message = R.string.error_generic;
} catch (IOException e) {
- Log.e(MyTracksConstants.TAG, "Caught an unexpected exception.", e);
+ Log.e(TAG, "Caught an unexpected exception.", e);
message = R.string.error_unable_to_read_file;
} catch (NullPointerException e) {
- Log.e(MyTracksConstants.TAG, "Caught an unexpected exception.", e);
+ Log.e(TAG, "Caught an unexpected exception.", e);
message = R.string.error_invalid_gpx_format;
} catch (OutOfMemoryError e) {
- Log.e(MyTracksConstants.TAG, "Caught an unexpected exception.", e);
+ Log.e(TAG, "Caught an unexpected exception.", e);
message = R.string.error_out_of_memory;
}
if (trackIdsImported != null && trackIdsImported.length > 0) {
// select last track from import file
- setSelectedTrackId(trackIdsImported[trackIdsImported.length - 1]);
+ dataHub.loadTrack(trackIdsImported[trackIdsImported.length - 1]);
} else {
dialogManager.showMessageDialog(message, false/* success */);
}
@@ -791,8 +738,8 @@ public class MyTracks extends TabActivity implements OnTouchListener,
public void onClick(DialogInterface dialog, int i) {
dialog.dismiss();
providerUtils.deleteTrack(trackId);
- if (trackId == selectedTrackId) {
- setSelectedTrackId(-1);
+ if (trackId == dataHub.getSelectedTrackId()) {
+ dataHub.unloadCurrentTrack();
}
}});
builder.setNegativeButton(getString(R.string.no),
@@ -805,46 +752,6 @@ public class MyTracks extends TabActivity implements OnTouchListener,
dialog.show();
}
- public Location getCurrentLocation() {
- // TODO: Let's look at more advanced algorithms to determine the best
- // current location.
- LocationManager locationManager =
- (LocationManager) getSystemService(Context.LOCATION_SERVICE);
- if (locationManager == null) {
- return null;
- }
- final long maxAgeMilliSeconds = 1000 * 60 * 1; // 1 minute
- final long maxAgeNetworkMilliSeconds = 1000 * 60 * 10; // 10 minutes
- final long now = System.currentTimeMillis();
- Location loc = locationManager.getLastKnownLocation(
- MyTracksConstants.GPS_PROVIDER);
- if (loc == null || loc.getTime() < now - maxAgeMilliSeconds) {
- // We don't have a recent GPS fix, just use cell towers if available
- loc = locationManager.getLastKnownLocation(
- LocationManager.NETWORK_PROVIDER);
- if (loc == null || loc.getTime() < now - maxAgeNetworkMilliSeconds) {
- // We don't have a recent cell tower location, let the user know:
- Toast.makeText(this, getString(R.string.status_no_location),
- Toast.LENGTH_LONG).show();
- return null;
- } else {
- // Let the user know we have only an approximate location:
- Toast.makeText(this, getString(R.string.status_approximate_location),
- Toast.LENGTH_LONG).show();
- }
- }
- return loc;
- }
-
- public Location getLastLocation() {
- if (providerUtils.getLastLocationId(recordingTrackId) < 0) {
- return null;
- }
- LocationManager locationManager =
- (LocationManager) getSystemService(Context.LOCATION_SERVICE);
- return locationManager.getLastKnownLocation(MyTracksConstants.GPS_PROVIDER);
- }
-
/**
* Inserts a waypoint marker.
*
@@ -877,16 +784,15 @@ public class MyTracks extends TabActivity implements OnTouchListener,
final String service) {
auth = authMap.get(service);
if (auth == null) {
- Log.i(MyTracksConstants.TAG,
- "Creating a new authentication for service: " + service);
+ Log.i(TAG, "Creating a new authentication for service: " + service);
auth = AuthManagerFactory.getAuthManager(this,
- MyTracksConstants.GET_LOGIN,
+ Constants.GET_LOGIN,
null,
true,
service);
authMap.put(service, auth);
}
- Log.d(MyTracksConstants.TAG, "Logging in to " + service + "...");
+ Log.d(TAG, "Logging in to " + service + "...");
if (AuthManagerFactory.useModernAuthManager()) {
runOnUiThread(new Runnable() {
@Override
@@ -913,7 +819,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
final String service, final Account account) {
auth.doLogin(new Runnable() {
public void run() {
- Log.d(MyTracksConstants.TAG, "Loggin success for " + service + "!");
+ Log.d(TAG, "Loggin success for " + service + "!");
onActivityResult(requestCode, RESULT_OK, results);
}
}, account);
@@ -922,9 +828,9 @@ public class MyTracks extends TabActivity implements OnTouchListener,
private void startRecordingNewTrack(
ITrackRecordingService trackRecordingService) {
try {
- recordingTrackId = trackRecordingService.startNewTrack();
+ long recordingTrackId = trackRecordingService.startNewTrack();
// Select the recording track.
- setSelectedTrackId(recordingTrackId);
+ dataHub.loadTrack(recordingTrackId);
Toast.makeText(this, getString(R.string.status_now_recording),
Toast.LENGTH_SHORT).show();
// TODO: We catch Exception, because after eliminating the service process
@@ -933,7 +839,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
Toast.makeText(this,
getString(R.string.error_unable_to_start_recording),
Toast.LENGTH_SHORT).show();
- Log.w(MyTracksConstants.TAG, "Unable to start recording.", e);
+ Log.w(TAG, "Unable to start recording.", e);
}
}
@@ -959,25 +865,27 @@ public class MyTracks extends TabActivity implements OnTouchListener,
public void stopRecording() {
if (trackRecordingService != null) {
// Save the track id as the shared preference will overwrite the recording track id.
- long currentTrackId = recordingTrackId;
+ long currentTrackId = sharedPreferences.getLong(getString(R.string.recording_track_key), -1);
try {
trackRecordingService.endCurrentTrack();
// TODO: We catch Exception, because after eliminating the service process
// all exceptions it may throw are no longer wrapped in a RemoteException.
} catch (Exception e) {
- Log.e(MyTracksConstants.TAG, "Unable to stop recording.", e);
+ Log.e(TAG, "Unable to stop recording.", e);
+ }
+
+ if (currentTrackId > 0) {
+ Intent intent = new Intent(MyTracks.this, TrackDetails.class);
+ intent.putExtra("trackid", currentTrackId);
+ intent.putExtra("hasCancelButton", false);
+ startActivity(intent);
}
- Intent intent = new Intent(MyTracks.this, MyTracksDetails.class);
- intent.putExtra("trackid", currentTrackId);
- intent.putExtra("hasCancelButton", false);
- startActivity(intent);
}
tryUnbindTrackRecordingService();
try {
stopService(new Intent(MyTracks.this, TrackRecordingService.class));
} catch (SecurityException e) {
- Log.e(MyTracksConstants.TAG,
- "Encountered a security exception when trying to stop service.", e);
+ Log.e(TAG, "Encountered a security exception when trying to stop service.", e);
}
trackRecordingService = null;
}
@@ -986,7 +894,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
* Initiates the process to send tracks to google.
* This is called once the user has selected sending options via the
* SendToGoogleDialog.
- *
+ *
* TODO: Change this whole flow to an actual state machine.
*/
public void sendToGoogle() {
@@ -1006,7 +914,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
} else if (sendToGoogleDialog.getSendToDocs()) {
authenticateToGoogleDocs();
} else {
- Log.w(MyTracksConstants.TAG, "Nowhere to upload to");
+ Log.w(TAG, "Nowhere to upload to");
onSendToGoogleDone();
}
}
@@ -1015,7 +923,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
if (!sendToGoogleDialog.getCreateNewMap()) {
// Ask the user to choose a map to upload into
Intent listIntent = new Intent(this, MyMapsList.class);
- startActivityForResult(listIntent, MyTracksConstants.GET_MAP);
+ startActivityForResult(listIntent, Constants.GET_MAP);
// The callback for GET_MAP calls authenticateToGoogleMaps
} else {
authenticateToGoogleMaps(null);
@@ -1028,7 +936,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
setProgressValue(0);
setProgressMessage(
R.string.progress_message_authenticating_mymaps);
- authenticate(results, MyTracksConstants.AUTHENTICATE_TO_MY_MAPS,
+ authenticate(results, Constants.AUTHENTICATE_TO_MY_MAPS,
MyMapsConstants.SERVICE_NAME);
// AUTHENTICATE_TO_MY_MAPS callback calls sendToGoogleMaps
}
@@ -1049,7 +957,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
} catch (RuntimeException e) {
// If that fails whatever reasons we'll just log an error, but
// continue.
- Log.w(MyTracksConstants.TAG, "Updating map id failed.", e);
+ Log.w(TAG, "Updating map id failed.", e);
}
}
@@ -1081,7 +989,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
setProgressValue(0);
setProgressMessage(R.string.progress_message_authenticating_fusiontables);
- authenticate(results, MyTracksConstants.AUTHENTICATE_TO_FUSION_TABLES,
+ authenticate(results, Constants.AUTHENTICATE_TO_FUSION_TABLES,
SendToFusionTables.SERVICE_ID);
// AUTHENTICATE_TO_FUSION_TABLES callback calls sendToFusionTables
}
@@ -1103,10 +1011,10 @@ public class MyTracks extends TabActivity implements OnTouchListener,
} catch (RuntimeException e) {
// If that fails whatever reasons we'll just log an error, but
// continue.
- Log.w(MyTracksConstants.TAG, "Updating table id failed.", e);
+ Log.w(TAG, "Updating table id failed.", e);
}
}
-
+
onSendToFusionTablesDone();
}
};
@@ -1134,7 +1042,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
setProgressMessage(
R.string.progress_message_authenticating_docs);
authenticate(new Intent(),
- MyTracksConstants.AUTHENTICATE_TO_DOCLIST,
+ Constants.AUTHENTICATE_TO_DOCLIST,
SendToDocs.GDATA_SERVICE_NAME_DOCLIST);
// AUTHENTICATE_TO_DOCLIST callback calls authenticateToGoogleTrix
}
@@ -1144,16 +1052,16 @@ public class MyTracks extends TabActivity implements OnTouchListener,
setProgressMessage(
R.string.progress_message_authenticating_docs);
authenticate(new Intent(),
- MyTracksConstants.AUTHENTICATE_TO_TRIX,
+ Constants.AUTHENTICATE_TO_TRIX,
SendToDocs.GDATA_SERVICE_NAME_TRIX);
// AUTHENTICATE_TO_TRIX callback calls sendToGoogleDocs
}
private void sendToGoogleDocs(final long trackId) {
- Log.d(MyTracksConstants.TAG, "Sending to Docs....");
+ Log.d(TAG, "Sending to Docs....");
setProgressValue(50);
setProgressMessage(R.string.progress_message_sending_docs);
- final SendToDocs sender = new SendToDocs(this,
+ final SendToDocs sender = new SendToDocs(this,
authMap.get(SendToDocs.GDATA_SERVICE_NAME_TRIX),
authMap.get(SendToDocs.GDATA_SERVICE_NAME_DOCLIST), trackId);
sendToTrackId = trackId;
@@ -1222,7 +1130,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
DialogManager.showDialogSafely(this, sendToGoogleResultDialog);
}
- private boolean shareLinkToMap(boolean sentToMyMaps, boolean sentToFusionTables) {
+ boolean shareLinkToMap(boolean sentToMyMaps, boolean sentToFusionTables) {
String url = null;
if (sentToMyMaps && sendToMyMapsSuccess) {
// Prefer a link to My Maps
@@ -1265,32 +1173,23 @@ public class MyTracks extends TabActivity implements OnTouchListener,
return results;
}
- /**
- * Writes the selected track id to the shared preferences.
- * Executed on the UI thread.
- *
- * @param trackId the id of the track
- */
- public void setSelectedTrackId(final long trackId) {
- ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
- sharedPreferences
- .edit()
- .putLong(getString(R.string.selected_track_key), trackId));
+ void clearSelectedTrack() {
+ dataHub.unloadCurrentTrack();
}
long getSelectedTrackId() {
- return selectedTrackId;
+ return dataHub.getSelectedTrackId();
}
/**
* Binds to track recording service if it is running.
*/
private void tryBindTrackRecordingService() {
- Log.d(MyTracksConstants.TAG,
+ Log.d(TAG,
"MyTracks: Trying to bind to track recording service...");
bindService(new Intent(this, TrackRecordingService.class),
serviceConnection, 0);
- Log.d(MyTracksConstants.TAG, "MyTracks: ...bind finished!");
+ Log.d(TAG, "MyTracks: ...bind finished!");
isBound = true;
}
@@ -1300,14 +1199,12 @@ public class MyTracks extends TabActivity implements OnTouchListener,
*/
private void tryUnbindTrackRecordingService() {
if (isBound) {
- Log.d(MyTracksConstants.TAG,
- "MyTracks: Trying to unbind from track recording service...");
+ Log.d(TAG, "MyTracks: Trying to unbind from track recording service...");
try {
unbindService(serviceConnection);
- Log.d(MyTracksConstants.TAG, "MyTracks: ...unbind finished!");
+ Log.d(TAG, "MyTracks: ...unbind finished!");
} catch (IllegalArgumentException e) {
- Log.d(MyTracksConstants.TAG,
- "MyTracks: Tried unbinding, but service was not registered.", e);
+ Log.d(TAG, "MyTracks: Tried unbinding, but service was not registered.", e);
}
isBound = false;
}
@@ -1399,26 +1296,30 @@ public class MyTracks extends TabActivity implements OnTouchListener,
}
public boolean getSendToGoogleSuccess() {
- return sendToMyMapsSuccess && sendToFusionTablesSuccess && sendToDocsSuccess;
+ return sendToFusionTablesSuccess && sendToDocsSuccess;
}
// @VisibleForTesting
long getRecordingTrackId() {
- return recordingTrackId;
+ return sharedPreferences.getLong(getString(R.string.recording_track_key), -1);
}
-
+
// @VisibleForTesting
SharedPreferences getSharedPreferences() {
return sharedPreferences;
}
-
+
// @VisibleForTesting
static void clearInstance() {
instance = null;
}
-
+
// @VisibleForTesting
ITrackRecordingService getTrackRecordingService() {
return trackRecordingService;
}
+
+ public TrackDataHub getDataHub() {
+ return dataHub;
+ }
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracksMap.java b/MyTracks/src/com/google/android/apps/mytracks/MyTracksMap.java
deleted file mode 100644
index 608a7ec3c..000000000
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracksMap.java
+++ /dev/null
@@ -1,1094 +0,0 @@
-/*
- * Copyright 2008 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.android.apps.mytracks;
-
-import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
-import com.google.android.apps.mytracks.content.Track;
-import com.google.android.apps.mytracks.content.TrackPointsColumns;
-import com.google.android.apps.mytracks.content.Waypoint;
-import com.google.android.apps.mytracks.content.WaypointsColumns;
-import com.google.android.apps.mytracks.services.StatusAnnouncerFactory;
-import com.google.android.apps.mytracks.stats.TripStatistics;
-import com.google.android.apps.mytracks.util.ApiFeatures;
-import com.google.android.apps.mytracks.util.GeoRect;
-import com.google.android.apps.mytracks.util.MyTracksUtils;
-import com.google.android.maps.GeoPoint;
-import com.google.android.maps.MapActivity;
-import com.google.android.maps.MapController;
-import com.google.android.maps.MapView;
-import com.google.android.maps.mytracks.R;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.hardware.GeomagneticField;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.location.LocationProvider;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.provider.Settings;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.SubMenu;
-import android.view.View;
-import android.view.Window;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.View.OnCreateContextMenuListener;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
-import android.widget.Toast;
-
-/**
- * The map view activity of the MyTracks application.
- *
- * @author Leif Hendrik Wilden
- */
-public class MyTracksMap extends MapActivity
- implements View.OnTouchListener, View.OnClickListener,
- SharedPreferences.OnSharedPreferenceChangeListener {
- private static final int TRACKPOINT_BUFFER_SIZE = 1024;
-
- // Saved instance state keys:
- // ---------------------------
-
- public static final String KEY_CURRENT_LOCATION = "currentLocation";
- public static final String KEY_KEEP_MY_LOCATION_VISIBLE =
- "keepMyLocationVisible";
- public static final String KEY_HAVE_GOOD_FIX = "haveGoodFix";
-
- /**
- * The ID of the currently selected track (or -1 if nothing selected).
- */
- private long selectedTrackId = -1;
-
- /**
- * The id of the currently recording track.
- */
- private long recordingTrackId = -1;
-
- /**
- * True if the map should be scrolled so that the pointer is always in the
- * visible area.
- */
- private boolean keepMyLocationVisible;
-
- /**
- * Id of the first location that was seen when reading tracks from the
- * provider.
- */
- private long firstSeenLocationId = -1;
-
- /**
- * Id of the last location that was seen when reading tracks from the
- * provider. This is used to determine which locations are new compared to the
- * last time the mapOverlay was updated.
- */
- private long lastSeenLocationId = -1;
-
- /**
- * Magnetic variation.
- */
- private double variation;
-
- /**
- * From the shared preferences.
- */
- private int minRequiredAccuracy =
- MyTracksSettings.DEFAULT_MIN_REQUIRED_ACCURACY;
-
- /**
- * True, if the application thinks it has a good fix, i.e. accuracy is better
- * than the required accuracy.
- */
- private boolean haveGoodFix;
-
- /**
- * The current pointer location.
- */
- private Location currentLocation;
-
- /**
- * A thread with a looper. Post to updateTrackHandler to execute
- * {@link Runnable}s on this thread.
- */
- private HandlerThread updateTrackThread;
-
- /**
- * Handler for updateTrackThread.
- */
- private Handler updateTrackHandler;
-
- private MyTracksProviderUtils providerUtils;
-
- private SharedPreferences sharedPreferences;
-
- /**
- * A runnable that updates the track from the provider (looking for points
- * added after "lastSeenLocationId").
- */
- private final Runnable updateTrackRunnable = new Runnable() {
- @Override
- public void run() {
- if (!isATrackSelected()) {
- return;
- }
-
- readAllNewTrackPoints();
- }
- };
-
- /**
- * A runnable that restores all track points from the provider.
- */
- private Runnable restoreTrackRunnable = new Runnable() {
- @Override
- public void run() {
- if (!isATrackSelected()) {
- return;
- }
-
- mapOverlay.clearPoints();
- firstSeenLocationId = -1;
- lastSeenLocationId = -1;
- readAllNewTrackPoints();
- }
- };
-
- /**
- * A runnable that restores all waypoints from the provider.
- */
- private final Runnable restoreWaypointsRunnable = new Runnable() {
- @Override
- public void run() {
- if (!isATrackSelected()) {
- return;
- }
-
- Cursor cursor = null;
- mapOverlay.clearWaypoints();
- try {
- // We will silently drop extra waypoints to make the app responsive.
- // TODO: Try to only load the waypoints in the view port.
- cursor = providerUtils.getWaypointsCursor(
- selectedTrackId, 0,
- MyTracksConstants.MAX_DISPLAYED_WAYPOINTS_POINTS);
- if (cursor != null && cursor.moveToFirst()) {
- do {
- Waypoint waypoint = providerUtils.createWaypoint(cursor);
- if (MyTracksUtils.isValidLocation(waypoint.getLocation())) {
- mapOverlay.addWaypoint(waypoint);
- }
- } while (cursor.moveToNext());
- }
- } catch (RuntimeException e) {
- Log.w(MyTracksConstants.TAG, "Caught an unexpected exception.", e);
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- mapView.postInvalidate();
- }
- };
-
- /**
- * A runnable intended to be posted to the {@code #updateTrackThread} after
- * the selected track changes. It will post to the UI thread to update
- * the screen elements and move the map to show the selected track.
- */
- private final Runnable setSelectedTrackRunnable = new Runnable() {
- @Override
- public void run() {
- uiHandler.post(new Runnable() {
- public void run() {
- showTrack(selectedTrackId);
- mapOverlay.setTrackDrawingEnabled(isATrackSelected());
- mapOverlay.setShowEndMarker(!isRecordingSelected());
- mapView.invalidate();
- busyPane.setVisibility(View.GONE);
- updateOptionsButton();
- }
- });
- }
- };
-
- // UI elements:
- // -------------
-
- private RelativeLayout screen;
- private MapView mapView;
- private MyTracksOverlay mapOverlay;
- private LinearLayout messagePane;
- private TextView messageText;
- private LinearLayout busyPane;
- private ImageButton optionsBtn;
-
- private MenuItem myLocation;
- private MenuItem toggleLayers;
-
- private SensorManager sensorManager;
- private LocationManager locationManager;
- private ContentObserver observer;
- private ContentObserver waypointObserver;
-
- /** Handler for callbacks to the UI thread */
- private final Handler uiHandler = new Handler();
-
- /**
- * We are not displaying driving directions. Just an arbitrary track that is
- * not associated to any licensed mapping data. Therefore it should be okay to
- * return false here and still comply with the terms of service.
- */
- @Override
- protected boolean isRouteDisplayed() {
- return false;
- }
-
- /**
- * We are displaying a location. This needs to return true in order to comply
- * with the terms of service.
- */
- @Override
- protected boolean isLocationDisplayed() {
- return true;
- }
-
- // Application life cycle:
- // ------------------------
-
- @Override
- public void onCreate(Bundle bundle) {
- Log.d(MyTracksConstants.TAG, "MyTracksMap.onCreate");
- super.onCreate(bundle);
-
- // The volume we want to control is the Text-To-Speech volume
- int volumeStream =
- new StatusAnnouncerFactory(ApiFeatures.getInstance()).getVolumeStream();
- setVolumeControlStream(volumeStream);
-
- providerUtils = MyTracksProviderUtils.Factory.get(this);
-
- // We don't need a window title bar:
- requestWindowFeature(Window.FEATURE_NO_TITLE);
-
- // Inflate the layout:
- setContentView(R.layout.mytracks_layout);
-
- // Remove the window's background because the MapView will obscure it
- getWindow().setBackgroundDrawable(null);
-
- // Set up a map overlay:
- screen = (RelativeLayout) findViewById(R.id.screen);
- mapView = (MapView) findViewById(R.id.map);
- mapView.requestFocus();
- mapOverlay = new MyTracksOverlay(this);
- mapView.getOverlays().add(mapOverlay);
- mapView.setOnTouchListener(this);
- messagePane = (LinearLayout) findViewById(R.id.messagepane);
- messageText = (TextView) findViewById(R.id.messagetext);
- busyPane = (LinearLayout) findViewById(R.id.busypane);
- optionsBtn = (ImageButton) findViewById(R.id.showOptions);
-
- optionsBtn.setOnCreateContextMenuListener(contextMenuListener);
- optionsBtn.setOnClickListener(this);
-
- setupZoomControls();
-
- // Get the sensor and location managers:
- sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
- locationManager =
- (LocationManager) getSystemService(Context.LOCATION_SERVICE);
-
- updateTrackThread = new HandlerThread("updateTrackThread");
- updateTrackThread.start();
- updateTrackHandler = new Handler(updateTrackThread.getLooper());
-
- // Register observer for the track point provider:
- Handler contentHandler = new Handler();
- observer = new ContentObserver(contentHandler) {
- @Override
- public void onChange(boolean selfChange) {
- Log.d(MyTracksConstants.TAG, "MyTracksMap: ContentObserver.onChange");
- if (!isRecordingSelected()) {
- // No track, or one other than the recording track is selected,
- // don't bother.
- return;
- }
- // Update can potentially be lengthy, put it in its own thread:
- updateTrackHandler.post(updateTrackRunnable);
- super.onChange(selfChange);
- }
- };
-
- waypointObserver = new ContentObserver(contentHandler) {
- @Override
- public void onChange(boolean selfChange) {
- Log.d(MyTracksConstants.TAG,
- "MyTracksMap: ContentObserver.onChange waypoints");
- if (!isATrackSelected()) {
- return;
- }
- updateTrackHandler.post(restoreWaypointsRunnable);
- super.onChange(selfChange);
- }
- };
-
- // Read shared preferences and register change listener.
- sharedPreferences = getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
- if (sharedPreferences != null) {
- reloadSharedPreferences(sharedPreferences, null);
- updateOptionsButton();
- sharedPreferences.registerOnSharedPreferenceChangeListener(this);
- }
- }
-
- @Override
- protected void onDestroy() {
- Log.d(MyTracksConstants.TAG, "MyTracksMap.onDestroy");
-
- if (updateTrackThread != null) {
- ApiFeatures.getInstance().getApiPlatformAdapter().stopHandlerThread(
- updateTrackThread);
- }
- if (sharedPreferences != null) {
- sharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
- }
-
- super.onDestroy();
- }
-
- /**
- * Returns whether there's a track currently selected for display.
- */
- private boolean isATrackSelected() {
- return selectedTrackId >= 0;
- }
-
- /**
- * Returns whether we're currently recording the same track that's selected
- * for display.
- */
- private boolean isRecordingSelected() {
- return isATrackSelected() && selectedTrackId == recordingTrackId;
- }
-
- protected void setupZoomControls() {
- mapView.setBuiltInZoomControls(true);
- }
-
- @Override
- protected void onStart() {
- // Called after onCreate or onStop.
- // Will be followed by onRestart.
- Log.d(MyTracksConstants.TAG, "MyTracksMap.onStart");
- super.onStart();
- }
-
- @Override
- protected void onStop() {
- // Called when activity is no longer visible to user.
- // Next either onStart, onDestroy or nothing will be called.
- // This method may never be called in low memory situations.
- Log.d(MyTracksConstants.TAG, "MyTracksMap.onStop");
- super.onStop();
- }
-
- @Override
- protected void onRestart() {
- // Called when the current activity is being re-displayed.
- // Will be followed by onResume.
- Log.d(MyTracksConstants.TAG, "MyTracksMap.onRestart");
- super.onRestart();
- }
-
- @Override
- protected void onPause() {
- // Called when activity is going into the background, but has not (yet) been
- // killed. Shouldn't block longer than approx. 2 seconds.
- Log.d(MyTracksConstants.TAG, "MyTracksMap.onPause");
- unregisterLocationAndSensorListeners();
- unregisterContentObservers();
- super.onPause();
- }
-
- @Override
- protected void onResume() {
- // Called when the current activity is being displayed or re-displayed
- // to the user.
- 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);
- waypointObserver.onChange(false);
-
- registerContentObservers();
- registerLocationAndSensorListeners();
-
- if (locationManager.isProviderEnabled(MyTracksConstants.GPS_PROVIDER)) {
- messageText.setText(R.string.wait_for_fix);
- messagePane.setOnClickListener(null);
- } else {
- messageText.setText(R.string.status_enable_gps);
- messagePane.setVisibility(View.VISIBLE);
- messagePane.setOnClickListener(this);
- screen.requestLayout();
- }
-
- // While this activity was paused the user may have deleted the selected
- // track. In that case the map overlay needs to be cleared:
- if (isATrackSelected() && !providerUtils.trackExists(selectedTrackId)) {
- // The recording track must have been deleted meanwhile.
- mapOverlay.setTrackDrawingEnabled(false);
- mapView.invalidate();
- }
- }
-
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- Log.d(MyTracksConstants.TAG, "MyTracksMap.onSaveInstanceState");
- outState.putBoolean(KEY_HAVE_GOOD_FIX, haveGoodFix);
- outState.putBoolean(KEY_KEEP_MY_LOCATION_VISIBLE, keepMyLocationVisible);
- if (currentLocation != null) {
- outState.putParcelable(KEY_CURRENT_LOCATION, currentLocation);
- }
- super.onSaveInstanceState(outState);
- }
-
- @Override
- protected void onRestoreInstanceState(Bundle bundle) {
- Log.d(MyTracksConstants.TAG, "MyTracksMap.onRestoreInstanceState");
- if (bundle != null) {
- super.onRestoreInstanceState(bundle);
- haveGoodFix = bundle.getBoolean(KEY_HAVE_GOOD_FIX, false);
- keepMyLocationVisible =
- bundle.getBoolean(KEY_KEEP_MY_LOCATION_VISIBLE, false);
- if (bundle.containsKey(KEY_CURRENT_LOCATION)) {
- currentLocation = (Location) bundle.getParcelable(KEY_CURRENT_LOCATION);
- if (currentLocation != null) {
- setVariation(currentLocation);
- showCurrentLocation();
- }
- } else {
- currentLocation = null;
- }
- }
- }
-
- // Utility functions:
- // -------------------
-
- /**
- * Toggles between satellite and map view.
- */
- public void toggleLayer() {
- mapView.setSatellite(!mapView.isSatellite());
- }
-
- /**
- * Registers to receive location updates from the GPS location provider and
- * sensor updated from the compass.
- */
- void registerLocationAndSensorListeners() {
- if (locationManager != null) {
- LocationProvider gpsProvider =
- locationManager.getProvider(MyTracksConstants.GPS_PROVIDER);
- if (gpsProvider == null) {
- alert(getString(R.string.error_no_gps_location_provider));
- return;
- } else {
- Log.d(MyTracksConstants.TAG, "MyTracksMap: Using location provider "
- + gpsProvider.getName());
- }
- locationManager.requestLocationUpdates(gpsProvider.getName(),
- 0 /*minTime*/, 0 /*minDist*/, locationListener);
- try {
- locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
- 1000 * 60 * 5 /*minTime*/, 0 /*minDist*/, locationListener);
- } catch (RuntimeException e) {
- // If anything at all goes wrong with getting a cell location do not
- // abort. Cell location is not essential to this app.
- Log.w(MyTracksConstants.TAG,
- "Could not register network location listener.");
- }
- }
- if (sensorManager == null) {
- return;
- }
- Sensor compass = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
- if (compass == null) {
- return;
- }
- Log.d(MyTracksConstants.TAG,
- "MyTracksMap: Now registering sensor listeners.");
- sensorManager.registerListener(
- sensorListener, compass, SensorManager.SENSOR_DELAY_UI);
- }
-
- /**
- * Unregisters all location and sensor listeners
- */
- void unregisterLocationAndSensorListeners() {
- if (locationManager != null) {
- Log.d(MyTracksConstants.TAG,
- "MyTracksMap: Now unregistering location listeners.");
- locationManager.removeUpdates(locationListener);
- }
- if (sensorManager != null) {
- Log.d(MyTracksConstants.TAG,
- "MyTracksMap: Now unregistering sensor listeners.");
- sensorManager.unregisterListener(sensorListener);
- }
- }
-
- /**
- * Registers the content observer for the map overlay.
- */
- private void registerContentObservers() {
- getContentResolver().registerContentObserver(
- TrackPointsColumns.CONTENT_URI, false /* notifyForDescendents */,
- observer);
- getContentResolver().registerContentObserver(
- WaypointsColumns.CONTENT_URI, false /* notifyForDescendents */,
- waypointObserver);
- }
-
- /**
- * Unregisters the content observer for the map overlay.
- */
- private void unregisterContentObservers() {
- getContentResolver().unregisterContentObserver(observer);
- getContentResolver().unregisterContentObserver(waypointObserver);
- }
-
- /**
- * Shows the options button if a track is selected, or hide it if not.
- */
- private void updateOptionsButton() {
- optionsBtn.setVisibility(
- isATrackSelected() ? View.VISIBLE : View.INVISIBLE);
- }
-
- /**
- * Tests if a location is visible.
- *
- * @param location a given location
- * @return true if the given location is within the visible map area
- */
- private boolean locationIsVisible(Location location) {
- if (location == null || mapView == null) {
- return false;
- }
- GeoPoint center = mapView.getMapCenter();
- int latSpan = mapView.getLatitudeSpan();
- int lonSpan = mapView.getLongitudeSpan();
-
- // Bottom of map view is obscured by zoom controls/buttons.
- // Subtract a margin from the visible area:
- GeoPoint marginBottom = mapView.getProjection().fromPixels(
- 0, mapView.getHeight());
- GeoPoint marginTop = mapView.getProjection().fromPixels(0,
- mapView.getHeight()
- - mapView.getZoomButtonsController().getZoomControls().getHeight());
- int margin =
- Math.abs(marginTop.getLatitudeE6() - marginBottom.getLatitudeE6());
- GeoRect r = new GeoRect(center, latSpan, lonSpan);
- r.top += margin;
-
- GeoPoint geoPoint = MyTracksUtils.getGeoPoint(location);
- return r.contains(geoPoint);
- }
-
- /**
- * Moves the location pointer to the current location and center the map if
- * the current location is outside the visible area.
- */
- private void showCurrentLocation() {
- if (currentLocation == null || mapOverlay == null || mapView == null) {
- return;
- }
- mapOverlay.setMyLocation(currentLocation);
- mapView.invalidate();
- if (keepMyLocationVisible && !locationIsVisible(currentLocation)) {
- MapController controller = mapView.getController();
- GeoPoint geoPoint = MyTracksUtils.getGeoPoint(currentLocation);
- controller.animateTo(geoPoint);
- }
- }
-
- /**
- * Zooms and pans the map so that the given track is visible.
- *
- * @param trackId a given track ID
- */
- public void showTrack(long trackId) {
- if (mapView == null) {
- return;
- }
-
- Track track = providerUtils.getTrack(trackId);
- if (track == null || track.getNumberOfPoints() < 2) {
- return;
- }
-
- TripStatistics stats = track.getStatistics();
- int bottom = stats.getBottom();
- int left = stats.getLeft();
- int latSpanE6 = stats.getTop() - bottom;
- int lonSpanE6 = stats.getRight() - left;
- if (latSpanE6 > 0
- && latSpanE6 < 180E6
- && lonSpanE6 > 0
- && lonSpanE6 < 360E6) {
- keepMyLocationVisible = false;
- GeoPoint center = new GeoPoint(
- bottom + latSpanE6 / 2,
- left + lonSpanE6 / 2);
- if (MyTracksUtils.isValidGeoPoint(center)) {
- mapView.getController().setCenter(center);
- mapView.getController().zoomToSpan(latSpanE6, lonSpanE6);
- }
- }
- }
-
- /**
- * Zooms and pans the map so that the given waypoint is visible.
- */
- public void showWaypoint(long waypointId) {
- Waypoint wpt = providerUtils.getWaypoint(waypointId);
- if (wpt != null && wpt.getLocation() != null) {
- keepMyLocationVisible = false;
- GeoPoint center = new GeoPoint(
- (int) (wpt.getLocation().getLatitude() * 1E6),
- (int) (wpt.getLocation().getLongitude() * 1E6));
- mapView.getController().setCenter(center);
- mapView.getController().setZoom(20);
- mapView.invalidate();
- }
- }
-
- /**
- * Sets the selected track and zoom and pan the map so that it is visible.
- *
- * @param trackId a given track id
- */
- public void setSelectedTrack(final long trackId) {
- Log.d(MyTracksConstants.TAG, "MyTracksMap.setSelectedTrack: "
- + "selectedTrackId = " + selectedTrackId + ", trackId = " + trackId);
-
- if (selectedTrackId == trackId) {
- // Selected track did not change, nothing to do.
- mapOverlay.setTrackDrawingEnabled(isATrackSelected());
- updateOptionsButton();
- mapView.invalidate();
- return;
- }
-
- if (trackId < 0) {
- // Remove selection.
- selectedTrackId = -1;
- mapOverlay.setTrackDrawingEnabled(false);
- mapOverlay.clearWaypoints();
- updateOptionsButton();
- mapView.invalidate();
- return;
- }
-
- busyPane.setVisibility(View.VISIBLE);
- selectedTrackId = trackId;
- loadSelectedTrack();
- }
-
- private void loadSelectedTrack() {
- updateTrackHandler.post(restoreTrackRunnable);
- updateTrackHandler.post(restoreWaypointsRunnable);
- updateTrackHandler.post(setSelectedTrackRunnable);
- }
-
- /**
- * Displays an alert for a few seconds.
- *
- * @param txt The text to be displayed
- */
- public void alert(String txt) {
- Toast.makeText(this, txt, Toast.LENGTH_LONG).show();
- }
-
- public void launchMyLocationSettings() {
- startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
- }
-
- public void setVariation(Location location) {
- long timestamp = location.getTime();
- if (timestamp == 0) {
- // Hack for Samsung phones which don't populate the time field
- timestamp = System.currentTimeMillis();
- }
-
- GeomagneticField field = new GeomagneticField(
- (float) location.getLatitude(),
- (float) location.getLongitude(),
- (float) location.getAltitude(),
- timestamp);
- variation = field.getDeclination();
-
- Log.d(MyTracksConstants.TAG,
- "MyTracksMap: Variation reset to " + variation + " degrees.");
- }
-
- public MyTracksOverlay getMapOverlay() {
- return mapOverlay;
- }
-
- public MapView getMapView() {
- return mapView;
- }
-
- // Event listeners:
- // -----------------
-
- private final OnCreateContextMenuListener contextMenuListener =
- new OnCreateContextMenuListener() {
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
- menu.setHeaderTitle(R.string.tracklist_this_track);
- menu.add(0, MyTracksConstants.MENU_EDIT, 0,
- R.string.tracklist_edit_track);
- 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,
- R.string.tracklist_share_track);
- share.add(0, MyTracksConstants.MENU_SHARE_LINK, 0,
- R.string.tracklist_share_link);
- share.add(0, MyTracksConstants.MENU_SHARE_GPX_FILE, 0,
- R.string.tracklist_share_gpx_file);
- share.add(0, MyTracksConstants.MENU_SHARE_KML_FILE, 0,
- R.string.tracklist_share_kml_file);
- share.add(0, MyTracksConstants.MENU_SHARE_CSV_FILE, 0,
- R.string.tracklist_share_csv_file);
- share.add(0, MyTracksConstants.MENU_SHARE_TCX_FILE, 0,
- R.string.tracklist_share_tcx_file);
- SubMenu save = menu.addSubMenu(0,
- MyTracksConstants.MENU_WRITE_TO_SD_CARD, 0,
- R.string.tracklist_write_to_sd);
- save.add(0, MyTracksConstants.MENU_SAVE_GPX_FILE, 0,
- R.string.tracklist_save_as_gpx);
- save.add(0, MyTracksConstants.MENU_SAVE_KML_FILE, 0,
- R.string.tracklist_save_as_kml);
- save.add(0, MyTracksConstants.MENU_SAVE_CSV_FILE, 0,
- R.string.tracklist_save_as_csv);
- save.add(0, MyTracksConstants.MENU_SAVE_TCX_FILE, 0,
- R.string.tracklist_save_as_tcx);
- menu.add(0, MyTracksConstants.MENU_CLEAR_MAP, 0,
- R.string.tracklist_clear_map);
- menu.add(0, MyTracksConstants.MENU_DELETE, 0,
- R.string.tracklist_delete_track);
- }
- }
- };
-
- @Override
- public boolean onMenuItemSelected(int featureId, MenuItem item) {
- if (!super.onMenuItemSelected(featureId, item)) {
- if (isATrackSelected()) {
- MyTracks.getInstance().onActivityResult(
- MyTracksConstants.getActionFromMenuId(item.getItemId()), RESULT_OK,
- new Intent());
- return true;
- }
- }
- return false;
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- myLocation = menu.add(0, MyTracksConstants.MENU_MY_LOCATION, 0,
- R.string.mylocation);
- myLocation.setIcon(android.R.drawable.ic_menu_mylocation);
- toggleLayers = menu.add(0, MyTracksConstants.MENU_TOGGLE_LAYERS, 0,
- R.string.switch_to_sat);
- toggleLayers.setIcon(android.R.drawable.ic_menu_mapmode);
- return true;
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- toggleLayers.setTitle(mapView.isSatellite() ?
- R.string.switch_to_map : R.string.switch_to_sat);
- return super.onPrepareOptionsMenu(menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case MyTracksConstants.MENU_MY_LOCATION: {
- Location loc = MyTracks.getInstance().getCurrentLocation();
- if (loc != null) {
- currentLocation = loc;
- setVariation(currentLocation);
- mapOverlay.setMyLocation(loc);
- mapView.invalidate();
- GeoPoint geoPoint = MyTracksUtils.getGeoPoint(loc);
- MapController controller = mapView.getController();
- controller.animateTo(geoPoint);
- if (mapView.getZoomLevel() < 18) {
- controller.setZoom(18);
- }
- keepMyLocationVisible = true;
- }
- return true;
- }
- case MyTracksConstants.MENU_TOGGLE_LAYERS: {
- toggleLayer();
- return true;
- }
- }
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- public void onClick(View v) {
- if (v == messagePane) {
- launchMyLocationSettings();
- } else if (v == optionsBtn) {
- optionsBtn.performLongClick();
- }
- }
-
- /**
- * We want the pointer to become visible again in case of the next location
- * update:
- */
- @Override
- public boolean onTouch(View view, MotionEvent event) {
- if (keepMyLocationVisible && event.getAction() == MotionEvent.ACTION_MOVE) {
- if (!locationIsVisible(currentLocation)) {
- keepMyLocationVisible = false;
- }
- }
- return false;
- }
-
- @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() {
- reloadSharedPreferences(sharedPreferences, key);
- }
- });
- }
- }
-
- private final LocationListener locationListener = new LocationListener() {
- @Override
- public void onProviderEnabled(String provider) {
- if (provider.equals(MyTracksConstants.GPS_PROVIDER)) {
- messageText.setText(R.string.wait_for_fix);
- }
- }
-
- @Override
- public void onProviderDisabled(String provider) {
- if (provider.equals(MyTracksConstants.GPS_PROVIDER)) {
- messageText.setText(R.string.status_enable_gps);
- messagePane.setVisibility(View.VISIBLE);
- messagePane.setOnClickListener(MyTracksMap.this);
- screen.requestLayout();
- }
- }
-
- @Override
- public void onLocationChanged(Location location) {
- if (location.getProvider().equals(MyTracksConstants.GPS_PROVIDER)) {
- // Recalculate the variation if there was a jump in location > 1km:
- if (currentLocation == null ||
- location.distanceTo(currentLocation) > 1000) {
- setVariation(location);
- }
- currentLocation = location;
- boolean haveGoodFixNow =
- currentLocation.getAccuracy() < minRequiredAccuracy;
- if (haveGoodFixNow != haveGoodFix) {
- haveGoodFix = haveGoodFixNow;
- messagePane.setVisibility(haveGoodFix ? View.GONE : View.VISIBLE);
- screen.requestLayout();
- }
- showCurrentLocation();
- } else {
- Log.d(MyTracksConstants.TAG,
- "MyTracksMap: Network location update received.");
- }
- }
-
- @Override
- public void onStatusChanged(String provider, int status, Bundle extras) {
- if (provider.equals(MyTracksConstants.GPS_PROVIDER)) {
- switch (status) {
- case LocationProvider.OUT_OF_SERVICE:
- case LocationProvider.TEMPORARILY_UNAVAILABLE:
- haveGoodFix = false;
- messagePane.setVisibility(View.VISIBLE);
- screen.requestLayout();
- break;
- }
- }
- }
- };
-
- private final SensorEventListener sensorListener = new SensorEventListener() {
- @Override
- public void onSensorChanged(SensorEvent se) {
- synchronized (this) {
- float magneticHeading = se.values[0];
- double heading = magneticHeading + variation;
- if (mapOverlay.setHeading((float) heading)) {
- mapView.invalidate();
- }
- }
- }
-
- @Override
- public void onAccuracyChanged(Sensor s, int accuracy) {
- // do nothing
- }
- };
-
- 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) {
- // We're about to exceed the maximum allowed number of points, so reload
- // the whole track with fewer points (the sampling frequency will be
- // lower).
- loadSelectedTrack();
- return;
- }
- // Keep a copy of selectedTrackId, because it can change asynchronously.
- long currentSelectedTrackId = selectedTrackId;
- long lastStoredLocationId =
- providerUtils.getLastLocationId(currentSelectedTrackId);
- int samplingFrequency = -1;
- Location location = new Location("");
- while (currentSelectedTrackId == selectedTrackId) {
- Cursor cursor = null;
- try {
- cursor = providerUtils.getLocationsCursor(currentSelectedTrackId,
- lastSeenLocationId + 1, TRACKPOINT_BUFFER_SIZE, false);
- if (cursor == null || !cursor.moveToFirst()) {
- // No (more) data
- break;
- }
-
- final int idColumnIdx = cursor.getColumnIndexOrThrow(
- TrackPointsColumns._ID);
- do {
- long locationId = cursor.getLong(idColumnIdx);
- lastSeenLocationId = locationId;
- if (firstSeenLocationId == -1) {
- // This was our first point, keep its ID
- firstSeenLocationId = locationId;
- }
- if (samplingFrequency == -1) {
- // Now we already have at least one point, calculate the sampling
- // frequency
- long numTotalPoints = lastStoredLocationId - firstSeenLocationId;
- samplingFrequency = (int) (1 + numTotalPoints
- / MyTracksConstants.TARGET_DISPLAYED_TRACK_POINTS);
- // TODO: This shouldn't happen after adding currentSelectedTrackId,
- // but just to be safe until we have 100% confidence.
- if (samplingFrequency <= 0) {
- Log.w(MyTracksConstants.TAG,
- "readAllNewTrackPoints: samplingFreq <= 0, numTotalPoints = "
- + numTotalPoints + ", trackId = " + currentSelectedTrackId);
- samplingFrequency = 1;
- }
- }
-
- providerUtils.fillLocation(cursor, location);
-
- // Include a point if it fits one of the following criteria:
- // - Has the mod for the sampling frequency (includes first point).
- // - Is the last point and we are not recording this track.
- // - The point is a segment split
- if (numPoints % samplingFrequency == 0 ||
- (!isRecordingSelected() && locationId == lastStoredLocationId) ||
- !MyTracksUtils.isValidLocation(location)) {
- // No need to allocate a new location (we can safely reuse the existing).
- mapOverlay.addLocation(location);
- }
-
- numPoints++;
- } while (cursor.moveToNext() &&
- currentSelectedTrackId == selectedTrackId);
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
- mapView.postInvalidate();
- }
-}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/SensorStateActivity.java b/MyTracks/src/com/google/android/apps/mytracks/SensorStateActivity.java
index fb9559d26..5302ad80b 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/SensorStateActivity.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/SensorStateActivity.java
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks;
-import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
+import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.services.ITrackRecordingService;
import com.google.android.apps.mytracks.services.sensors.SensorUtils;
@@ -103,7 +103,7 @@ public class SensorStateActivity extends Activity {
ITrackRecordingService service =
mt == null ? null : mt.getTrackRecordingService();
if (service == null) {
- Log.d(MyTracksConstants.TAG, "Could not get track recording service.");
+ Log.d(Constants.TAG, "Could not get track recording service.");
updateSensorState(Sensor.SensorState.NONE);
updateSensorData(null);
return;
@@ -116,9 +116,9 @@ public class SensorStateActivity extends Activity {
updateSensorData(sds);
}
} catch (RemoteException e) {
- Log.e(MyTracksConstants.TAG, "Could not read sensor data.", e);
+ Log.e(Constants.TAG, "Could not read sensor data.", e);
} catch (InvalidProtocolBufferException e) {
- Log.e(MyTracksConstants.TAG, "Could not read sensor data.", e);
+ Log.e(Constants.TAG, "Could not read sensor data.", e);
}
updateSensorData(sds);
@@ -126,7 +126,7 @@ public class SensorStateActivity extends Activity {
int i = service.getSensorState();
updateSensorState(Sensor.SensorState.valueOf(i));
} catch (RemoteException e) {
- Log.e(MyTracksConstants.TAG, "Could not read sensor state.", e);
+ Log.e(Constants.TAG, "Could not read sensor state.", e);
updateSensorState(Sensor.SensorState.NONE);
}
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracksSettings.java b/MyTracks/src/com/google/android/apps/mytracks/SettingsActivity.java
similarity index 93%
rename from MyTracks/src/com/google/android/apps/mytracks/MyTracksSettings.java
rename to MyTracks/src/com/google/android/apps/mytracks/SettingsActivity.java
index 0e02d05f8..cc2ed1731 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracksSettings.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/SettingsActivity.java
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks;
-import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
+import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.io.backup.BackupActivityHelper;
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
@@ -54,28 +54,14 @@ import java.util.Set;
* @author Leif Hendrik Wilden
* @author Rodrigo Damazio
*/
-public class MyTracksSettings extends PreferenceActivity {
-
- public static final String SETTINGS_NAME = "MyTracksSettings";
-
- /*
- * Default values - keep in sync with those in preferences.xml.
- */
- public static final int DEFAULT_AUTO_RESUME_TRACK_TIMEOUT = 10; // In min.
- public static final int DEFAULT_ANNOUNCEMENT_FREQUENCY = -1;
- public static final int DEFAULT_MAX_RECORDING_DISTANCE = 200;
- public static final int DEFAULT_MIN_RECORDING_DISTANCE = 5;
- public static final int DEFAULT_MIN_RECORDING_INTERVAL = 0;
- public static final int DEFAULT_MIN_REQUIRED_ACCURACY = 200;
- public static final int DEFAULT_SPLIT_FREQUENCY = 0;
+public class SettingsActivity extends PreferenceActivity {
private BackupPreferencesListener backupListener;
-
private SharedPreferences preferences;
/** Called when the activity is first created. */
@Override
- public void onCreate(Bundle icicle) {
+ protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
// The volume we want to control is the Text-To-Speech volume
@@ -86,7 +72,7 @@ public class MyTracksSettings extends PreferenceActivity {
// Tell it where to read/write preferences
PreferenceManager preferenceManager = getPreferenceManager();
- preferenceManager.setSharedPreferencesName(SETTINGS_NAME);
+ preferenceManager.setSharedPreferencesName(Constants.SETTINGS_NAME);
preferenceManager.setSharedPreferencesMode(0);
// Set up automatic preferences backup
@@ -219,7 +205,7 @@ public class MyTracksSettings extends PreferenceActivity {
@Override
public boolean onPreferenceClick(Preference preference) {
BackupActivityHelper backupHelper =
- new BackupActivityHelper(MyTracksSettings.this);
+ new BackupActivityHelper(SettingsActivity.this);
backupHelper.writeBackup();
return true;
}
@@ -229,7 +215,7 @@ public class MyTracksSettings extends PreferenceActivity {
@Override
public boolean onPreferenceClick(Preference preference) {
BackupActivityHelper backupHelper =
- new BackupActivityHelper(MyTracksSettings.this);
+ new BackupActivityHelper(SettingsActivity.this);
backupHelper.restoreBackup();
return true;
}
@@ -373,7 +359,7 @@ public class MyTracksSettings extends PreferenceActivity {
public void run() {
// Give feedback to the user.
Toast.makeText(
- MyTracksSettings.this,
+ SettingsActivity.this,
R.string.settings_reset_done,
Toast.LENGTH_SHORT).show();
diff --git a/MyTracks/src/com/google/android/apps/mytracks/StatsActivity.java b/MyTracks/src/com/google/android/apps/mytracks/StatsActivity.java
index d185c12db..3ddab3bbd 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/StatsActivity.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/StatsActivity.java
@@ -15,26 +15,17 @@
*/
package com.google.android.apps.mytracks;
-import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
-import com.google.android.apps.mytracks.content.MyTracksProviderUtilsImpl;
+import static com.google.android.apps.mytracks.Constants.TAG;
+
import com.google.android.apps.mytracks.content.Track;
-import com.google.android.apps.mytracks.content.TracksColumns;
-import com.google.android.apps.mytracks.content.WaypointsColumns;
+import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.services.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.database.ContentObserver;
import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.location.LocationProvider;
import android.os.Bundle;
-import android.os.Handler;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Menu;
@@ -42,66 +33,39 @@ import android.view.MenuItem;
import android.view.Window;
import android.widget.ScrollView;
import android.widget.TextView;
-import android.widget.Toast;
/**
* An activity that displays track statistics to the user.
*
* @author Sandor Dornbush
+ * @author Rodrigo Damazio
*/
-public class StatsActivity extends Activity
- implements OnSharedPreferenceChangeListener {
-
+public class StatsActivity extends Activity implements TrackDataListener {
private StatsUtilities utils;
private UIUpdateThread thread;
- private ContentObserver observer;
-
- /**
- * The id of the currently selected track.
- */
- private long selectedTrackId = -1;
-
- /**
- * The id of the currently recording track.
- */
- private long recordingTrackId = -1;
-
/**
* The start time of the selected track.
*/
private long startTime = -1;
- /**
- * True if distances should be displayed in metric units (from shared
- * preferences).
- */
- private boolean metricUnits = true;
-
- /**
- * True if pace should be displayed as dist/time (from shared preferences).
- */
- private boolean displaySpeed = true;
-
- /**
- * true if activity has resumed and is on top
- */
- private boolean activityOnTop = false;
-
/**
* If true, the statistics for the current segment are shown, otherwise
* for the full track.
*/
private boolean showCurrentSegment = false;
- private MyTracksProviderUtils providerUtils;
+ private TrackDataHub dataHub;
/**
* A runnable for posting to the UI thread. Will update the total time field.
*/
private final Runnable updateResults = new Runnable() {
public void run() {
- updateTotalTime();
+ if (dataHub.isRecordingSelected()) {
+ utils.setTime(R.id.total_time_register,
+ System.currentTimeMillis() - startTime);
+ }
}
};
@@ -112,24 +76,22 @@ public class StatsActivity extends Activity
public UIUpdateThread() {
super();
- Log.i(MyTracksConstants.TAG, "Created UI update thread");
+ Log.i(TAG, "Created UI update thread");
}
@Override
public void run() {
- Log.i(MyTracksConstants.TAG, "Started UI update thread");
+ Log.i(TAG, "Started UI update thread");
while (MyTracks.getInstance().isRecording()) {
- long sleeptime = 1000;
runOnUiThread(updateResults);
try {
- Thread.sleep(sleeptime);
+ Thread.sleep(1000L);
} catch (InterruptedException e) {
- Log.w(MyTracksConstants.TAG,
- "StatsActivity: Caught exception on sleep.", e);
+ Log.w(TAG, "StatsActivity: Caught exception on sleep.", e);
break;
}
}
- Log.w(MyTracksConstants.TAG, "UIUpdateThread finished.");
+ Log.w(TAG, "UIUpdateThread finished.");
}
}
@@ -138,9 +100,9 @@ public class StatsActivity extends Activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ dataHub = MyTracks.getInstance().getDataHub();
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();
@@ -151,40 +113,10 @@ public class StatsActivity extends Activity
setContentView(R.layout.stats);
- Handler contentHandler = new Handler();
- observer = new ContentObserver(contentHandler) {
- @Override
- public void onChange(boolean selfChange) {
- Log.d(MyTracksConstants.TAG, "StatsActivity: ContentObserver.onChange");
- restoreStats();
- super.onChange(selfChange);
- }
- };
-
ScrollView sv = ((ScrollView) findViewById(R.id.scrolly));
sv.setScrollBarStyle(ScrollView.SCROLLBARS_OUTSIDE_INSET);
- SharedPreferences preferences =
- getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
- if (preferences != null) {
- selectedTrackId = preferences.getLong(
- getString(R.string.selected_track_key), -1);
- recordingTrackId = preferences.getLong(
- getString(R.string.recording_track_key), -1);
- metricUnits = preferences.getBoolean(
- getString(R.string.metric_units_key), true);
- displaySpeed =
- preferences.getBoolean(getString(R.string.report_speed_key), true);
- checkLiveTrack();
- restoreStats();
- showUnknownLocation();
- preferences.registerOnSharedPreferenceChangeListener(this);
- }
- utils.setMetricUnits(metricUnits);
- utils.setReportSpeed(displaySpeed);
- utils.updateUnits();
- utils.setSpeedLabel(R.id.speed_label, R.string.speed, R.string.pace_label);
- utils.setSpeedLabels();
+ showUnknownLocation();
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
@@ -194,88 +126,63 @@ public class StatsActivity extends Activity
}
@Override
- protected void onPause() {
- unregisterLocationListener();
+ protected void onStart() {
+ dataHub.registerTrackDataListener(this);
+
+ super.onStart();
+ }
+
+ @Override
+ protected void onStop() {
+ dataHub.unregisterTrackDataListener(this);
+
if (thread != null) {
thread.interrupt();
thread = null;
}
- getContentResolver().unregisterContentObserver(observer);
- activityOnTop = false;
- super.onPause();
+
+ super.onStop();
}
@Override
- protected void onResume() {
- activityOnTop = true;
- checkLiveTrack();
- restoreStats();
- showUnknownLocation();
- super.onResume();
+ public boolean onUnitsChanged(boolean metric) {
+ utils.setMetricUnits(metric);
+ updateLabels();
+
+ return true; // Reload data
}
@Override
- public void onSharedPreferenceChanged(
- final SharedPreferences sharedPreferences, final String key) {
- Log.d(MyTracksConstants.TAG,
- "StatsActivity: onSharedPreferences changed " + key);
- if (key != null) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- if (key.equals(getString(R.string.selected_track_key))) {
- selectedTrackId =
- sharedPreferences.getLong(
- getString(R.string.selected_track_key),
- -1);
- checkLiveTrack();
- restoreStats();
- showUnknownLocation();
- } else if (key.equals(getString(R.string.recording_track_key))) {
- recordingTrackId =
- sharedPreferences.getLong(
- getString(R.string.recording_track_key),
- -1);
- checkLiveTrack();
- restoreStats();
- showUnknownLocation();
- } else if (key.equals(getString(R.string.metric_units_key))) {
- metricUnits =
- sharedPreferences.getBoolean(
- getString(R.string.metric_units_key), true);
- utils.setMetricUnits(metricUnits);
- utils.updateUnits();
- restoreStats();
- } else if (key.equals(getString(R.string.report_speed_key))) {
- displaySpeed =
- sharedPreferences.getBoolean(
- getString(R.string.report_speed_key),
- true);
- utils.setReportSpeed(displaySpeed);
- utils.updateUnits();
- utils.setSpeedLabel(
- R.id.speed_label, R.string.speed, R.string.pace_label);
- Log.w(MyTracksConstants.TAG, "Setting speed labels");
- utils.setSpeedLabels();
- restoreStats();
- }
- }
- });
- }
+ public boolean onReportSpeedChanged(boolean displaySpeed) {
+ utils.setReportSpeed(displaySpeed);
+ updateLabels();
+
+ return true; // Reload data
+ }
+
+ private void updateLabels() {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ utils.updateUnits();
+ utils.setSpeedLabel(R.id.speed_label, R.string.speed, R.string.pace_label);
+ utils.setSpeedLabels();
+ }
+ });
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuItem currentSegment = menu.add(0,
- MyTracksConstants.MENU_CURRENT_SEGMENT, 0, R.string.current_segment);
+ Constants.MENU_CURRENT_SEGMENT, 0, R.string.current_segment);
currentSegment.setIcon(R.drawable.ic_menu_lastsegment);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
- MenuItem item = menu.findItem(MyTracksConstants.MENU_CURRENT_SEGMENT);
+ MenuItem item = menu.findItem(Constants.MENU_CURRENT_SEGMENT);
if (item != null) {
item.setTitle(showCurrentSegment
? getString(R.string.current_track)
@@ -287,139 +194,14 @@ public class StatsActivity extends Activity
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case MyTracksConstants.MENU_CURRENT_SEGMENT:
+ case Constants.MENU_CURRENT_SEGMENT:
showCurrentSegment = !showCurrentSegment;
- restoreStats();
+ // TODO: Re-read only the data that interests us
return true;
}
return super.onOptionsItemSelected(item);
}
- private final LocationListener locationListener = new LocationListener() {
- @Override
- public void onLocationChanged(Location l) {
- if (selectedTrackIsRecording()) {
- showLocation(l);
- }
- }
-
- @Override
- public void onProviderDisabled(String provider) {
- // Do nothing
- }
-
- @Override
- public void onProviderEnabled(String provider) {
- // Do nothing
- }
-
- @Override
- public void onStatusChanged(String provider, int status, Bundle extras) {
- // Do nothing
- }
- };
-
- /**
- * Registers to receive location updates from the GPS location provider.
- */
- private void registerLocationListener() {
- LocationManager locationManager =
- (LocationManager) getSystemService(Context.LOCATION_SERVICE);
- if (locationManager != null) {
- LocationProvider gpsProvider =
- locationManager.getProvider(MyTracksConstants.GPS_PROVIDER);
- if (gpsProvider == null) {
- Toast.makeText(this, getString(R.string.error_no_gps_location_provider),
- Toast.LENGTH_LONG).show();
- return;
- } else {
- Log.d(MyTracksConstants.TAG, "StatsActivity: Using location provider "
- + gpsProvider.getName());
- }
- locationManager.requestLocationUpdates(gpsProvider.getName(),
- 0/*minTime*/, 0/*minDist*/, locationListener);
- }
- }
-
- /**
- * Unregisters all location listener.
- */
- private void unregisterLocationListener() {
- LocationManager locationManager =
- (LocationManager) getSystemService(Context.LOCATION_SERVICE);
- if (locationManager != null) {
- locationManager.removeUpdates(locationListener);
- }
- }
-
- /**
- * @return true if the selected track is the currently recording track
- */
- private boolean selectedTrackIsRecording() {
- return MyTracks.getInstance().isRecording()
- && selectedTrackId == recordingTrackId;
- }
-
- /**
- * Reads values for selected tracks from provider and update the UI.
- */
- private void restoreStats() {
- if (selectedTrackId < 0) {
- utils.setAllToUnknown();
- return;
- }
-
- Track track = providerUtils.getTrack(selectedTrackId);
- if (track == null || track.getStatistics() == null) {
- utils.setAllToUnknown();
- return;
- }
-
- startTime = track.getStatistics().getStartTime();
- if (!selectedTrackIsRecording()) {
- utils.setTime(R.id.total_time_register,
- track.getStatistics().getTotalTime());
- }
- utils.setAllStats(track.getStatistics());
- }
-
- /**
- * Checks if this activity needs to update live track data or not.
- * If so, make sure that:
- * a) a thread keeps updating the total time
- * b) a location listener is registered
- * c) a content observer is registered
- * Otherwise unregister listeners, observers, and kill update thread.
- */
- private void checkLiveTrack() {
- final boolean isRecording = selectedTrackIsRecording();
- final boolean startThread =
- (thread == null) && isRecording && activityOnTop;
- final boolean killThread =
- (thread != null) && (!isRecording || !activityOnTop);
- if (startThread) {
- thread = new UIUpdateThread();
- thread.start();
- getContentResolver().registerContentObserver(
- TracksColumns.CONTENT_URI, false, observer);
- getContentResolver().registerContentObserver(
- WaypointsColumns.CONTENT_URI, false, observer);
- registerLocationListener();
- } else if (killThread) {
- thread.interrupt();
- thread = null;
- getContentResolver().unregisterContentObserver(observer);
- unregisterLocationListener();
- }
- }
-
- public void updateTotalTime() {
- if (selectedTrackIsRecording()) {
- utils.setTime(R.id.total_time_register,
- System.currentTimeMillis() - startTime);
- }
- }
-
/**
* Updates the given location fields (latitude, longitude, altitude) and all
* other fields.
@@ -439,4 +221,112 @@ public class StatsActivity extends Activity
utils.setUnknown(R.id.longitude_register);
utils.setUnknown(R.id.speed_register);
}
+
+ @Override
+ public void onSelectedTrackChanged(Track track, boolean isRecording) {
+ /*
+ * Checks if this activity needs to update live track data or not.
+ * If so, make sure that:
+ * a) a thread keeps updating the total time
+ * b) a location listener is registered
+ * c) a content observer is registered
+ * Otherwise unregister listeners, observers, and kill update thread.
+ */
+ final boolean startThread = (thread == null) && isRecording;
+ final boolean killThread = (thread != null) && (!isRecording);
+ if (startThread) {
+ thread = new UIUpdateThread();
+ thread.start();
+ } else if (killThread) {
+ thread.interrupt();
+ thread = null;
+ }
+
+ if (track == null || track.getStatistics() == null) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ utils.setAllToUnknown();
+ }
+ });
+ }
+ }
+
+ @Override
+ public void onCurrentLocationChanged(Location loc) {
+ if (dataHub.isRecordingSelected()) {
+ showLocation(loc);
+ }
+ }
+
+ @Override
+ public void onCurrentHeadingChanged(double heading) {
+ // We don't care.
+ }
+
+ @Override
+ public void onProviderStateChange(ProviderState state) {
+ switch (state) {
+ case DISABLED:
+ case NO_FIX:
+ showUnknownLocation();
+ break;
+ }
+ }
+
+ @Override
+ public void onTrackUpdated(final Track track) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ startTime = track.getStatistics().getStartTime();
+ if (!dataHub.isRecordingSelected()) {
+ utils.setTime(R.id.total_time_register,
+ track.getStatistics().getTotalTime());
+ showUnknownLocation();
+ }
+ utils.setAllStats(track.getStatistics());
+ }
+ });
+ }
+
+ @Override
+ public void clearWaypoints() {
+ // We don't care.
+ }
+
+ @Override
+ public void onNewWaypoint(Waypoint wpt) {
+ // We don't care.
+ }
+
+ @Override
+ public void onNewWaypointsDone() {
+ // We don't care.
+ }
+
+ @Override
+ public void clearTrackPoints() {
+ // We don't care.
+ }
+
+ @Override
+ public void onNewTrackPoint(Location loc) {
+ // We don't care.
+ }
+
+ @Override
+ public void onSegmentSplit() {
+ // We don't care.
+ }
+
+ @Override
+ public void onSampledOutTrackPoint(Location loc) {
+ // We don't care.
+ }
+
+ @Override
+ public void onNewTrackPointsDone() {
+ // We don't care.
+ }
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/StatsUtilities.java b/MyTracks/src/com/google/android/apps/mytracks/StatsUtilities.java
index c37ecab65..f6327dace 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/StatsUtilities.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/StatsUtilities.java
@@ -235,7 +235,7 @@ public class StatsUtilities {
}
public void setSpeedLabel(int id, int speedString, int paceString) {
- Log.w(MyTracksConstants.TAG, "Setting view " + id +
+ Log.w(Constants.TAG, "Setting view " + id +
" to " + reportSpeed +
" speed: " + speedString +
" pace: " + paceString);
@@ -243,7 +243,7 @@ public class StatsUtilities {
if (tv != null) {
tv.setText(reportSpeed ? speedString : paceString);
} else {
- Log.w(MyTracksConstants.TAG, "Could not find id: " + id);
+ Log.w(Constants.TAG, "Could not find id: " + id);
}
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/TrackDataHub.java b/MyTracks/src/com/google/android/apps/mytracks/TrackDataHub.java
new file mode 100644
index 000000000..d165f0e1e
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/TrackDataHub.java
@@ -0,0 +1,1011 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.android.apps.mytracks;
+
+import static com.google.android.apps.mytracks.Constants.TAG;
+
+import com.google.android.apps.mytracks.TrackDataListener.ProviderState;
+import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
+import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
+import com.google.android.apps.mytracks.content.Track;
+import com.google.android.apps.mytracks.content.TrackPointsColumns;
+import com.google.android.apps.mytracks.content.TracksColumns;
+import com.google.android.apps.mytracks.content.Waypoint;
+import com.google.android.apps.mytracks.content.WaypointsColumns;
+import com.google.android.apps.mytracks.services.TrackRecordingService;
+import com.google.android.apps.mytracks.util.ApiFeatures;
+import com.google.android.apps.mytracks.util.LocationUtils;
+import com.google.android.maps.mytracks.R;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.hardware.GeomagneticField;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.location.LocationProvider;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.Log;
+import android.widget.Toast;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * Track data hub, which receives data (both live and recorded) from many
+ * different sources and distributes it to those interested after some standard
+ * processing.
+ *
+ * @author Rodrigo Damazio
+ */
+public class TrackDataHub {
+
+ private static final long MAX_LOCATION_AGE_MS = 60 * 1000; // 1 minute
+ private static final long MAX_NETWORK_AGE_MS = 1000 * 60 * 10; // 10 minutes
+
+ // Preference keys
+ private final String SELECTED_TRACK_KEY;
+ private final String RECORDING_TRACK_KEY;
+ private final String MIN_REQUIRED_ACCURACY_KEY;
+ private final String METRIC_UNITS_KEY;
+ private final String SPEED_REPORTING_KEY;
+
+ // Application services
+ private final Context context;
+ private final MyTracksProviderUtils providerUtils;
+
+ // System services
+ private final SensorManager sensorManager;
+ private final LocationManager locationManager;
+ private final SharedPreferences sharedPreferences;
+ private final ContentResolver contentResolver;
+
+ // Internal listeners (to receive data from the system)
+ private final ContentObserver pointObserver;
+ private final ContentObserver waypointObserver;
+ private final ContentObserver trackObserver;
+ private final LocationListener locationListener;
+ private final OnSharedPreferenceChangeListener preferenceListener;
+ private final SensorEventListener compassListener;
+
+ // External listeners (to pass data to activities)
+ private final Set registeredListeners =
+ new LinkedHashSet();
+
+ // Get content notifications on the main thread, send listener callbacks in another.
+ // This ensures listener calls are serialized.
+ private final HandlerThread listenerHandlerThread;
+ private final Handler listenerHandler;
+ private boolean started;
+
+ // Cached preference values
+ private int minRequiredAccuracy;
+ private boolean useMetricUnits;
+ private boolean reportSpeed;
+
+ // Cached sensor readings
+ private float declination;
+ private long lastDeclinationUpdate;
+ private float lastSeenMagneticHeading;
+ private Location lastSeenLocation;
+ private boolean hasFix;
+ private boolean hasGoodFix;
+
+ // Transient state about the selected track
+ private long firstSeenLocationId;
+ private long lastSeenLocationId;
+ private long selectedTrackId;
+ private long recordingTrackId;
+ private int numLoadedPoints;
+ private boolean hasProviderEnabled;
+
+ /** Callback for when the tracks table is updated. */
+ private class TrackObserverCallback implements Runnable {
+ @Override
+ public void run() {
+ notifyTrackUpdated(getRegisteredListenerArray());
+ }
+ }
+
+ /** Callback for when the waypoints table is updated. */
+ private class WaypointObserverCallback implements Runnable {
+ @Override
+ public void run() {
+ notifyWaypointUpdated(getRegisteredListenerArray());
+ }
+ }
+
+ /** Callback for when the points table is updated. */
+ private class PointObserverCallback implements Runnable {
+ @Override
+ public void run() {
+ notifyPointsUpdated(true, getRegisteredListenerArray());
+ }
+ }
+
+ /** Listener for when preferences change. */
+ private class HubSharedPreferenceListener implements OnSharedPreferenceChangeListener {
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ notifyPreferenceChanged(key);
+ }
+ }
+
+ /**
+ * Generic content observer which will call a given {@link Runnable} in the
+ * given handler if the content has changed and we're recording the selected
+ * track.
+ */
+ private class TrackContentObserver extends ContentObserver {
+ private final Runnable callback;
+
+ public TrackContentObserver(Handler contentHandler, Runnable callback) {
+ super(contentHandler);
+
+ this.callback = callback;
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ Log.v(TAG, "TrackContentObserver.onChange");
+
+ // We want to filter only updates from the selected track, but since
+ // we can't see what the update is, we'll let two cases pass:
+ // 1 - The point(s) was(ere) changed because it's a recording track
+ // (and thus we care about it if the recording is the selected one)
+ // 2 - The point(s) was(ere) changed because it's syncing a track
+ // (and thus there will be no new points for the selected one)
+ if (!isRecordingSelected()) {
+ return;
+ }
+
+ // Update can potentially be lengthy, put it in its own thread:
+ listenerHandler.post(callback);
+ }
+ }
+
+ /** Listener for the current location (independent from track data). */
+ private class CurrentLocationListener implements
+ LocationListener {
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ if (!LocationManager.GPS_PROVIDER.equals(provider)) return;
+
+ hasProviderEnabled = (status == LocationProvider.AVAILABLE);
+ notifyFixType();
+ }
+
+ @Override
+ public void onProviderEnabled(String provider) {
+ if (!LocationManager.GPS_PROVIDER.equals(provider)) return;
+
+ hasProviderEnabled = true;
+ notifyFixType();
+ }
+
+ @Override
+ public void onProviderDisabled(String provider) {
+ if (!LocationManager.GPS_PROVIDER.equals(provider)) return;
+
+ hasProviderEnabled = false;
+ notifyFixType();
+ }
+
+ @Override
+ public void onLocationChanged(Location location) {
+ notifyLocationChanged(location);
+ }
+ }
+
+ /** Listener for compass readings. */
+ private class CompassListener implements
+ SensorEventListener {
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ lastSeenMagneticHeading = event.values[0];
+ maybeUpdateDeclination();
+ notifyHeadingChanged(getRegisteredListenerArray());
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // Do nothing
+ }
+ }
+
+ public TrackDataHub(Context ctx, MyTracksProviderUtils providerUtils) {
+ this.context = ctx;
+ this.providerUtils = providerUtils;
+
+ SELECTED_TRACK_KEY = context.getString(R.string.selected_track_key);
+ RECORDING_TRACK_KEY = context.getString(R.string.recording_track_key);
+ MIN_REQUIRED_ACCURACY_KEY = context.getString(R.string.min_required_accuracy_key);
+ METRIC_UNITS_KEY = context.getString(R.string.metric_units_key);
+ SPEED_REPORTING_KEY = context.getString(R.string.report_speed_key);
+
+ listenerHandlerThread = new HandlerThread("trackDataContentThread");
+ listenerHandlerThread.start();
+ listenerHandler = new Handler(listenerHandlerThread.getLooper());
+
+ sharedPreferences = ctx.getSharedPreferences(Constants.SETTINGS_NAME, 0);
+ preferenceListener = new HubSharedPreferenceListener();
+
+ sensorManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
+ locationManager =
+ (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE);
+
+ contentResolver = ctx.getContentResolver();
+ Handler contentHandler = new Handler();
+ pointObserver = new TrackContentObserver(contentHandler, new PointObserverCallback());
+ waypointObserver = new TrackContentObserver(contentHandler, new WaypointObserverCallback());
+ trackObserver = new TrackContentObserver(contentHandler, new TrackObserverCallback());
+
+ compassListener = new CompassListener();
+ locationListener = new CurrentLocationListener();
+ }
+
+ /**
+ * Starts listening to data sources and reporting the data to external
+ * listeners.
+ */
+ public void start() {
+ Log.i(TAG, "TrackDataHub.start");
+ if (started) {
+ Log.w(TAG, "Already started, ignoring");
+ return;
+ }
+ started = true;
+
+ sharedPreferences.registerOnSharedPreferenceChangeListener(preferenceListener);
+ selectedTrackId = sharedPreferences.getLong(SELECTED_TRACK_KEY, -1);
+ recordingTrackId = sharedPreferences.getLong(RECORDING_TRACK_KEY, -1);
+ useMetricUnits = sharedPreferences.getBoolean(METRIC_UNITS_KEY, true);
+ reportSpeed = sharedPreferences.getBoolean(SPEED_REPORTING_KEY, true);
+ minRequiredAccuracy = sharedPreferences.getInt(MIN_REQUIRED_ACCURACY_KEY,
+ Constants.DEFAULT_MIN_REQUIRED_ACCURACY);
+
+ if (recordingTrackId > 0) {
+ Intent startIntent = new Intent(context, TrackRecordingService.class);
+ context.startService(startIntent);
+ }
+
+ // This may or may not register internal listeners, depending on whether
+ // we already had external listeners.
+ updateInternalListeners();
+
+ // If there were listeners already registered, make sure they become up-to-date.
+ // TODO: This should really only send new data (in a start-stop-start cycle).
+ reloadDataFor(getRegisteredListenerArray());
+ }
+
+ /**
+ * Stops listening to data sources and reporting the data to external
+ * listeners.
+ */
+ public void stop() {
+ Log.i(TAG, "TrackDataHub.stop");
+ if (!started) {
+ Log.w(TAG, "Not started, ignoring");
+ return;
+ }
+
+ sharedPreferences.unregisterOnSharedPreferenceChangeListener(preferenceListener);
+
+ // Unregister internal listeners even if there are external listeners registered.
+ unregisterInternalListeners();
+
+ started = false;
+ }
+
+ /** Permanently invalidates and throws away all resources used by this class. */
+ public void destroy() {
+ if (started) {
+ throw new IllegalStateException("Can only destroy the data hub after it's been stopped");
+ }
+
+ listenerHandlerThread.quit();
+ }
+
+ /** Updates known magnetic declination if needed. */
+ private void maybeUpdateDeclination() {
+ if (lastSeenLocation == null) {
+ // We still don't know where we are.
+ return;
+ }
+
+ // Update the variation every hour
+ long now = System.currentTimeMillis();
+ if (now - lastDeclinationUpdate < 60 * 60 * 1000) {
+ return;
+ }
+
+ lastDeclinationUpdate = now;
+ long timestamp = lastSeenLocation.getTime();
+ if (timestamp == 0) {
+ // Hack for Samsung phones which don't populate the time field
+ timestamp = now;
+ }
+
+ GeomagneticField field = new GeomagneticField(
+ (float) lastSeenLocation.getLatitude(),
+ (float) lastSeenLocation.getLongitude(),
+ (float) lastSeenLocation.getAltitude(),
+ timestamp);
+ declination = field.getDeclination();
+ }
+
+ /**
+ * Forces the current location to be updated and reported to all listeners.
+ * The reported location may be from the network provider if the GPS provider
+ * is not available or doesn't have a fix.
+ */
+ public void forceUpdateLocation() {
+ checkStarted();
+
+ // TODO: Let's look at more advanced algorithms to determine the best
+ // current location.
+ if (locationManager == null) {
+ return;
+ }
+
+ final long now = System.currentTimeMillis();
+ Location loc = locationManager.getLastKnownLocation(
+ Constants.GPS_PROVIDER);
+ if (loc == null || loc.getTime() < now - MAX_LOCATION_AGE_MS) {
+ // We don't have a recent GPS fix, just use cell towers if available
+ loc = locationManager.getLastKnownLocation(
+ LocationManager.NETWORK_PROVIDER);
+ if (loc == null || loc.getTime() < now - MAX_NETWORK_AGE_MS) {
+ // We don't have a recent cell tower location, let the user know:
+ Toast.makeText(context, context.getString(R.string.status_no_location),
+ Toast.LENGTH_LONG).show();
+ return;
+ } else {
+ // Let the user know we have only an approximate location:
+ Toast.makeText(context, context.getString(R.string.status_approximate_location),
+ Toast.LENGTH_LONG).show();
+ }
+ }
+
+ notifyLocationChanged(loc, getRegisteredListenerArray());
+ }
+
+ /** Returns the ID of the currently-selected track. */
+ public long getSelectedTrackId() {
+ checkStarted();
+ return selectedTrackId;
+ }
+
+ /** Returns whether there's a track currently selected. */
+ public boolean isATrackSelected() {
+ checkStarted();
+ return selectedTrackId > 0;
+ }
+
+ /** Returns whether we're currently recording a track. */
+ public boolean isRecording() {
+ checkStarted();
+ return recordingTrackId > 0;
+ }
+
+ /** Returns whether the selected track is still being recorded. */
+ public boolean isRecordingSelected() {
+ checkStarted();
+ return isRecording() && recordingTrackId == selectedTrackId;
+ }
+
+ /**
+ * Loads the given track and makes it the currently-selected one.
+ * It is ok to call this method before {@link start}, and in that case
+ * the data will only be passed to listeners when {@link start} is called.
+ *
+ * @param trackId the ID of the track to load
+ */
+ public void loadTrack(long trackId) {
+ if (trackId == selectedTrackId) {
+ Log.w(TAG, "Not reloading track, id=" + trackId);
+ return;
+ }
+
+ // Save the selection to memory and flash.
+ ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
+ sharedPreferences.edit().putLong(SELECTED_TRACK_KEY, trackId));
+ selectedTrackId = trackId;
+
+ // Force it to reload data from the beginning.
+ firstSeenLocationId = -1;
+ lastSeenLocationId = -1;
+ numLoadedPoints = 0;
+
+ reloadDataFor(getRegisteredListenerArray());
+ }
+
+ /**
+ * Unloads the currently-selected track.
+ */
+ public void unloadCurrentTrack() {
+ loadTrack(-1);
+ }
+
+ /**
+ * Registers a listener to send data to.
+ * It is ok to call this method before {@link start}, and in that case
+ * the data will only be passed to listeners when {@link start} is called.
+ *
+ * @param listener the listener to register
+ */
+ public void registerTrackDataListener(final TrackDataListener listener) {
+ Log.d(TAG, "Registered track data listener: " + listener);
+ synchronized (registeredListeners) {
+ registeredListeners.add(listener);
+
+ // Don't load any data or start internal listeners if start() hasn't been
+ // called. When it is called, we'll do both things.
+ if (!started) return;
+
+ reloadDataFor(listener);
+ }
+
+ updateInternalListeners();
+ }
+
+ /**
+ * Unregisters a listener to send data to.
+ *
+ * @param listener the listener to unregister
+ */
+ public void unregisterTrackDataListener(TrackDataListener listener) {
+ Log.d(TAG, "Unregistered track data listener: " + listener);
+ synchronized (registeredListeners) {
+ registeredListeners.remove(listener);
+
+ // Don't load any data or start internal listeners if start() hasn't been
+ // called. When it is called, we'll do both things.
+ if (!started) return;
+ }
+ updateInternalListeners();
+ }
+
+ /** Updates the internal (sensor, position, etc) listeners. */
+ private void updateInternalListeners() {
+ boolean hasListeners;
+ synchronized (registeredListeners) {
+ hasListeners = registeredListeners.isEmpty();
+ }
+
+ if (hasListeners) {
+ unregisterInternalListeners();
+ } else {
+ registerInternalListeners();
+ }
+ }
+
+ /** Registers all internal (sensor, position, etc.) listeners. */
+ private void registerInternalListeners() {
+ // Listen to data provider
+ contentResolver.registerContentObserver(
+ TracksColumns.CONTENT_URI, false, trackObserver);
+ contentResolver.registerContentObserver(
+ WaypointsColumns.CONTENT_URI, false, waypointObserver);
+ contentResolver.registerContentObserver(
+ TrackPointsColumns.CONTENT_URI, false, pointObserver);
+
+ // Listen to compass
+ Sensor compass = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
+ if (compass != null) {
+ Log.d(Constants.TAG,
+ "TrackDataHub: Now registering sensor listeners.");
+ sensorManager.registerListener(compassListener, compass, SensorManager.SENSOR_DELAY_UI);
+ }
+
+ // Listen to GPS
+ LocationProvider gpsProvider =
+ locationManager.getProvider(Constants.GPS_PROVIDER);
+ if (gpsProvider == null) {
+ Toast.makeText(context, R.string.error_no_gps_location_provider, Toast.LENGTH_LONG).show();
+ hasProviderEnabled = false;
+ return;
+ } else {
+ Log.d(Constants.TAG, "TrackDataHub: Using location provider "
+ + gpsProvider.getName());
+ }
+ locationManager.requestLocationUpdates(gpsProvider.getName(),
+ 0 /*minTime*/, 0 /*minDist*/, locationListener);
+ hasProviderEnabled = locationManager.isProviderEnabled(Constants.GPS_PROVIDER);
+
+ // Listen to network location
+ try {
+ locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
+ 1000 * 60 * 5 /*minTime*/, 0 /*minDist*/, locationListener);
+ } catch (RuntimeException e) {
+ // If anything at all goes wrong with getting a cell location do not
+ // abort. Cell location is not essential to this app.
+ Log.w(Constants.TAG,
+ "Could not register network location listener.");
+ }
+ }
+
+ /** Unregisters all internal (sensor, position, etc.) listeners. */
+ private void unregisterInternalListeners() {
+ locationManager.removeUpdates(locationListener);
+ sensorManager.unregisterListener(compassListener);
+ contentResolver.unregisterContentObserver(trackObserver);
+ contentResolver.unregisterContentObserver(waypointObserver);
+ contentResolver.unregisterContentObserver(pointObserver);
+ }
+
+ /**
+ * Reloads all track data received so far into the specified listeners.
+ */
+ public void reloadDataFor(final TrackDataListener... listeners) {
+ if (listeners.length == 0) {
+ Log.d(TAG, "No listeners, not reloading");
+ return;
+ }
+ if (!started) {
+ Log.w(TAG, "Not started, not reloading");
+ return;
+ }
+
+ listenerHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ Track track = providerUtils.getTrack(selectedTrackId);
+
+ // Ignore the return values here, we're already sending the full data set anyway
+ for (TrackDataListener listener : listeners) {
+ listener.onUnitsChanged(useMetricUnits);
+ listener.onReportSpeedChanged(reportSpeed);
+ }
+
+ notifySelectedTrackChanged(track, listeners);
+ notifyPointsCleared(listeners);
+ notifyPointsUpdated(false, listeners);
+ notifyWaypointUpdated(listeners);
+
+ if (lastSeenLocation != null) {
+ notifyLocationChanged(lastSeenLocation, true, listeners);
+ } else {
+ notifyFixType();
+ }
+
+ notifyHeadingChanged(listeners);
+ }
+ });
+ }
+
+ /**
+ * Called when a preference changes.
+ *
+ * @param key the key to the preference that changed
+ */
+ private void notifyPreferenceChanged(String key) {
+ if (key.equals(RECORDING_TRACK_KEY)) {
+ recordingTrackId = sharedPreferences.getLong(RECORDING_TRACK_KEY, -1);
+ } else if (key.equals(MIN_REQUIRED_ACCURACY_KEY)) {
+ minRequiredAccuracy = sharedPreferences.getInt(RECORDING_TRACK_KEY,
+ Constants.DEFAULT_MIN_REQUIRED_ACCURACY);
+ } else if (key.equals(METRIC_UNITS_KEY)) {
+ useMetricUnits = sharedPreferences.getBoolean(METRIC_UNITS_KEY, true);
+ notifyUnitsChanged();
+ } else if (key.equals(SPEED_REPORTING_KEY)) {
+ reportSpeed = sharedPreferences.getBoolean(SPEED_REPORTING_KEY, true);
+ notifySpeedReportingChanged();
+ }
+ }
+
+ /** Called when the speed/pace reporting preference changes. */
+ private void notifySpeedReportingChanged() {
+ listenerHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ TrackDataListener[] listeners = getRegisteredListenerArray();
+
+ boolean reloadData = false;
+ for (TrackDataListener listener : listeners) {
+ reloadData |= listener.onReportSpeedChanged(reportSpeed);
+ }
+
+ if (reloadData) {
+ reloadDataFor(listeners);
+ }
+ }
+ });
+ }
+
+ /** Called when the metric units setting changes. */
+ private void notifyUnitsChanged() {
+ listenerHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ TrackDataListener[] listeners = getRegisteredListenerArray();
+
+ boolean reloadData = false;
+ for (TrackDataListener listener : listeners) {
+ reloadData |= listener.onUnitsChanged(useMetricUnits);
+ }
+
+ if (reloadData) {
+ reloadDataFor(listeners);
+ }
+ }
+ });
+ }
+
+ /** Notifies about the current GPS fix state. */
+ private void notifyFixType() {
+ final TrackDataListener.ProviderState state;
+ if (!hasProviderEnabled) {
+ state = ProviderState.DISABLED;
+ } else if (!hasFix) {
+ state = ProviderState.NO_FIX;
+ } else if (!hasGoodFix) {
+ state = ProviderState.BAD_FIX;
+ } else {
+ state = ProviderState.GOOD_FIX;
+ }
+
+ listenerHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ for (TrackDataListener listener : registeredListeners) {
+ listener.onProviderStateChange(state);
+ }
+ }
+ });
+ }
+
+ /**
+ * Notifies the the current location has changed, without any filtering.
+ * If the state of GPS fix has changed, that will also be reported.
+ *
+ * @param location the current location
+ * @param listeners the listeners to notify
+ */
+ private void notifyLocationChanged(Location location, TrackDataListener... listeners) {
+ notifyLocationChanged(location, false, listeners);
+ }
+
+ /**
+ * Notifies that the current location has changed, without any filtering.
+ * If the state of GPS fix has changed, that will also be reported.
+ *
+ * @param location the current location
+ * @param forceUpdate whether to force the notifications to happen
+ * @param listeners the listeners to notify
+ */
+ private void notifyLocationChanged(final Location location, boolean forceUpdate, final TrackDataListener... listeners) {
+ if (location == null) return;
+
+ boolean isGpsLocation = location.getProvider().equals(LocationManager.GPS_PROVIDER);
+
+ boolean oldHasFix = hasFix;
+ boolean oldHasGoodFix = hasGoodFix;
+
+ // We consider a good fix to be a recent one with reasonable accuracy.
+ if (isGpsLocation) {
+ lastSeenLocation = location;
+ hasFix = (location != null && System.currentTimeMillis() - location.getTime() <= MAX_LOCATION_AGE_MS);
+ hasGoodFix = (location != null && location.getAccuracy() <= minRequiredAccuracy);
+ if (hasFix != oldHasFix || hasGoodFix != oldHasGoodFix || forceUpdate) {
+ notifyFixType();
+ }
+ }
+
+ listenerHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ for (TrackDataListener listener : listeners) {
+ listener.onCurrentLocationChanged(location);
+ }
+ }
+ });
+ }
+
+ /**
+ * Notifies that the current heading has changed.
+ *
+ * @param listeners the listeners to notify
+ */
+ private void notifyHeadingChanged(final TrackDataListener... listeners) {
+ listenerHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ for (TrackDataListener listener : listeners) {
+ listener.onCurrentHeadingChanged(lastSeenMagneticHeading + declination);
+ }
+ }
+ });
+ }
+
+ /**
+ * Notifies that a new track has been selected..
+ *
+ * @param track the new selected track
+ * @param listeners the listeners to notify
+ */
+ private void notifySelectedTrackChanged(final Track track, final TrackDataListener... listeners) {
+ Log.d(TAG, "New track selected, id=" + (track != null ? track.getId() : "none"));
+
+ listenerHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ for (TrackDataListener listener : listeners) {
+ listener.onSelectedTrackChanged(track, isRecordingSelected());
+
+ if (track != null) {
+ listener.onTrackUpdated(track);
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Notifies that the currently-selected track's data has been updated.
+ *
+ * @param listeners the listeners to notify
+ */
+ private void notifyTrackUpdated(final TrackDataListener... listeners) {
+ final Track track = providerUtils.getTrack(selectedTrackId);
+
+ listenerHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ for (TrackDataListener listener : registeredListeners) {
+ listener.onTrackUpdated(track);
+ }
+ }
+ });
+ }
+
+ /**
+ * Notifies that waypoints have been updated.
+ * We assume few waypoints, so we reload them all every time.
+ *
+ * @param listeners the listeners to notify
+ */
+ private void notifyWaypointUpdated(final TrackDataListener... listeners) {
+ // Always reload all the waypoints.
+ final Cursor cursor = providerUtils.getWaypointsCursor(
+ selectedTrackId, 0, Constants.MAX_DISPLAYED_WAYPOINTS_POINTS);
+
+ listenerHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ for (TrackDataListener listener : registeredListeners) {
+ listener.clearWaypoints();
+ }
+
+ try {
+ if (cursor != null && cursor.moveToFirst()) {
+ do {
+ Waypoint waypoint = providerUtils.createWaypoint(cursor);
+ if (!LocationUtils.isValidLocation(waypoint.getLocation())) {
+ continue;
+ }
+
+ for (TrackDataListener listener : listeners) {
+ listener.onNewWaypoint(waypoint);
+ }
+ } while (cursor.moveToNext());
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+
+ for (TrackDataListener listener : listeners) {
+ listener.onNewWaypointsDone();
+ }
+ }
+ });
+ }
+
+ /**
+ * Tells listeners to clear the current list of points.
+ *
+ * @param listeners the listeners to notify
+ */
+ private void notifyPointsCleared(final TrackDataListener... listeners) {
+ listenerHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ for (TrackDataListener listener : listeners) {
+ listener.clearTrackPoints();
+ }
+ }
+ });
+ }
+
+ /**
+ * Notifies the given listeners about track points in the given ID range.
+ *
+ * @param minPointId the first point ID to notify, inclusive
+ * @param maxPointId the last poind ID to notify, inclusive
+ * @param keepState whether to load and save state about the already-notified points.
+ * If true, only new points are reported.
+ * If false, then the whole track will be loaded, without affecting the store.
+ * @param listeners the listeners to notify
+ */
+ private void notifyPointsUpdated(final boolean keepState, final TrackDataListener... listeners) {
+ listenerHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ notifyPointsUpdatedSync(keepState, listeners);
+ }
+ });
+ }
+
+ /**
+ * Asynchronous version of the above method.
+ */
+ private void notifyPointsUpdatedSync(boolean keepState, TrackDataListener[] listeners) {
+ // If we're loading state, start from after the last seen point up to the last recorded one
+ // (all new points)
+ // If we're not loading state, then notify about all the previously-seen points.
+ long minPointId = keepState ? lastSeenLocationId + 1 : 0;
+ long maxPointId = keepState ? -1 : lastSeenLocationId;
+
+ if (numLoadedPoints >= Constants.MAX_DISPLAYED_TRACK_POINTS) {
+ // We're about to exceed the maximum allowed number of points, so reload
+ // the whole track with fewer points (the sampling frequency will be
+ // lower). We do this for every listener even if we were loading just for
+ // a few of them (why miss the oportunity?).
+
+ firstSeenLocationId = -1;
+ lastSeenLocationId = -1;
+ numLoadedPoints = 0;
+ listeners = getRegisteredListenerArray();
+ maxPointId = -1;
+ minPointId = 0;
+ keepState = true;
+
+ for (TrackDataListener listener : listeners) {
+ listener.clearTrackPoints();
+ }
+ }
+
+ // Keep the originally selected track ID so we can stop if it changes.
+ long currentSelectedTrackId = selectedTrackId;
+
+ // If we're ignoring state, start from the beginning of the track
+ int localNumLoadedPoints = keepState ? numLoadedPoints : 0;
+ long localFirstSeenLocationId = keepState ? firstSeenLocationId : 0;
+ long localLastSeenLocationId = minPointId;
+ long lastStoredLocationId = providerUtils.getLastLocationId(currentSelectedTrackId);
+ int pointSamplingFrequency = -1;
+
+ // Create a double-buffering location provider.
+ MyTracksProviderUtils.DoubleBufferedLocationFactory locationFactory =
+ new MyTracksProviderUtils.DoubleBufferedLocationFactory();
+ LocationIterator it = providerUtils.getLocationIterator(
+ currentSelectedTrackId, minPointId, false, locationFactory);
+
+ while (it.hasNext()) {
+ if (currentSelectedTrackId != selectedTrackId) {
+ // The selected track changed beneath us, stop.
+ break;
+ }
+
+ Location location = it.next();
+ long locationId = it.getLocationId();
+
+ // If past the last wanted point, stop.
+ // This happens when adding a new listener after data has already been loaded,
+ // in which case we only want to bring that listener up to the point where the others
+ // were. In case it does happen, we should be wasting few points (only the ones not
+ // yet notified to other listeners).
+ if (maxPointId > 0 && locationId > maxPointId) {
+ break;
+ }
+
+ if (localFirstSeenLocationId == -1) {
+ // This was our first point, keep its ID
+ localFirstSeenLocationId = locationId;
+ }
+
+ if (pointSamplingFrequency == -1) {
+ // Now we already have at least one point, calculate the sampling
+ // frequency.
+ long numTotalPoints = lastStoredLocationId - localFirstSeenLocationId;
+ pointSamplingFrequency =
+ (int) (1 + numTotalPoints / Constants.TARGET_DISPLAYED_TRACK_POINTS);
+ }
+
+ notifyNewPoint(location, locationId, lastStoredLocationId,
+ localNumLoadedPoints, pointSamplingFrequency, listeners);
+
+ localNumLoadedPoints++;
+ localLastSeenLocationId = locationId;
+ }
+ it.close();
+
+ if (keepState) {
+ numLoadedPoints = localNumLoadedPoints;
+ firstSeenLocationId = localFirstSeenLocationId;
+ lastSeenLocationId = localLastSeenLocationId;
+ }
+
+ for (TrackDataListener listener : listeners) {
+ listener.onNewTrackPointsDone();
+ }
+ }
+
+ private void notifyNewPoint(Location location,
+ long locationId,
+ long lastStoredLocationId,
+ int numLoadedPoints,
+ int pointSamplingFrequency,
+ TrackDataListener[] listeners) {
+ boolean isValid = LocationUtils.isValidLocation(location);
+ if (!isValid) {
+ // Invalid points are segment splits - report those separately.
+ // TODO: Always send last valid point before and first valid point after a split
+ for (TrackDataListener listener : listeners) {
+ listener.onSegmentSplit();
+ }
+ return;
+ }
+
+ // Include a point if it fits one of the following criteria:
+ // - Has the mod for the sampling frequency (includes first point).
+ // - Is the last point and we are not recording this track.
+ boolean includeInSample =
+ (numLoadedPoints % pointSamplingFrequency == 0 ||
+ (!isRecordingSelected() && locationId == lastStoredLocationId));
+
+ if (!includeInSample) {
+ for (TrackDataListener listener : listeners) {
+ listener.onSampledOutTrackPoint(location);
+ }
+ return;
+ }
+
+ // Point is valid and included in sample.
+ for (TrackDataListener listener : listeners) {
+ // No need to allocate a new location (we can safely reuse the existing).
+ listener.onNewTrackPoint(location);
+ }
+ }
+
+ /** Returns an array with all the currently-registered listeners. */
+ private TrackDataListener[] getRegisteredListenerArray() {
+ synchronized (registeredListeners) {
+ TrackDataListener listenerArray[] = new TrackDataListener[registeredListeners.size()];
+ return registeredListeners.toArray(listenerArray);
+ }
+ }
+
+ /** Verifies that {@link #start} has been called. */
+ private void checkStarted() {
+ if (!started) {
+ throw new IllegalStateException("TrackDataHub has not been started.");
+ }
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/TrackDataListener.java b/MyTracks/src/com/google/android/apps/mytracks/TrackDataListener.java
new file mode 100644
index 000000000..96c79ae5c
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/TrackDataListener.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.android.apps.mytracks;
+
+import com.google.android.apps.mytracks.content.Track;
+import com.google.android.apps.mytracks.content.Waypoint;
+
+import android.location.Location;
+
+/**
+ * Listener for track data, for both initial and incremental loading.
+ *
+ * TODO: Allow listening to just part of the data received here.
+ *
+ * @author Rodrigo Damazio
+ */
+public interface TrackDataListener {
+
+ /** States for the GPS location provider. */
+ public enum ProviderState {
+ DISABLED,
+ NO_FIX,
+ BAD_FIX,
+ GOOD_FIX;
+ }
+
+ /**
+ * Called when the location provider changes state.
+ */
+ void onProviderStateChange(ProviderState state);
+
+ /**
+ * Called when the current location changes.
+ * This is meant for immediate location display only - track point data is
+ * delivered by other methods below, such as {@link #onNewTrackPoint}.
+ *
+ * @param loc the last known location
+ */
+ void onCurrentLocationChanged(Location loc);
+
+ /**
+ * Called when the current heading changes.
+ *
+ * @param heading the current heading, already accounting magnetic declination
+ */
+ void onCurrentHeadingChanged(double heading);
+
+ // This is always followed by calls to onTrackUpdated/onNewTrackPoints/onWaypointsChanged
+ // The recipient has a chance to unregister here before that happens.
+
+ /**
+ * Called when the currently-selected track changes.
+ * This will be followed by calls to data methods such as
+ * {@link #onTrackUpdated}, {@link #clearTrackPoints},
+ * {@link #onNewTrackPoint(Location)}, etc., even if no track is currently
+ * selected (in which case you'll only get calls to clear the current data).
+ *
+ * @param track the selected track, or null if no track is selected
+ * @param isRecording whether we're currently recording the selected track
+ */
+ void onSelectedTrackChanged(Track track, boolean isRecording);
+
+ // Called when the already-selected track gets updated
+
+ /**
+ * Called when the track and/or its statistics have been updated.
+ *
+ * @param track the updated version of the track
+ */
+ void onTrackUpdated(Track track);
+
+ // Map, chart - points, waypoints
+ // Stats - track
+ // Points are loaded progressively in batches
+ // Track is always loaded
+ // Waypoints are always fully loaded (limit to MyTracksConstants.MAX_DISPLAYED_WAYPOINTS_POINTS)
+
+
+ // Initial load - clear + N * onNewTrackPoint + onNewTrackPointsDone
+ // New points - onNewTrackPoint + onNewTrackPointsDone
+ // Points passed in are already sampled (but can be invalid to denote a split)
+ // If needs to resample, repeats initial load
+
+ /**
+ * Called to clear any previously-sent track points.
+ * This can be called at any time that we decide the data needs to be
+ * reloaded, such as when it needs to be resampled.
+ */
+ void clearTrackPoints();
+
+ /**
+ * Called when a new interesting track point is read.
+ * In this case, interesting means that the point has already undergone
+ * sampling and invalid point filtering.
+ *
+ * @param loc the new track point
+ */
+ void onNewTrackPoint(Location loc);
+
+ /**
+ * Called when a uninteresting track point is read.
+ * Uninteresting points are all points that get sampled out of the track.
+ *
+ * @param loc the new track point
+ */
+ void onSampledOutTrackPoint(Location loc);
+
+ /**
+ * Called when an invalid point (representing a segment split) is read.
+ */
+ void onSegmentSplit();
+
+ /**
+ * Called when we're done (for the time being) sending new points.
+ * This gets called after every batch of calls to {@link #onNewTrackPoint},
+ * {@link #onSampledOutTrackPoint} and {@link #onSegmentSplit}.
+ */
+ void onNewTrackPointsDone();
+
+ /**
+ * Called to clear any previously-sent waypoints.
+ * This can be called at any time that we decide the data needs to be
+ * reloaded.
+ */
+ void clearWaypoints();
+
+ /**
+ * Called when a new waypoint is read.
+ *
+ * @param wpt the new waypoint
+ */
+ void onNewWaypoint(Waypoint wpt);
+
+ /**
+ * Called when we're done (for the time being) sending new waypoints.
+ * This gets called after every batch of calls to {@link #clearWaypoints} and
+ * {@link #onNewWaypoint}.
+ */
+ void onNewWaypointsDone();
+
+ /**
+ * Called when the display units are changed by the user.
+ *
+ * @param metric true if the units are metric, false if imperial
+ * @return true to reload all the data, false otherwise
+ */
+ boolean onUnitsChanged(boolean metric);
+
+ /**
+ * Called when the speed/pace display unit is changed by the user.
+ *
+ * @param reportSpeed true to report speed, false for pace
+ * @return true to reload all the data, false otherwise
+ */
+ boolean onReportSpeedChanged(boolean reportSpeed);
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracksDetails.java b/MyTracks/src/com/google/android/apps/mytracks/TrackDetails.java
similarity index 97%
rename from MyTracks/src/com/google/android/apps/mytracks/MyTracksDetails.java
rename to MyTracks/src/com/google/android/apps/mytracks/TrackDetails.java
index 47d387d37..fcdd4dfa0 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracksDetails.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/TrackDetails.java
@@ -37,7 +37,7 @@ import android.widget.EditText;
*
* @author Leif Hendrik Wilden
*/
-public class MyTracksDetails extends Activity implements OnClickListener {
+public class TrackDetails extends Activity implements OnClickListener {
/**
* The id of the track being edited (taken from bundle, "trackid")
@@ -56,7 +56,7 @@ public class MyTracksDetails extends Activity implements OnClickListener {
// Required extra when launching this intent:
trackId = getIntent().getLongExtra("trackid", -1);
if (trackId < 0) {
- Log.d(MyTracksConstants.TAG,
+ Log.d(Constants.TAG,
"MyTracksDetails intent was launched w/o track id.");
finish();
return;
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracksList.java b/MyTracks/src/com/google/android/apps/mytracks/TrackList.java
similarity index 84%
rename from MyTracks/src/com/google/android/apps/mytracks/MyTracksList.java
rename to MyTracks/src/com/google/android/apps/mytracks/TrackList.java
index ad424e530..990062836 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracksList.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/TrackList.java
@@ -45,7 +45,7 @@ import android.widget.TextView;
*
* @author Leif Hendrik Wilden
*/
-public class MyTracksList extends ListActivity
+public class TrackList extends ListActivity
implements SharedPreferences.OnSharedPreferenceChangeListener,
View.OnClickListener {
@@ -70,40 +70,40 @@ public class MyTracksList extends ListActivity
AdapterView.AdapterContextMenuInfo info =
(AdapterView.AdapterContextMenuInfo) menuInfo;
contextPosition = info.position;
- trackId = MyTracksList.this.listView.getAdapter().getItemId(
+ trackId = TrackList.this.listView.getAdapter().getItemId(
contextPosition);
- menu.add(0, MyTracksConstants.MENU_SHOW, 0,
+ menu.add(0, Constants.MENU_SHOW, 0,
R.string.tracklist_show_track);
- menu.add(0, MyTracksConstants.MENU_EDIT, 0,
+ menu.add(0, Constants.MENU_EDIT, 0,
R.string.tracklist_edit_track);
if (!MyTracks.getInstance().isRecording()
|| trackId != recordingTrackId) {
- menu.add(0, MyTracksConstants.MENU_SEND_TO_GOOGLE, 0,
+ menu.add(0, Constants.MENU_SEND_TO_GOOGLE, 0,
R.string.tracklist_send_to_google);
- SubMenu share = menu.addSubMenu(0, MyTracksConstants.MENU_SHARE, 0,
+ SubMenu share = menu.addSubMenu(0, Constants.MENU_SHARE, 0,
R.string.tracklist_share_track);
- share.add(0, MyTracksConstants.MENU_SHARE_LINK, 0,
+ share.add(0, Constants.MENU_SHARE_LINK, 0,
R.string.tracklist_share_link);
- share.add(0, MyTracksConstants.MENU_SHARE_GPX_FILE, 0,
+ share.add(0, Constants.MENU_SHARE_GPX_FILE, 0,
R.string.tracklist_share_gpx_file);
- share.add(0, MyTracksConstants.MENU_SHARE_KML_FILE, 0,
+ share.add(0, Constants.MENU_SHARE_KML_FILE, 0,
R.string.tracklist_share_kml_file);
- share.add(0, MyTracksConstants.MENU_SHARE_CSV_FILE, 0,
+ share.add(0, Constants.MENU_SHARE_CSV_FILE, 0,
R.string.tracklist_share_csv_file);
- share.add(0, MyTracksConstants.MENU_SHARE_TCX_FILE, 0,
+ share.add(0, Constants.MENU_SHARE_TCX_FILE, 0,
R.string.tracklist_share_tcx_file);
SubMenu save = menu.addSubMenu(0,
- MyTracksConstants.MENU_WRITE_TO_SD_CARD, 0,
+ Constants.MENU_WRITE_TO_SD_CARD, 0,
R.string.tracklist_write_to_sd);
- save.add(0, MyTracksConstants.MENU_SAVE_GPX_FILE, 0,
+ save.add(0, Constants.MENU_SAVE_GPX_FILE, 0,
R.string.tracklist_save_as_gpx);
- save.add(0, MyTracksConstants.MENU_SAVE_KML_FILE, 0,
+ save.add(0, Constants.MENU_SAVE_KML_FILE, 0,
R.string.tracklist_save_as_kml);
- save.add(0, MyTracksConstants.MENU_SAVE_CSV_FILE, 0,
+ save.add(0, Constants.MENU_SAVE_CSV_FILE, 0,
R.string.tracklist_save_as_csv);
- save.add(0, MyTracksConstants.MENU_SAVE_TCX_FILE, 0,
+ save.add(0, Constants.MENU_SAVE_TCX_FILE, 0,
R.string.tracklist_save_as_tcx);
- menu.add(0, MyTracksConstants.MENU_DELETE, 0,
+ menu.add(0, Constants.MENU_DELETE, 0,
R.string.tracklist_delete_track);
}
}
@@ -132,7 +132,7 @@ public class MyTracksList extends ListActivity
protected void onListItemClick(ListView l, View v, int position, long id) {
Intent result = new Intent();
result.putExtra("trackid", id);
- setResult(MyTracksConstants.SHOW_TRACK, result);
+ setResult(Constants.SHOW_TRACK, result);
finish();
}
@@ -140,24 +140,24 @@ public class MyTracksList extends ListActivity
public boolean onMenuItemSelected(int featureId, MenuItem item) {
if (!super.onMenuItemSelected(featureId, item)) {
switch (item.getItemId()) {
- case MyTracksConstants.MENU_SHOW: {
+ case Constants.MENU_SHOW: {
onListItemClick(null, null, 0, trackId);
return true;
}
- case MyTracksConstants.MENU_EDIT: {
- Intent intent = new Intent(this, MyTracksDetails.class);
+ case Constants.MENU_EDIT: {
+ Intent intent = new Intent(this, TrackDetails.class);
intent.putExtra("trackid", trackId);
startActivity(intent);
return true;
}
- case MyTracksConstants.MENU_SHARE:
- case MyTracksConstants.MENU_WRITE_TO_SD_CARD:
+ case Constants.MENU_SHARE:
+ case Constants.MENU_WRITE_TO_SD_CARD:
return false;
default: {
Intent result = new Intent();
result.putExtra("trackid", trackId);
setResult(
- MyTracksConstants.getActionFromMenuId(item.getItemId()), result);
+ Constants.getActionFromMenuId(item.getItemId()), result);
finish();
return true;
}
@@ -170,7 +170,7 @@ public class MyTracksList extends ListActivity
public void onClick(View v) {
switch (v.getId()) {
case R.id.tracklist_btn_delete_all: {
- Handler h = new MyTracksDeleteAllTracks(this, null);
+ Handler h = new DeleteAllTracks(this, null);
h.handleMessage(null);
break;
}
@@ -202,7 +202,7 @@ public class MyTracksList extends ListActivity
findViewById(R.id.tracklist_btn_import_all).setOnClickListener(this);
SharedPreferences preferences =
- getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
+ getSharedPreferences(Constants.SETTINGS_NAME, 0);
preferences.registerOnSharedPreferenceChangeListener(this);
metricUnits =
preferences.getBoolean(getString(R.string.metric_units_key), true);
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracksWaypointDetails.java b/MyTracks/src/com/google/android/apps/mytracks/WaypointDetails.java
similarity index 97%
rename from MyTracks/src/com/google/android/apps/mytracks/MyTracksWaypointDetails.java
rename to MyTracks/src/com/google/android/apps/mytracks/WaypointDetails.java
index 5e9f110b7..a4a32436d 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracksWaypointDetails.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/WaypointDetails.java
@@ -39,7 +39,7 @@ import android.widget.ImageView;
*
* @author Leif Hendrik Wilden
*/
-public class MyTracksWaypointDetails extends Activity
+public class WaypointDetails extends Activity
implements OnClickListener {
public static final String WAYPOINT_ID_EXTRA = "com.google.android.apps.mytracks.WAYPOINT_ID";
@@ -65,7 +65,7 @@ public class MyTracksWaypointDetails extends Activity
utils = new StatsUtilities(this);
SharedPreferences preferences =
- getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
+ getSharedPreferences(Constants.SETTINGS_NAME, 0);
if (preferences != null) {
boolean useMetric =
preferences.getBoolean(getString(R.string.metric_units_key), true);
@@ -82,7 +82,7 @@ public class MyTracksWaypointDetails extends Activity
// Required extra when launching this intent:
waypointId = getIntent().getLongExtra(WAYPOINT_ID_EXTRA, -1);
if (waypointId < 0) {
- Log.d(MyTracksConstants.TAG,
+ Log.d(Constants.TAG,
"MyTracksWaypointsDetails intent was launched w/o waypoint id.");
finish();
return;
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracksWaypointsList.java b/MyTracks/src/com/google/android/apps/mytracks/WaypointsList.java
similarity index 88%
rename from MyTracks/src/com/google/android/apps/mytracks/MyTracksWaypointsList.java
rename to MyTracks/src/com/google/android/apps/mytracks/WaypointsList.java
index f3c151169..cbaad0481 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracksWaypointsList.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/WaypointsList.java
@@ -49,7 +49,7 @@ import android.widget.TextView;
*
* @author Leif Hendrik Wilden
*/
-public class MyTracksWaypointsList extends ListActivity
+public class WaypointsList extends ListActivity
implements View.OnClickListener {
private int contextPosition = -1;
@@ -59,7 +59,6 @@ public class MyTracksWaypointsList extends ListActivity
private Button insertWaypointButton = null;
private Button insertStatisticsButton = null;
private long recordingTrackId = -1;
- private long selectedTrackId = -1;
private MyTracksProviderUtils providerUtils;
private Cursor waypointsCursor = null;
@@ -72,14 +71,14 @@ public class MyTracksWaypointsList extends ListActivity
AdapterView.AdapterContextMenuInfo info =
(AdapterView.AdapterContextMenuInfo) menuInfo;
contextPosition = info.position;
- waypointId = MyTracksWaypointsList.this.listView.getAdapter()
+ waypointId = WaypointsList.this.listView.getAdapter()
.getItemId(contextPosition);
int type = providerUtils.getWaypoint(info.id).getType();
- menu.add(0, MyTracksConstants.MENU_SHOW, 0,
+ menu.add(0, Constants.MENU_SHOW, 0,
R.string.waypointslist_show_waypoint);
- menu.add(0, MyTracksConstants.MENU_EDIT, 0,
+ menu.add(0, Constants.MENU_EDIT, 0,
R.string.waypointslist_edit_waypoint);
- menu.add(0, MyTracksConstants.MENU_DELETE, 0,
+ menu.add(0, Constants.MENU_DELETE, 0,
R.string.waypointslist_delete_waypoint).setEnabled(
recordingTrackId < 0 || type == Waypoint.TYPE_WAYPOINT ||
info.id != providerUtils.getLastWaypointId(recordingTrackId));
@@ -90,8 +89,8 @@ public class MyTracksWaypointsList extends ListActivity
protected void onListItemClick(ListView l, View v, int position, long id) {
Intent result = new Intent();
result.putExtra("trackid", trackId);
- result.putExtra(MyTracksWaypointDetails.WAYPOINT_ID_EXTRA, id);
- setResult(MyTracksConstants.EDIT_WAYPOINT, result);
+ result.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, id);
+ setResult(Constants.EDIT_WAYPOINT, result);
finish();
}
@@ -99,18 +98,18 @@ public class MyTracksWaypointsList extends ListActivity
public boolean onMenuItemSelected(int featureId, MenuItem item) {
if (!super.onMenuItemSelected(featureId, item)) {
switch (item.getItemId()) {
- case MyTracksConstants.MENU_SHOW: {
+ case Constants.MENU_SHOW: {
onListItemClick(null, null, 0, waypointId);
return true;
}
- case MyTracksConstants.MENU_EDIT: {
- Intent intent = new Intent(this, MyTracksWaypointDetails.class);
+ case Constants.MENU_EDIT: {
+ Intent intent = new Intent(this, WaypointDetails.class);
intent.putExtra("trackid", trackId);
- intent.putExtra(MyTracksWaypointDetails.WAYPOINT_ID_EXTRA, waypointId);
+ intent.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, waypointId);
startActivity(intent);
return true;
}
- case MyTracksConstants.MENU_DELETE: {
+ case Constants.MENU_DELETE: {
deleteWaypoint(waypointId);
}
}
@@ -139,7 +138,10 @@ public class MyTracksWaypointsList extends ListActivity
(Button) findViewById(R.id.waypointslist_btn_insert_statistics);
insertStatisticsButton.setOnClickListener(this);
SharedPreferences preferences =
- getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
+ getSharedPreferences(Constants.SETTINGS_NAME, 0);
+
+ // TODO: Get rid of selected and recording track IDs
+ long selectedTrackId = -1;
if (preferences != null) {
recordingTrackId =
preferences.getLong(getString(R.string.recording_track_key), -1);
@@ -183,18 +185,18 @@ public class MyTracksWaypointsList extends ListActivity
try {
id = MyTracks.getInstance().insertWaypoint(request);
} catch (RemoteException e) {
- Log.e(MyTracksConstants.TAG, "Cannot insert marker.", e);
+ Log.e(Constants.TAG, "Cannot insert marker.", e);
return;
} catch (IllegalStateException e) {
- Log.e(MyTracksConstants.TAG, "Cannot insert marker.", e);
+ Log.e(Constants.TAG, "Cannot insert marker.", e);
return;
}
if (id < 0) {
- Log.e(MyTracksConstants.TAG, "Failed to insert marker.");
+ Log.e(Constants.TAG, "Failed to insert marker.");
return;
}
- Intent intent = new Intent(this, MyTracksWaypointDetails.class);
- intent.putExtra(MyTracksWaypointDetails.WAYPOINT_ID_EXTRA, id);
+ Intent intent = new Intent(this, WaypointDetails.class);
+ intent.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, id);
startActivity(intent);
}
@@ -259,7 +261,7 @@ public class MyTracksWaypointsList extends ListActivity
public void onClick(DialogInterface dialog, int i) {
dialog.dismiss();
providerUtils.deleteWaypoint(waypointId,
- new StringUtils(MyTracksWaypointsList.this));
+ new StringUtils(WaypointsList.this));
}
});
builder.setNegativeButton(getString(R.string.no),
diff --git a/MyTracks/src/com/google/android/apps/mytracks/WelcomeActivity.java b/MyTracks/src/com/google/android/apps/mytracks/WelcomeActivity.java
index 45251a3b7..113253c5c 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/WelcomeActivity.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/WelcomeActivity.java
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks;
-import com.google.android.apps.mytracks.util.MyTracksUtils;
+import com.google.android.apps.mytracks.util.SystemUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
@@ -82,6 +82,6 @@ public class WelcomeActivity extends Activity {
AlertDialog dialog = builder.create();
dialog.show();
((TextView) dialog.findViewById(R.id.about_version_register)).
- setText(MyTracksUtils.getMyTracksVersion(this));
+ setText(SystemUtils.getMyTracksVersion(this));
}
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/content/MyTracksProvider.java b/MyTracks/src/com/google/android/apps/mytracks/content/MyTracksProvider.java
index e1c26901a..7c437a172 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/content/MyTracksProvider.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/content/MyTracksProvider.java
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.content;
-import com.google.android.apps.mytracks.MyTracksConstants;
+import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.util.ApiFeatures;
import android.content.ContentProvider;
@@ -382,7 +382,7 @@ public class MyTracksProvider extends ContentProvider {
}
if (ApiFeatures.getInstance().canReuseSQLiteQueryBuilder()) {
- Log.i(MyTracksConstants.TAG,
+ Log.i(Constants.TAG,
"Build query: " + qb.buildQuery(projection, selection, selectionArgs,
null, null, sortOrder, null));
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/AuthManagerFactory.java b/MyTracks/src/com/google/android/apps/mytracks/io/AuthManagerFactory.java
index d701a530c..8532e807d 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/AuthManagerFactory.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/AuthManagerFactory.java
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.io;
-import com.google.android.apps.mytracks.MyTracksConstants;
+import com.google.android.apps.mytracks.Constants;
import android.app.Activity;
import android.os.Build;
@@ -46,11 +46,11 @@ public class AuthManagerFactory {
public static AuthManager getAuthManager(Activity activity, int code,
Bundle extras, boolean requireGoogle, String service) {
if (useModernAuthManager()) {
- Log.i(MyTracksConstants.TAG,
+ Log.i(Constants.TAG,
"Creating modern auth manager: " + service);
return new ModernAuthManager(activity, code, extras, requireGoogle, service);
} else {
- Log.i(MyTracksConstants.TAG,
+ Log.i(Constants.TAG,
"Creating legacy auth manager: " + service);
return new AuthManagerOld(activity, code, extras, requireGoogle, service);
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/GpxImporter.java b/MyTracks/src/com/google/android/apps/mytracks/io/GpxImporter.java
index 02f5af832..45586faa6 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/GpxImporter.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/GpxImporter.java
@@ -15,11 +15,11 @@
*/
package com.google.android.apps.mytracks.io;
-import com.google.android.apps.mytracks.MyTracksConstants;
+import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
-import com.google.android.apps.mytracks.util.MyTracksUtils;
+import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import android.location.Location;
@@ -174,7 +174,7 @@ public class GpxImporter extends DefaultHandler {
parser.parse(is, handler);
long end = System.currentTimeMillis();
- Log.d(MyTracksConstants.TAG, "Total import time: " + (end - start) + "ms");
+ Log.d(Constants.TAG, "Total import time: " + (end - start) + "ms");
trackIds = handler.getImportedTrackIds();
} finally {
@@ -362,7 +362,7 @@ public class GpxImporter extends DefaultHandler {
* @throws SAXException - thrown if track point is invalid
*/
private void onTrackPointElementEnd() throws SAXException {
- if (MyTracksUtils.isValidLocation(location)) {
+ if (LocationUtils.isValidLocation(location)) {
if (statsBuilder == null) {
// first point did not have a time, start stats builder without it
statsBuilder = new TripStatisticsBuilder(0);
@@ -462,7 +462,7 @@ public class GpxImporter extends DefaultHandler {
// check for negative time change
if (timeDifference < 0) {
- Log.w(MyTracksConstants.TAG, "Found negative time change.");
+ Log.w(Constants.TAG, "Found negative time change.");
} else {
// We don't have a speed and bearing in GPX, make something up from
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/ModernAuthManager.java b/MyTracks/src/com/google/android/apps/mytracks/io/ModernAuthManager.java
index 511584541..24c721bc4 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/ModernAuthManager.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/ModernAuthManager.java
@@ -23,7 +23,7 @@ import com.google.android.accounts.AuthenticatorException;
import com.google.android.accounts.OperationCanceledException;
import com.google.android.apps.mytracks.AccountChooser;
import com.google.android.apps.mytracks.MyTracks;
-import com.google.android.apps.mytracks.MyTracksConstants;
+import com.google.android.apps.mytracks.Constants;
import android.app.Activity;
import android.content.Intent;
@@ -104,20 +104,20 @@ public class ModernAuthManager implements AuthManager {
if (result.containsKey(AccountManager.KEY_INTENT)) {
Intent intent = (Intent) result.get(AccountManager.KEY_INTENT);
clearNewTaskFlag(intent);
- activity.startActivityForResult(intent, MyTracksConstants.GET_LOGIN);
+ activity.startActivityForResult(intent, Constants.GET_LOGIN);
return;
}
authToken = result.getString(
AccountManager.KEY_AUTHTOKEN);
- Log.e(MyTracksConstants.TAG, "Got auth token.");
+ Log.e(Constants.TAG, "Got auth token.");
runWhenFinished();
} catch (OperationCanceledException e) {
- Log.e(MyTracksConstants.TAG, "Operation Canceled", e);
+ Log.e(Constants.TAG, "Operation Canceled", e);
} catch (IOException e) {
- Log.e(MyTracksConstants.TAG, "IOException", e);
+ Log.e(Constants.TAG, "IOException", e);
} catch (AuthenticatorException e) {
- Log.e(MyTracksConstants.TAG, "Authentication Failed", e);
+ Log.e(Constants.TAG, "Authentication Failed", e);
}
}
}, null /* handler */);
@@ -149,9 +149,9 @@ public class ModernAuthManager implements AuthManager {
if (results != null) {
authToken = results.getStringExtra(
AccountManager.KEY_AUTHTOKEN);
- Log.w(MyTracksConstants.TAG, "authResult: " + authToken);
+ Log.w(Constants.TAG, "authResult: " + authToken);
} else {
- Log.e(MyTracksConstants.TAG, "No auth result results!!");
+ Log.e(Constants.TAG, "No auth result results!!");
}
runWhenFinished();
return authToken != null;
@@ -181,7 +181,7 @@ public class ModernAuthManager implements AuthManager {
activity.runOnUiThread(new Runnable() {
public void run() {
- accountManager.invalidateAuthToken(MyTracksConstants.ACCOUNT_TYPE,
+ accountManager.invalidateAuthToken(Constants.ACCOUNT_TYPE,
authToken);
MyTracks.getInstance().getAccountChooser().chooseAccount(activity,
new AccountChooser.AccountHandler() {
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/SendToDocs.java b/MyTracks/src/com/google/android/apps/mytracks/io/SendToDocs.java
index 5c9254cd0..5105285e4 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/SendToDocs.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/SendToDocs.java
@@ -16,8 +16,7 @@
package com.google.android.apps.mytracks.io;
import com.google.android.apps.mytracks.MyTracks;
-import com.google.android.apps.mytracks.MyTracksConstants;
-import com.google.android.apps.mytracks.MyTracksSettings;
+import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.io.docs.DocsHelper;
@@ -73,7 +72,7 @@ public class SendToDocs {
this.trackId = trackId;
SharedPreferences preferences = activity.getSharedPreferences(
- MyTracksSettings.SETTINGS_NAME, 0);
+ Constants.SETTINGS_NAME, 0);
if (preferences != null) {
metricUnits =
preferences.getBoolean(activity.getString(R.string.metric_units_key),
@@ -82,7 +81,7 @@ public class SendToDocs {
metricUnits = true;
}
- Log.d(MyTracksConstants.TAG,
+ Log.d(Constants.TAG,
"Sending to Google Docs: trackId = " + trackId);
handlerThread = new HandlerThread("SendToGoogleDocs");
handlerThread.start();
@@ -105,7 +104,7 @@ public class SendToDocs {
try {
if (trackId == -1) {
- Log.w(MyTracksConstants.TAG, "Cannot get track id.");
+ Log.w(Constants.TAG, "Cannot get track id.");
return;
}
@@ -113,14 +112,14 @@ public class SendToDocs {
Track track =
MyTracksProviderUtils.Factory.get(activity).getTrack(trackId);
if (track == null) {
- Log.w(MyTracksConstants.TAG, "Cannot get track.");
+ Log.w(Constants.TAG, "Cannot get track.");
return;
}
// Transmit track stats via GData feed:
// -------------------------------
- Log.d(MyTracksConstants.TAG, "SendToDocs: Uploading to spreadsheet");
+ Log.d(Constants.TAG, "SendToDocs: Uploading to spreadsheet");
success = uploadToDocs(track);
if (success) {
if (createdNewSpreadSheet) {
@@ -133,7 +132,7 @@ public class SendToDocs {
} else {
statusMessage = activity.getString(R.string.error_sending_to_docs);
}
- Log.d(MyTracksConstants.TAG, "SendToDocs: Done.");
+ Log.d(Constants.TAG, "SendToDocs: Done.");
} finally {
if (onCompletion != null) {
activity.runOnUiThread(onCompletion);
@@ -176,7 +175,7 @@ public class SendToDocs {
SpreadsheetsClient gdataClient = new SpreadsheetsClient(androidClient,
new XmlDocsGDataParserFactory(new AndroidXmlParserFactory()));
trixWrapper.setClient(gdataClient);
- Log.d(MyTracksConstants.TAG,
+ Log.d(Constants.TAG,
"GData connection prepared: " + this.docListAuth);
String sheetTitle = "My Tracks";
@@ -194,7 +193,7 @@ public class SendToDocs {
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
sheetTitle);
} catch (IOException e) {
- Log.i(MyTracksConstants.TAG, "Spreadsheet lookup failed.", e);
+ Log.i(Constants.TAG, "Spreadsheet lookup failed.", e);
return false;
}
@@ -205,14 +204,14 @@ public class SendToDocs {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
- Log.e(MyTracksConstants.TAG, "Sleep interrupted", e);
+ Log.e(Constants.TAG, "Sleep interrupted", e);
}
try {
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
sheetTitle);
} catch (IOException e) {
- Log.i(MyTracksConstants.TAG, "2nd spreadsheet lookup failed.", e);
+ Log.i(Constants.TAG, "2nd spreadsheet lookup failed.", e);
return false;
}
}
@@ -220,13 +219,13 @@ public class SendToDocs {
// We were unable to find an existing spreadsheet, so create a new one.
MyTracks.getInstance().setProgressValue(70);
if (spreadsheetId == null) {
- Log.i(MyTracksConstants.TAG, "Creating new spreadsheet: " + sheetTitle);
+ Log.i(Constants.TAG, "Creating new spreadsheet: " + sheetTitle);
try {
spreadsheetId = docsHelper.createSpreadsheet(activity, docListWrapper,
sheetTitle);
} catch (IOException e) {
- Log.i(MyTracksConstants.TAG, "Failed to create new spreadsheet "
+ Log.i(Constants.TAG, "Failed to create new spreadsheet "
+ sheetTitle, e);
return false;
}
@@ -239,19 +238,19 @@ public class SendToDocs {
// reported an error. Seems to be a know bug,
// see http://code.google.com/p/gdata-issues/issues/detail?id=929
// Try to find the created spreadsheet:
- Log.w(MyTracksConstants.TAG,
+ Log.w(Constants.TAG,
"Create might have failed. Trying to find created document.");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
- Log.e(MyTracksConstants.TAG, "Sleep interrupted", e);
+ Log.e(Constants.TAG, "Sleep interrupted", e);
}
try {
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
sheetTitle);
} catch (IOException e) {
- Log.i(MyTracksConstants.TAG, "Failed create-failed lookup", e);
+ Log.i(Constants.TAG, "Failed create-failed lookup", e);
return false;
}
@@ -261,19 +260,19 @@ public class SendToDocs {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
- Log.e(MyTracksConstants.TAG, "Sleep interrupted", e);
+ Log.e(Constants.TAG, "Sleep interrupted", e);
}
try {
spreadsheetId = docsHelper.requestSpreadsheetId(docListWrapper,
sheetTitle);
} catch (IOException e) {
- Log.i(MyTracksConstants.TAG, "Failed create-failed relookup", e);
+ Log.i(Constants.TAG, "Failed create-failed relookup", e);
return false;
}
}
if (spreadsheetId == null) {
- Log.i(MyTracksConstants.TAG,
+ Log.i(Constants.TAG,
"Creating new spreadsheet really failed.");
return false;
}
@@ -287,7 +286,7 @@ public class SendToDocs {
throw new IOException("Worksheet ID lookup returned empty");
}
} catch (IOException e) {
- Log.i(MyTracksConstants.TAG, "Looking up worksheet id failed.", e);
+ Log.i(Constants.TAG, "Looking up worksheet id failed.", e);
return false;
}
@@ -295,9 +294,9 @@ public class SendToDocs {
docsHelper.addTrackRow(activity, trixAuth, spreadsheetId, worksheetId,
track, metricUnits);
- Log.i(MyTracksConstants.TAG, "Done uploading to docs.");
+ Log.i(Constants.TAG, "Done uploading to docs.");
} catch (IOException e) {
- Log.e(MyTracksConstants.TAG, "Unable to upload docs.", e);
+ Log.e(Constants.TAG, "Unable to upload docs.", e);
return false;
} finally {
if (androidClient != null) {
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/SendToFusionTables.java b/MyTracks/src/com/google/android/apps/mytracks/io/SendToFusionTables.java
index c15013a50..eeb769b88 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/SendToFusionTables.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/SendToFusionTables.java
@@ -15,8 +15,7 @@
*/
package com.google.android.apps.mytracks.io;
-import com.google.android.apps.mytracks.MyTracksConstants;
-import com.google.android.apps.mytracks.MyTracksSettings;
+import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.ProgressIndicator;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
@@ -25,8 +24,9 @@ import com.google.android.apps.mytracks.io.gdata.GDataWrapper;
import com.google.android.apps.mytracks.io.gdata.GDataWrapper.QueryFunction;
import com.google.android.apps.mytracks.stats.DoubleBuffer;
import com.google.android.apps.mytracks.stats.TripStatistics;
-import com.google.android.apps.mytracks.util.MyTracksUtils;
+import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.StringUtils;
+import com.google.android.apps.mytracks.util.SystemUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
import com.google.api.client.googleapis.GoogleHeaders;
@@ -141,7 +141,7 @@ public class SendToFusionTables implements Runnable {
this.providerUtils = MyTracksProviderUtils.Factory.get(context);
GoogleHeaders headers = new GoogleHeaders();
- headers.setApplicationName("Google-MyTracks-" + MyTracksUtils.getMyTracksVersion(context));
+ headers.setApplicationName("Google-MyTracks-" + SystemUtils.getMyTracksVersion(context));
headers.gdataVersion = GDATA_VERSION;
transport = new HttpTransport();
@@ -151,7 +151,7 @@ public class SendToFusionTables implements Runnable {
@Override
public void run() {
- Log.d(MyTracksConstants.TAG, "Sending to Fusion tables: trackId = " + trackId);
+ Log.d(Constants.TAG, "Sending to Fusion tables: trackId = " + trackId);
doUpload();
}
@@ -172,7 +172,7 @@ public class SendToFusionTables implements Runnable {
private void doUpload() {
((GoogleHeaders) transport.defaultHeaders).setGoogleLogin(auth.getAuthToken());
int statusMessageId = R.string.error_sending_to_fusiontables;
- boolean success = false;
+ boolean success = true;
try {
progressIndicator.setProgressValue(PROGRESS_INITIALIZATION);
progressIndicator.setProgressMessage(R.string.progress_message_reading_track);
@@ -204,11 +204,10 @@ public class SendToFusionTables implements Runnable {
}
statusMessageId = R.string.status_new_fusiontable_has_been_created;
- success = true;
- Log.d(MyTracksConstants.TAG, "SendToFusionTables: Done: " + success);
+ Log.d(Constants.TAG, "SendToFusionTables: Done: " + success);
progressIndicator.setProgressValue(PROGRESS_COMPLETE);
-
} finally {
+
final boolean finalSuccess = success;
final int finalStatusMessageId = statusMessageId;
context.runOnUiThread(new Runnable() {
@@ -229,14 +228,14 @@ public class SendToFusionTables implements Runnable {
* @return true in case of success.
*/
private boolean createNewTable(Track track) {
- Log.d(MyTracksConstants.TAG, "Creating a new fusion table.");
+ Log.d(Constants.TAG, "Creating a new fusion table.");
String query = "CREATE TABLE '" + sqlEscape(track.getName()) +
"' (name:STRING,description:STRING,geometry:LOCATION,marker:STRING)";
return runUpdate(query);
}
private boolean makeTableUnlisted(String tableId) {
- Log.d(MyTracksConstants.TAG, "Setting visibility to unlisted.");
+ Log.d(Constants.TAG, "Setting visibility to unlisted.");
String query = "UPDATE TABLE " + tableId + " SET VISIBILITY = UNLISTED";
return runUpdate(query);
}
@@ -275,7 +274,7 @@ public class SendToFusionTables implements Runnable {
*/
private boolean createNewPoint(String name, String description, Location location,
String marker) {
- Log.d(MyTracksConstants.TAG, "Creating a new row with a point.");
+ Log.d(Constants.TAG, "Creating a new row with a point.");
String query = "INSERT INTO " + tableId + " (name,description,geometry,marker) VALUES "
+ values(name, description, getKmlPoint(location), marker);
return runUpdate(query);
@@ -288,7 +287,7 @@ public class SendToFusionTables implements Runnable {
* @return true in case of success.
*/
private boolean createNewLineString(Track track) {
- Log.d(MyTracksConstants.TAG, "Creating a new row with a point.");
+ Log.d(Constants.TAG, "Creating a new row with a point.");
String query = "INSERT INTO " + tableId
+ " (name,description,geometry) VALUES "
+ values(track.getName(), track.getDescription(), getKmlLineString(track));
@@ -297,7 +296,7 @@ public class SendToFusionTables implements Runnable {
private boolean uploadAllTrackPoints(final Track track, String originalDescription) {
- SharedPreferences preferences = context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
+ SharedPreferences preferences = context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
boolean metricUnits = true;
if (preferences != null) {
metricUnits = preferences.getBoolean(context.getString(R.string.metric_units_key), true);
@@ -306,7 +305,7 @@ public class SendToFusionTables implements Runnable {
Cursor locationsCursor = providerUtils.getLocationsCursor(track.getId(), 0, -1, false);
try {
if (!locationsCursor.moveToFirst()) {
- Log.w(MyTracksConstants.TAG, "Unable to get any points to upload");
+ Log.w(Constants.TAG, "Unable to get any points to upload");
return false;
}
@@ -319,14 +318,14 @@ public class SendToFusionTables implements Runnable {
// Limit the number of elevation readings. Ideally we would want around 250.
int elevationSamplingFrequency =
Math.max(1, (int) (totalLocations / 250.0));
- Log.d(MyTracksConstants.TAG,
+ Log.d(Constants.TAG,
"Using elevation sampling factor: " + elevationSamplingFrequency
+ " on " + totalLocations);
double totalDistance = 0;
Vector distances = new Vector();
Vector elevations = new Vector();
- DoubleBuffer elevationBuffer = new DoubleBuffer(MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
+ DoubleBuffer elevationBuffer = new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR);
List locations = new ArrayList(MAX_POINTS_PER_UPLOAD);
Location lastLocation = null;
@@ -345,7 +344,7 @@ public class SendToFusionTables implements Runnable {
}
// Add to the elevation profile.
- if (loc != null && MyTracksUtils.isValidLocation(loc)) {
+ if (loc != null && LocationUtils.isValidLocation(loc)) {
// All points go into the smoothing buffer...
elevationBuffer.setNext(metricUnits ? loc.getAltitude()
: loc.getAltitude() * UnitConversions.M_TO_FT);
@@ -448,7 +447,7 @@ public class SendToFusionTables implements Runnable {
int numLocations = locations.size();
if (numLocations < 2) {
- Log.d(MyTracksConstants.TAG, "Not preparing/uploading too few points");
+ Log.d(Constants.TAG, "Not preparing/uploading too few points");
totalLocationsUploaded += numLocations;
return true;
}
@@ -464,16 +463,16 @@ public class SendToFusionTables implements Runnable {
context.getString(R.string.part), totalSegmentsUploaded));
}
totalSegmentsUploaded++;
- Log.d(MyTracksConstants.TAG,
+ Log.d(Constants.TAG,
"SendToFusionTables: Prepared feature for upload w/ "
+ splitTrack.getLocations().size() + " points.");
// Transmit tracks via GData feed:
// -------------------------------
- Log.d(MyTracksConstants.TAG,
+ Log.d(Constants.TAG,
"SendToFusionTables: Uploading to table " + tableId + " w/ auth " + auth);
if (!uploadTrackPoints(splitTrack)) {
- Log.e(MyTracksConstants.TAG, "Uploading failed");
+ Log.e(Constants.TAG, "Uploading failed");
return false;
}
}
@@ -519,7 +518,7 @@ public class SendToFusionTables implements Runnable {
// Close up the last segment.
prepareTrackSegment(segment, splitTracks);
- Log.d(MyTracksConstants.TAG,
+ Log.d(Constants.TAG,
"MyTracksSendToFusionTables: Starting new track segment...");
startNewTrackSegment = false;
segment = new Track();
@@ -567,12 +566,12 @@ public class SendToFusionTables implements Runnable {
* Decimate to 2 meter precision. Fusion tables doesn't like too many
* points:
*/
- MyTracksUtils.decimate(segment, 2.0);
+ LocationUtils.decimate(segment, 2.0);
/* If the track still has > 2500 points, split it in pieces: */
final int maxPoints = 2500;
if (segment.getLocations().size() > maxPoints) {
- splitTracks.addAll(MyTracksUtils.split(segment, maxPoints));
+ splitTracks.addAll(LocationUtils.split(segment, maxPoints));
} else if (segment.getLocations().size() >= 2) {
splitTracks.add(segment);
}
@@ -582,7 +581,7 @@ public class SendToFusionTables implements Runnable {
int numLocations = splitTrack.getLocations().size();
if (numLocations < 2) {
// Need at least two points for a polyline:
- Log.w(MyTracksConstants.TAG, "Not uploading too few points");
+ Log.w(Constants.TAG, "Not uploading too few points");
return true;
}
return createNewLineString(splitTrack);
@@ -605,14 +604,14 @@ public class SendToFusionTables implements Runnable {
try {
c = providerUtils.getWaypointsCursor(
track.getId(), 0,
- MyTracksConstants.MAX_LOADED_WAYPOINTS_POINTS);
+ Constants.MAX_LOADED_WAYPOINTS_POINTS);
if (c != null) {
if (c.moveToFirst()) {
// This will skip the 1st waypoint (it carries the stats for the
// last segment).
while (c.moveToNext()) {
Waypoint wpt = providerUtils.createWaypoint(c);
- Log.d(MyTracksConstants.TAG, "SendToFusionTables: Creating waypoint.");
+ Log.d(Constants.TAG, "SendToFusionTables: Creating waypoint.");
success = createNewPoint(wpt.getName(), wpt.getDescription(), wpt.getLocation(),
MARKER_TYPE_WAYPOINT);
if (!success) {
@@ -622,7 +621,7 @@ public class SendToFusionTables implements Runnable {
}
}
if (!success) {
- Log.w(MyTracksConstants.TAG, "SendToFusionTables: upload waypoints failed.");
+ Log.w(Constants.TAG, "SendToFusionTables: upload waypoints failed.");
}
return success;
} finally {
@@ -657,7 +656,7 @@ public class SendToFusionTables implements Runnable {
wrapper.setAuthManager(auth);
wrapper.setRetryOnAuthFailure(true);
wrapper.setClient(transport);
- Log.d(MyTracksConstants.TAG, "GData connection prepared: " + this.auth);
+ Log.d(Constants.TAG, "GData connection prepared: " + this.auth);
wrapper.runQuery(new QueryFunction() {
@Override
public void query(HttpTransport client)
@@ -672,7 +671,7 @@ public class SendToFusionTables implements Runnable {
isc.inputStream = new ByteArrayInputStream(Strings.toBytesUtf8(sql));
request.content = isc;
- Log.d(MyTracksConstants.TAG, "Running update query " + url.toString() + ": " + sql);
+ Log.d(Constants.TAG, "Running update query " + url.toString() + ": " + sql);
HttpResponse response;
try {
response = request.execute();
@@ -687,12 +686,12 @@ public class SendToFusionTables implements Runnable {
String[] lines = s.split(Strings.LINE_SEPARATOR);
if (lines[0].equals("tableid")) {
tableId = lines[1];
- Log.d(MyTracksConstants.TAG, "tableId = " + tableId);
+ Log.d(Constants.TAG, "tableId = " + tableId);
} else {
- Log.w(MyTracksConstants.TAG, "Unrecognized response: " + lines[0]);
+ Log.w(Constants.TAG, "Unrecognized response: " + lines[0]);
}
} else {
- Log.d(MyTracksConstants.TAG, "Query failed: " + response.statusMessage + " (" +
+ Log.d(Constants.TAG, "Query failed: " + response.statusMessage + " (" +
response.statusCode + ")");
throw new GDataWrapper.HttpException(response.statusCode, response.statusMessage);
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/SendToMyMaps.java b/MyTracks/src/com/google/android/apps/mytracks/io/SendToMyMaps.java
index 3891b0322..ffc895da6 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/SendToMyMaps.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/SendToMyMaps.java
@@ -15,8 +15,8 @@
*/
package com.google.android.apps.mytracks.io;
-import com.google.android.apps.mytracks.MyTracksConstants;
-import com.google.android.apps.mytracks.MyTracksSettings;
+import static com.google.android.apps.mytracks.Constants.TAG;
+import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.ProgressIndicator;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
@@ -24,7 +24,7 @@ import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.io.mymaps.MapsFacade;
import com.google.android.apps.mytracks.stats.DoubleBuffer;
import com.google.android.apps.mytracks.stats.TripStatistics;
-import com.google.android.apps.mytracks.util.MyTracksUtils;
+import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
@@ -92,7 +92,7 @@ public class SendToMyMaps implements Runnable {
@Override
public void run() {
- Log.d(MyTracksConstants.TAG, "Sending to MyMaps: trackId = " + trackId);
+ Log.d(TAG, "Sending to MyMaps: trackId = " + trackId);
doUpload();
}
@@ -116,7 +116,7 @@ public class SendToMyMaps implements Runnable {
boolean isNewMap = mapId.equals(NEW_MAP_ID);
if (isNewMap) {
SharedPreferences preferences = context.getSharedPreferences(
- MyTracksSettings.SETTINGS_NAME, 0);
+ Constants.SETTINGS_NAME, 0);
boolean mapPublic = true;
if (preferences != null) {
mapPublic = preferences.getBoolean(
@@ -141,7 +141,7 @@ public class SendToMyMaps implements Runnable {
if (success) {
Cursor c = providerUtils.getWaypointsCursor(
track.getId(), 0,
- MyTracksConstants.MAX_LOADED_WAYPOINTS_POINTS);
+ Constants.MAX_LOADED_WAYPOINTS_POINTS);
if (c != null) {
try {
if (c.getCount() > 1 && c.moveToFirst()) {
@@ -163,8 +163,7 @@ public class SendToMyMaps implements Runnable {
}
if (!success) {
- Log.w(MyTracksConstants.TAG,
- "SendToMyMaps: upload waypoints failed.");
+ Log.w(TAG, "SendToMyMaps: upload waypoints failed.");
}
}
@@ -173,7 +172,7 @@ public class SendToMyMaps implements Runnable {
? R.string.status_new_mymap_has_been_created
: R.string.status_tracks_have_been_uploaded;
}
- Log.d(MyTracksConstants.TAG, "SendToMyMaps: Done: " + success);
+ Log.d(TAG, "SendToMyMaps: Done: " + success);
progressIndicator.setProgressValue(100);
} finally {
if (mapsClient != null) {
@@ -196,7 +195,7 @@ public class SendToMyMaps implements Runnable {
private boolean uploadAllTrackPoints(
final Track track, String originalDescription) {
SharedPreferences preferences = context.getSharedPreferences(
- MyTracksSettings.SETTINGS_NAME, 0);
+ Constants.SETTINGS_NAME, 0);
boolean metricUnits = true;
if (preferences != null) {
metricUnits =
@@ -208,7 +207,7 @@ public class SendToMyMaps implements Runnable {
providerUtils.getLocationsCursor(track.getId(), 0, -1, false);
try {
if (!locationsCursor.moveToFirst()) {
- Log.w(MyTracksConstants.TAG, "Unable to get any points to upload");
+ Log.w(TAG, "Unable to get any points to upload");
return false;
}
@@ -221,7 +220,7 @@ public class SendToMyMaps implements Runnable {
// Limit the number of elevation readings. Ideally we would want around 250.
int elevationSamplingFrequency =
Math.max(1, (int) (totalLocations / 250.0));
- Log.d(MyTracksConstants.TAG,
+ Log.d(TAG,
"Using elevation sampling factor: " + elevationSamplingFrequency
+ " on " + totalLocations);
double totalDistance = 0;
@@ -229,7 +228,7 @@ public class SendToMyMaps implements Runnable {
Vector distances = new Vector();
Vector elevations = new Vector();
DoubleBuffer elevationBuffer =
- new DoubleBuffer(MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
+ new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR);
List locations = new ArrayList(MAX_POINTS_PER_UPLOAD);
progressIndicator.setProgressMessage(
@@ -249,7 +248,7 @@ public class SendToMyMaps implements Runnable {
}
// Add to the elevation profile.
- if (loc != null && MyTracksUtils.isValidLocation(loc)) {
+ if (loc != null && LocationUtils.isValidLocation(loc)) {
// All points go into the smoothing buffer...
elevationBuffer.setNext(metricUnits ? loc.getAltitude()
: loc.getAltitude() * UnitConversions.M_TO_FT);
@@ -310,7 +309,7 @@ public class SendToMyMaps implements Runnable {
int numLocations = locations.size();
if (numLocations < 2) {
- Log.d(MyTracksConstants.TAG, "Not preparing/uploading too few points");
+ Log.d(TAG, "Not preparing/uploading too few points");
totalLocationsUploaded += numLocations;
return true;
}
@@ -328,16 +327,16 @@ public class SendToMyMaps implements Runnable {
context.getString(R.string.part), totalSegmentsUploaded));
}
totalSegmentsUploaded++;
- Log.d(MyTracksConstants.TAG,
+ Log.d(TAG,
"SendToMyMaps: Prepared feature for upload w/ "
+ splitTrack.getLocations().size() + " points.");
// Transmit tracks via GData feed:
// -------------------------------
- Log.d(MyTracksConstants.TAG,
+ Log.d(TAG,
"SendToMyMaps: Uploading to map " + mapId + " w/ auth " + auth);
if (!mapsClient.uploadTrackPoints(mapId, splitTrack.getName(), splitTrack.getLocations())) {
- Log.e(MyTracksConstants.TAG, "Uploading failed");
+ Log.e(TAG, "Uploading failed");
return false;
}
}
@@ -383,7 +382,7 @@ public class SendToMyMaps implements Runnable {
// Close up the last segment.
prepareTrackSegment(segment, splitTracks);
- Log.d(MyTracksConstants.TAG,
+ Log.d(TAG,
"MyTracksSendToMyMaps: Starting new track segment...");
startNewTrackSegment = false;
segment = new Track();
@@ -431,11 +430,11 @@ public class SendToMyMaps implements Runnable {
* Decimate to 2 meter precision. Mapshop doesn't like too many
* points:
*/
- MyTracksUtils.decimate(segment, 2.0);
+ LocationUtils.decimate(segment, 2.0);
/* It the track still has > 500 points, split it in pieces: */
if (segment.getLocations().size() > 500) {
- splitTracks.addAll(MyTracksUtils.split(segment, 500));
+ splitTracks.addAll(LocationUtils.split(segment, 500));
} else if (segment.getLocations().size() >= 2) {
splitTracks.add(segment);
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/TcxTrackWriter.java b/MyTracks/src/com/google/android/apps/mytracks/io/TcxTrackWriter.java
index e27401b71..6cc76f68a 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/TcxTrackWriter.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/TcxTrackWriter.java
@@ -21,7 +21,7 @@ import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.io.TrackWriterFactory.TrackFileFormat;
-import com.google.android.apps.mytracks.util.MyTracksUtils;
+import com.google.android.apps.mytracks.util.SystemUtils;
import android.content.Context;
import android.location.Location;
@@ -236,7 +236,7 @@ public class TcxTrackWriter implements TrackFormatWriter {
// it. The TCX schema tightly defined the Version tag, so we can't put it
// there. They've similarly constrained the PartNumber tag, so it can't go
// there either.
- pw.format("My Tracks %s by Google\n", MyTracksUtils.getMyTracksVersion(context));
+ pw.format("My Tracks %s by Google\n", SystemUtils.getMyTracksVersion(context));
pw.println("");
@@ -246,11 +246,11 @@ public class TcxTrackWriter implements TrackFormatWriter {
// signify that this build is newer than the one associated with the
// version code given in VersionMajor.
pw.println("");
- pw.format("%d\n", MyTracksUtils.getMyTracksVersionCode(context));
- pw.format("%d\n", MyTracksUtils.isRelease(context) ? 0 : 1);
+ pw.format("%d\n", SystemUtils.getMyTracksVersion(context));
+ pw.format("%d\n", SystemUtils.isRelease(context) ? 0 : 1);
pw.println("");
- pw.format("%s\n", MyTracksUtils.isRelease(context) ? TCX_TYPE_RELEASE
+ pw.format("%s\n", SystemUtils.isRelease(context) ? TCX_TYPE_RELEASE
: TCX_TYPE_INTERNAL);
pw.println("");
pw.format("%s\n", Locale.getDefault().getLanguage());
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/TrackWriter.java b/MyTracks/src/com/google/android/apps/mytracks/io/TrackWriter.java
index 26fb19f87..1d86498ed 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/TrackWriter.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/TrackWriter.java
@@ -15,14 +15,14 @@
*/
package com.google.android.apps.mytracks.io;
-import com.google.android.apps.mytracks.MyTracksConstants;
+import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.MyTracksLocation;
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.MyTracksProviderUtils.LocationIterator;
import com.google.android.apps.mytracks.util.FileUtils;
-import com.google.android.apps.mytracks.util.MyTracksUtils;
+import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
@@ -160,16 +160,16 @@ public class TrackWriter {
String fileName = fileUtils.buildUniqueFileName(
directory, track.getName(), writer.getExtension());
if (fileName == null) {
- Log.e(MyTracksConstants.TAG,
+ Log.e(Constants.TAG,
"Unable to get a unique filename for " + fileName);
return false;
}
- Log.i(MyTracksConstants.TAG, "Writing track to: " + fileName);
+ Log.i(Constants.TAG, "Writing track to: " + fileName);
try {
writer.prepare(track, newOutputStream(fileName));
} catch (FileNotFoundException e) {
- Log.e(MyTracksConstants.TAG, "Failed to open output file.", e);
+ Log.e(Constants.TAG, "Failed to open output file.", e);
errorMessage = R.string.io_write_failed;
return false;
}
@@ -187,12 +187,12 @@ public class TrackWriter {
}
if (!fileUtils.isSdCardAvailable()) {
- Log.i(MyTracksConstants.TAG, "Could not find SD card.");
+ Log.i(Constants.TAG, "Could not find SD card.");
errorMessage = R.string.io_no_external_storage_found;
return false;
}
if (!fileUtils.ensureDirectoryExists(directory)) {
- Log.i(MyTracksConstants.TAG, "Could not create export directory.");
+ Log.i(Constants.TAG, "Could not create export directory.");
errorMessage = R.string.io_create_dir_failed;
return false;
}
@@ -230,7 +230,7 @@ public class TrackWriter {
// same time.
Cursor cursor = null;
cursor = providerUtils.getWaypointsCursor(trackId, 0,
- MyTracksConstants.MAX_LOADED_WAYPOINTS_POINTS);
+ Constants.MAX_LOADED_WAYPOINTS_POINTS);
if (cursor != null) {
try {
if (cursor.moveToFirst()) {
@@ -253,14 +253,14 @@ public class TrackWriter {
* Does the actual work of writing the track to the now open file.
*/
void writeDocument() {
- Log.d(MyTracksConstants.TAG, "Started writing track.");
+ Log.d(Constants.TAG, "Started writing track.");
writer.writeHeader();
writeWaypoints(track.getId());
writeLocations();
writer.writeFooter();
writer.close();
success = true;
- Log.d(MyTracksConstants.TAG, "Done writing track.");
+ Log.d(Constants.TAG, "Done writing track.");
errorMessage = R.string.io_write_finished;
}
@@ -296,13 +296,13 @@ public class TrackWriter {
locationFactory);
try {
if (!it.hasNext()) {
- Log.w(MyTracksConstants.TAG, "Unable to get any points to write");
+ Log.w(Constants.TAG, "Unable to get any points to write");
return;
}
while (it.hasNext()) {
Location loc = it.next();
- boolean isValid = MyTracksUtils.isValidLocation(loc);
+ boolean isValid = LocationUtils.isValidLocation(loc);
boolean validSegment = isValid && isLastValid;
if (!wroteFirst && validSegment) {
// Found the first two consecutive points which are valid
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/backup/BackupActivityHelper.java b/MyTracks/src/com/google/android/apps/mytracks/io/backup/BackupActivityHelper.java
index e66cd29d8..0de343479 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/backup/BackupActivityHelper.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/backup/BackupActivityHelper.java
@@ -16,7 +16,7 @@
package com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.MyTracks;
-import com.google.android.apps.mytracks.MyTracksConstants;
+import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.util.FileUtils;
import com.google.android.maps.mytracks.R;
@@ -97,7 +97,7 @@ public class BackupActivityHelper {
backup.writeToDefaultFile();
showToast(R.string.io_write_finished);
} catch (IOException e) {
- Log.e(MyTracksConstants.TAG, "Failed to write backup", e);
+ Log.e(Constants.TAG, "Failed to write backup", e);
showToast(R.string.io_write_failed);
} finally {
dismissDialog(progressDialog);
@@ -199,7 +199,7 @@ public class BackupActivityHelper {
backup.restoreFromDate(date);
showToast(R.string.io_read_finished);
} catch (IOException e) {
- Log.e(MyTracksConstants.TAG, "Failed to restore backup", e);
+ Log.e(Constants.TAG, "Failed to restore backup", e);
showToast(R.string.io_read_failed);
} finally {
dismissDialog(progressDialog);
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/backup/ExternalFileBackup.java b/MyTracks/src/com/google/android/apps/mytracks/io/backup/ExternalFileBackup.java
index cc346e2f7..1fbcf9485 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/backup/ExternalFileBackup.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/backup/ExternalFileBackup.java
@@ -15,8 +15,7 @@
*/
package com.google.android.apps.mytracks.io.backup;
-import com.google.android.apps.mytracks.MyTracksConstants;
-import com.google.android.apps.mytracks.MyTracksSettings;
+import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.TrackPointsColumns;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.content.WaypointsColumns;
@@ -88,7 +87,7 @@ class ExternalFileBackup {
private File getBackupsDirectory(boolean create) {
String dirName = fileUtils.buildExternalDirectoryPath(BACKUPS_SUBDIR);
final File dir = new File(dirName);
- Log.d(MyTracksConstants.TAG, "Dir: " + dir.getAbsolutePath());
+ Log.d(Constants.TAG, "Dir: " + dir.getAbsolutePath());
if (create) {
// Try to create - if that fails, return null
return fileUtils.ensureDirectoryExists(dir) ? dir : null;
@@ -147,7 +146,7 @@ class ExternalFileBackup {
* Synchronously writes a backup to the given file.
*/
private void writeToFile(File outputFile) throws IOException {
- Log.d(MyTracksConstants.TAG,
+ Log.d(Constants.TAG,
"Writing backup to file " + outputFile.getAbsolutePath());
// Create all the auxiliary classes that will do the writing
@@ -201,7 +200,7 @@ class ExternalFileBackup {
// Dump preferences
SharedPreferences preferences =
- context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
+ context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
preferencesHelper.exportPreferences(preferences, outWriter);
} catch (IOException e) {
// We tried to delete the partially created file, but do nothing
@@ -219,7 +218,7 @@ class ExternalFileBackup {
* Synchronously restores the backup from the given file.
*/
private void restoreFromFile(File inputFile) throws IOException {
- Log.d(MyTracksConstants.TAG,
+ Log.d(Constants.TAG,
"Restoring from file " + inputFile.getAbsolutePath());
PreferenceBackupHelper preferencesHelper = new PreferenceBackupHelper();
@@ -253,7 +252,7 @@ class ExternalFileBackup {
// Restore preferences
SharedPreferences preferences =
- context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
+ context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
preferencesHelper.importPreferences(reader, preferences);
} finally {
compressedStream.close();
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/backup/MyTracksBackupAgent.java b/MyTracks/src/com/google/android/apps/mytracks/io/backup/MyTracksBackupAgent.java
index f9bb2f352..4438ca47f 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/backup/MyTracksBackupAgent.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/backup/MyTracksBackupAgent.java
@@ -15,8 +15,7 @@
*/
package com.google.android.apps.mytracks.io.backup;
-import com.google.android.apps.mytracks.MyTracksConstants;
-import com.google.android.apps.mytracks.MyTracksSettings;
+import com.google.android.apps.mytracks.Constants;
import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
@@ -40,12 +39,12 @@ public class MyTracksBackupAgent extends BackupAgent {
@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) throws IOException {
- Log.i(MyTracksConstants.TAG, "Performing backup");
+ Log.i(Constants.TAG, "Performing backup");
SharedPreferences preferences = this.getSharedPreferences(
- MyTracksSettings.SETTINGS_NAME, 0);
+ Constants.SETTINGS_NAME, 0);
backupPreferences(data, preferences);
- Log.i(MyTracksConstants.TAG, "Backup complete");
+ Log.i(Constants.TAG, "Backup complete");
}
private void backupPreferences(BackupDataOutput data,
@@ -63,18 +62,18 @@ public class MyTracksBackupAgent extends BackupAgent {
@Override
public void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState) throws IOException {
- Log.i(MyTracksConstants.TAG, "Restoring from backup");
+ Log.i(Constants.TAG, "Restoring from backup");
while (data.readNextHeader()) {
String key = data.getKey();
- Log.d(MyTracksConstants.TAG, "Restoring entity " + key);
+ Log.d(Constants.TAG, "Restoring entity " + key);
if (key.equals(PREFERENCES_ENTITY)) {
restorePreferences(data);
} else {
- Log.e(MyTracksConstants.TAG, "Found unknown backup entity: " + key);
+ Log.e(Constants.TAG, "Found unknown backup entity: " + key);
data.skipEntityData();
}
}
- Log.i(MyTracksConstants.TAG, "Done restoring from backup");
+ Log.i(Constants.TAG, "Done restoring from backup");
}
/**
@@ -92,7 +91,7 @@ public class MyTracksBackupAgent extends BackupAgent {
}
SharedPreferences preferences = this.getSharedPreferences(
- MyTracksSettings.SETTINGS_NAME, 0);
+ Constants.SETTINGS_NAME, 0);
PreferenceBackupHelper importer = createPreferenceBackupHelper();
importer.importPreferences(dataBuffer, preferences);
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/docs/DocsHelper.java b/MyTracks/src/com/google/android/apps/mytracks/io/docs/DocsHelper.java
index e46a2573d..ce9752f39 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/docs/DocsHelper.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/docs/DocsHelper.java
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.io.docs;
-import com.google.android.apps.mytracks.MyTracksConstants;
+import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.io.AuthManager;
import com.google.android.apps.mytracks.io.gdata.GDataWrapper;
@@ -144,7 +144,7 @@ public class DocsHelper {
String id = result.substring(
idStringStart + DOCS_SPREADSHEET_URL.length(), idTagCloseIndex);
- Log.i(MyTracksConstants.TAG, "Created new spreadsheet: " + id);
+ Log.i(Constants.TAG, "Created new spreadsheet: " + id);
idSaver.set(id);
}});
@@ -184,7 +184,7 @@ public class DocsHelper {
while (listParser.hasMoreData()) {
Entry entry = listParser.readNextEntry(null);
String entryTitle = entry.getTitle();
- Log.i(MyTracksConstants.TAG, "Found docs entry: " + entryTitle);
+ Log.i(Constants.TAG, "Found docs entry: " + entryTitle);
if (entryTitle.equals(title)) {
String entryId = entry.getId();
int lastSlash = entryId.lastIndexOf('/');
@@ -233,7 +233,7 @@ public class DocsHelper {
trixWrapper.getAuthManager().getAuthToken());
sheetParser.init();
if (!sheetParser.hasMoreData()) {
- Log.i(MyTracksConstants.TAG, "Found no worksheets");
+ Log.i(Constants.TAG, "Found no worksheets");
return;
}
@@ -308,7 +308,7 @@ public class DocsHelper {
if (track.getMapId().length() > 0) {
tagBuilder.append("map", String.format("%s?msa=0&msid=%s",
- MyTracksConstants.MAPSHOP_BASE_URL, track.getMapId()));
+ Constants.MAPSHOP_BASE_URL, track.getMapId()));
}
String postText = new StringBuilder()
@@ -319,14 +319,14 @@ public class DocsHelper {
.append("")
.toString();
- Log.i(MyTracksConstants.TAG,
+ Log.i(Constants.TAG,
"Inserting at: " + spreadsheetId + " => " + worksheetUri);
- Log.i(MyTracksConstants.TAG, postText);
+ Log.i(Constants.TAG, postText);
writeRowData(trixAuth, worksheetUri, postText);
- Log.i(MyTracksConstants.TAG, "Post finished.");
+ Log.i(Constants.TAG, "Post finished.");
}
/**
@@ -358,7 +358,7 @@ public class DocsHelper {
String line;
while ((line = rd.readLine()) != null) {
// Process line.
- Log.i(MyTracksConstants.TAG, "r: " + line);
+ Log.i(Constants.TAG, "r: " + line);
}
wr.close();
rd.close();
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/gdata/GDataClientFactory.java b/MyTracks/src/com/google/android/apps/mytracks/io/gdata/GDataClientFactory.java
index 15dd588d0..a0a717bb1 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/gdata/GDataClientFactory.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/gdata/GDataClientFactory.java
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.io.gdata;
-import com.google.android.apps.mytracks.MyTracksConstants;
+import com.google.android.apps.mytracks.Constants;
import com.google.wireless.gdata.client.GDataClient;
import android.content.Context;
@@ -43,7 +43,7 @@ public class GDataClientFactory {
} catch (LinkageError e) {
// On all other platforms use the client implementation packaged in the
// apk.
- Log.i(MyTracksConstants.TAG, "Using mytracks AndroidGDataClient.", e);
+ Log.i(Constants.TAG, "Using mytracks AndroidGDataClient.", e);
return new com.google.android.apps.mytracks.io.gdata.AndroidGDataClient();
}
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/gdata/GDataWrapper.java b/MyTracks/src/com/google/android/apps/mytracks/io/gdata/GDataWrapper.java
index 75626c825..e26cbf947 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/io/gdata/GDataWrapper.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/io/gdata/GDataWrapper.java
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.io.gdata;
-import com.google.android.apps.mytracks.MyTracksConstants;
+import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.io.AuthManager;
import android.util.Log;
@@ -173,14 +173,14 @@ public class GDataWrapper {
return true;
}
- Log.d(MyTracksConstants.TAG, "GData error encountered: " + errorMessage);
+ Log.d(Constants.TAG, "GData error encountered: " + errorMessage);
if (errorType == ERROR_AUTH && auth != null) {
if (!retryOnAuthFailure || !invalidateAndRefreshAuthToken()) {
return false;
}
}
- Log.d(MyTracksConstants.TAG, "retrying function/query");
+ Log.d(Constants.TAG, "retrying function/query");
}
return false;
}
@@ -206,11 +206,11 @@ public class GDataWrapper {
errorMessage = null;
} catch (AuthenticationException e) {
- Log.e(MyTracksConstants.TAG, "AuthenticationException", e);
+ Log.e(Constants.TAG, "AuthenticationException", e);
errorType = ERROR_AUTH;
errorMessage = e.getMessage();
} catch (HttpException e) {
- Log.e(MyTracksConstants.TAG,
+ Log.e(Constants.TAG,
"HttpException, code " + e.getStatusCode() + " message " + e.getMessage(), e);
errorMessage = e.getMessage();
if (e.getStatusCode() == 401) {
@@ -219,11 +219,11 @@ public class GDataWrapper {
errorType = ERROR_CONNECTION;
}
} catch (FileNotFoundException e) {
- Log.e(MyTracksConstants.TAG, "Exception", e);
+ Log.e(Constants.TAG, "Exception", e);
errorType = ERROR_AUTH;
errorMessage = e.getMessage();
} catch (IOException e) {
- Log.e(MyTracksConstants.TAG, "Exception", e);
+ Log.e(Constants.TAG, "Exception", e);
errorMessage = e.getMessage();
if (errorMessage != null && errorMessage.contains("503")) {
errorType = ERROR_INTERNAL;
@@ -231,11 +231,11 @@ public class GDataWrapper {
errorType = ERROR_CONNECTION;
}
} catch (ParseException e) {
- Log.e(MyTracksConstants.TAG, "Exception", e);
+ Log.e(Constants.TAG, "Exception", e);
errorType = ERROR_LOCAL;
errorMessage = e.getMessage();
} catch (ConflictDetectedException e) {
- Log.e(MyTracksConstants.TAG, "Exception", e);
+ Log.e(Constants.TAG, "Exception", e);
errorType = ERROR_CONFLICT;
errorMessage = e.getMessage();
}
@@ -249,7 +249,7 @@ public class GDataWrapper {
* times out.
*/
private boolean invalidateAndRefreshAuthToken() {
- Log.d(MyTracksConstants.TAG, "Retrying due to auth failure");
+ Log.d(Constants.TAG, "Retrying due to auth failure");
// This FutureTask doesn't do anything -- it exists simply to be
// blocked upon using get().
FutureTask> whenFinishedFuture = new FutureTask