merge 1.1.4 release

This commit is contained in:
Matthew Simmons
2011-03-21 20:08:16 -04:00
83 changed files with 3041 additions and 2774 deletions
+7 -7
View File
@@ -52,7 +52,7 @@ limitations under the License.
</intent-filter>
</activity>
<activity android:name="com.google.android.apps.mytracks.MyTracksMap"
<activity android:name="com.google.android.apps.mytracks.MapActivity"
android:label="MyTracks"
android:exported="false" />
@@ -61,19 +61,19 @@ limitations under the License.
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|fontScale"
android:exported="false" />
<activity android:name="com.google.android.apps.mytracks.MyTracksList"
<activity android:name="com.google.android.apps.mytracks.TrackList"
android:label="Recorded Tracks" />
<activity android:name="com.google.android.apps.mytracks.MyTracksWaypointsList"
<activity android:name="com.google.android.apps.mytracks.WaypointsList"
android:label="Recorded Waypoints" />
<activity android:name="com.google.android.apps.mytracks.MyTracksDetails"
<activity android:name="com.google.android.apps.mytracks.TrackDetails"
android:label="@string/trackdetails_title" />
<activity android:name="com.google.android.apps.mytracks.MyTracksWaypointDetails"
<activity android:name="com.google.android.apps.mytracks.WaypointDetails"
android:label="@string/waypointdetails_title" />
<activity android:name="com.google.android.apps.mytracks.MyTracksSettings"
<activity android:name="com.google.android.apps.mytracks.SettingsActivity"
android:label="@string/mytracks_settings" />
<activity android:name="com.google.android.apps.mytracks.AggregatedStatsActivity"
@@ -101,7 +101,7 @@ limitations under the License.
android:exported="true"
android:permission="com.google.android.apps.mytracks.WRITE_TRACK_DATA" />
<receiver android:name="com.google.android.apps.mytracks.MyTracksReceiver">
<receiver android:name="com.google.android.apps.mytracks.BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
@@ -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);
@@ -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);
@@ -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");
}
}
}
@@ -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<double[]> pendingPoints = new ArrayList<double[]>();
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<double[]> 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<double[]> readPointsToList(Track track) {
Cursor cursor = null;
long lastLocationRead = lastSeenLocationId;
int points = 0;
int chartSamplingFrequency = getSamplingFrequency(track);
ArrayList<double[]> result = new ArrayList<double[]>();
// 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
}
}
@@ -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;
@@ -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);
}
@@ -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() { }
}
@@ -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) {
@@ -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);
}
}
});
@@ -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) {
@@ -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();
@@ -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();
@@ -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;
}
}
@@ -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<Waypoint>();
this.points = new ArrayList<CachedLocation>(1024);
this.pendingPoints = new ArrayBlockingQueue<CachedLocation>(
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;
@@ -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;
}
}
@@ -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;
}
}
File diff suppressed because it is too large Load Diff
@@ -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);
}
}
@@ -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();
@@ -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.
}
}
@@ -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);
}
}
File diff suppressed because it is too large Load Diff
@@ -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);
}
@@ -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;
@@ -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);
@@ -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;
@@ -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),
@@ -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));
}
}
@@ -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));
}
@@ -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);
}
@@ -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
@@ -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() {
@@ -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) {
@@ -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<Double> distances = new Vector<Double>();
Vector<Double> elevations = new Vector<Double>();
DoubleBuffer elevationBuffer = new DoubleBuffer(MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
DoubleBuffer elevationBuffer = new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR);
List<Location> locations = new ArrayList<Location>(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<HttpTransport>() {
@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);
}
@@ -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<Double> distances = new Vector<Double>();
Vector<Double> elevations = new Vector<Double>();
DoubleBuffer elevationBuffer =
new DoubleBuffer(MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR);
List<Location> locations = new ArrayList<Location>(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);
}
@@ -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("<Name>My Tracks %s by Google</Name>\n", MyTracksUtils.getMyTracksVersion(context));
pw.format("<Name>My Tracks %s by Google</Name>\n", SystemUtils.getMyTracksVersion(context));
pw.println("<Build>");
@@ -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("<Version>");
pw.format("<VersionMajor>%d</VersionMajor>\n", MyTracksUtils.getMyTracksVersionCode(context));
pw.format("<VersionMinor>%d</VersionMinor>\n", MyTracksUtils.isRelease(context) ? 0 : 1);
pw.format("<VersionMajor>%d</VersionMajor>\n", SystemUtils.getMyTracksVersion(context));
pw.format("<VersionMinor>%d</VersionMinor>\n", SystemUtils.isRelease(context) ? 0 : 1);
pw.println("</Version>");
pw.format("<Type>%s</Type>\n", MyTracksUtils.isRelease(context) ? TCX_TYPE_RELEASE
pw.format("<Type>%s</Type>\n", SystemUtils.isRelease(context) ? TCX_TYPE_RELEASE
: TCX_TYPE_INTERNAL);
pw.println("</Build>");
pw.format("<LangID>%s</LangID>\n", Locale.getDefault().getLanguage());
@@ -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
@@ -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);
@@ -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();
@@ -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);
}
@@ -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("</entry>")
.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();
@@ -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();
}
}
@@ -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<C> {
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<C> {
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<C> {
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<C> {
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<C> {
* 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<Object>(new Runnable() {
@@ -259,18 +259,18 @@ public class GDataWrapper<C> {
auth.invalidateAndRefresh(whenFinishedFuture);
try {
Log.d(MyTracksConstants.TAG, "waiting for invalidate");
Log.d(Constants.TAG, "waiting for invalidate");
whenFinishedFuture.get(AUTH_TOKEN_INVALIDATE_REFRESH_TIMEOUT,
TimeUnit.MILLISECONDS);
Log.d(MyTracksConstants.TAG, "invalidate finished");
Log.d(Constants.TAG, "invalidate finished");
return true;
} catch (InterruptedException e) {
Log.e(MyTracksConstants.TAG, "Failed to invalidate", e);
Log.e(Constants.TAG, "Failed to invalidate", e);
} catch (ExecutionException e) {
Log.e(MyTracksConstants.TAG, "Failed to invalidate", e);
Log.e(Constants.TAG, "Failed to invalidate", e);
} catch (TimeoutException e) {
Log.e(MyTracksConstants.TAG, "Invalidate didn't complete in time", e);
Log.e(Constants.TAG, "Invalidate didn't complete in time", e);
} finally {
whenFinishedFuture.cancel(false);
}
@@ -15,9 +15,9 @@
*/
package com.google.android.apps.mytracks.io.sendtogoogle;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.DialogManager;
import com.google.android.apps.mytracks.MyTracks;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.maps.mytracks.R;
import android.app.Dialog;
@@ -107,7 +107,7 @@ public class SendDialog extends Dialog {
R.id.sendtogoogle_send_stats_and_points);
SharedPreferences prefs =
getContext().getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
getContext().getSharedPreferences(Constants.SETTINGS_NAME, 0);
if (prefs != null) {
sendToMyMapsCheckBox.setChecked(
prefs.getBoolean(
@@ -138,7 +138,7 @@ public class SendDialog extends Dialog {
@Override
protected void onStop() {
SharedPreferences prefs =
getContext().getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
getContext().getSharedPreferences(Constants.SETTINGS_NAME, 0);
if (prefs != null) {
Editor editor = prefs.edit();
if (editor != null) {
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.services;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.Constants;
import com.google.android.maps.mytracks.R;
import android.content.Context;
@@ -58,7 +58,7 @@ class DefaultTrackNameFactory {
/** Determines whether the preferences allow a timestamp-based track name */
protected boolean useTimestampTrackName() {
SharedPreferences prefs =
context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
return prefs.getBoolean(
context.getString(R.string.timestamp_track_name_key), true);
}
@@ -16,7 +16,7 @@
package com.google.android.apps.mytracks.services;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import static com.google.android.apps.mytracks.Constants.TAG;
import android.content.Context;
import android.media.AudioManager;
@@ -16,7 +16,7 @@
package com.google.android.apps.mytracks.services;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.Constants;
import android.util.Log;
@@ -77,7 +77,7 @@ public class PeriodicTaskExecuter {
}
Date start = new Date(next);
Log.i(MyTracksConstants.TAG,
Log.i(Constants.TAG,
task.getClass().getSimpleName() + " scheduled to start at " + start
+ " every " + interval + " milliseconds.");
timer.scheduleAtFixedRate(new PeriodicTimerTask(), start, interval);
@@ -87,7 +87,7 @@ public class PeriodicTaskExecuter {
* Cleans up this object.
*/
public void shutdown() {
Log.i(MyTracksConstants.TAG,
Log.i(Constants.TAG,
task.getClass().getSimpleName() + " shutting down.");
if (timer != null) {
timer.cancel();
@@ -15,8 +15,7 @@
*/
package com.google.android.apps.mytracks.services;
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.maps.mytracks.R;
import android.content.SharedPreferences;
@@ -45,9 +44,9 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
public PreferenceManager(TrackRecordingService service) {
this.service = service;
this.sharedPreferences = service.getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, 0);
Constants.SETTINGS_NAME, 0);
if (sharedPreferences == null) {
Log.w(MyTracksConstants.TAG,
Log.w(Constants.TAG,
"TrackRecordingService: Couldn't get shared preferences.");
throw new IllegalStateException("Couldn't get shared preferences");
}
@@ -88,7 +87,7 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
if (service == null) {
Log.w(MyTracksConstants.TAG,
Log.w(Constants.TAG,
"onSharedPreferenceChanged: a preference change (key = " + key
+ ") after a call to shutdown()");
return;
@@ -97,20 +96,20 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
service.setMinRecordingDistance(
sharedPreferences.getInt(
minRecordingDistanceKey,
MyTracksSettings.DEFAULT_MIN_RECORDING_DISTANCE));
Log.d(MyTracksConstants.TAG,
Constants.DEFAULT_MIN_RECORDING_DISTANCE));
Log.d(Constants.TAG,
"TrackRecordingService: minRecordingDistance = "
+ service.getMinRecordingDistance());
}
if (key == null || key.equals(maxRecordingDistanceKey)) {
service.setMaxRecordingDistance(sharedPreferences.getInt(
maxRecordingDistanceKey,
MyTracksSettings.DEFAULT_MAX_RECORDING_DISTANCE));
Constants.DEFAULT_MAX_RECORDING_DISTANCE));
}
if (key == null || key.equals(minRecordingIntervalKey)) {
int minRecordingInterval = sharedPreferences.getInt(
minRecordingIntervalKey,
MyTracksSettings.DEFAULT_MIN_RECORDING_INTERVAL);
Constants.DEFAULT_MIN_RECORDING_INTERVAL);
switch (minRecordingInterval) {
case -2:
// Battery Miser
@@ -136,7 +135,7 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
if (key == null || key.equals(minRequiredAccuracyKey)) {
service.setMinRequiredAccuracy(sharedPreferences.getInt(
minRequiredAccuracyKey,
MyTracksSettings.DEFAULT_MIN_REQUIRED_ACCURACY));
Constants.DEFAULT_MIN_REQUIRED_ACCURACY));
}
if (key == null || key.equals(announcementFrequencyKey)) {
service.setAnnouncementFrequency(
@@ -145,7 +144,7 @@ public class PreferenceManager implements OnSharedPreferenceChangeListener {
if (key == null || key.equals(autoResumeTrackTimeoutKey)) {
service.setAutoResumeTrackTimeout(sharedPreferences.getInt(
autoResumeTrackTimeoutKey,
MyTracksSettings.DEFAULT_AUTO_RESUME_TRACK_TIMEOUT));
Constants.DEFAULT_AUTO_RESUME_TRACK_TIMEOUT));
}
if (key == null || key.equals(recordingTrackKey)) {
long recordingTrackId = sharedPreferences.getLong(recordingTrackKey, -1);
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.services;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.util.UnitConversions;
@@ -81,7 +81,7 @@ public class SplitManager {
if (splitFrequency >= 0) {
nextSplitDistance = Double.MAX_VALUE;
Log.d(MyTracksConstants.TAG,
Log.d(Constants.TAG,
"SplitManager: Distance splits disabled.");
return;
}
@@ -94,7 +94,7 @@ public class SplitManager {
int index = (int) (dist / splitFrequency);
index -= 1;
nextSplitDistance = splitFrequency * index;
Log.d(MyTracksConstants.TAG,
Log.d(Constants.TAG,
"SplitManager: Next split distance: " + nextSplitDistance);
}
@@ -126,7 +126,7 @@ public class SplitManager {
* @param splitFrequency The frequency in time or distance
*/
public void setSplitFrequency(int splitFrequency) {
Log.d(MyTracksConstants.TAG,
Log.d(Constants.TAG,
"setSplitFrequency: splitFrequency = " + splitFrequency);
this.splitFrequency = splitFrequency;
@@ -1,12 +1,12 @@
/*
* Copyright 2009 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
@@ -16,8 +16,9 @@
package com.google.android.apps.mytracks.services;
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.stats.TripStatistics;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
@@ -99,7 +100,7 @@ public class StatusAnnouncerTask implements PeriodicTask {
* Called when the TTS engine is initialized.
*/
protected void onTtsInit(int status) {
Log.i(MyTracksConstants.TAG, "TrackRecordingService.TTS init: " + status);
Log.i(TAG, "TrackRecordingService.TTS init: " + status);
this.ready = status == TextToSpeech.SUCCESS;
if (ready) {
@@ -111,7 +112,7 @@ public class StatusAnnouncerTask implements PeriodicTask {
languageAvailability == TextToSpeech.LANG_NOT_SUPPORTED) {
// English is probably supported.
// TODO: Somehow use announcement strings from English too.
Log.w(MyTracksConstants.TAG, "Default language not available, using English.");
Log.w(TAG, "Default language not available, using English.");
speechLanguage = Locale.ENGLISH;
}
tts.setLanguage(speechLanguage);
@@ -129,7 +130,7 @@ public class StatusAnnouncerTask implements PeriodicTask {
@Override
public void run(TrackRecordingService service) {
if (service == null) {
Log.e(MyTracksConstants.TAG, "StatusAnnouncer TrackRecordingService not initialized");
Log.e(TAG, "StatusAnnouncer TrackRecordingService not initialized");
return;
}
@@ -143,23 +144,22 @@ public class StatusAnnouncerTask implements PeriodicTask {
*/
protected void runWithStatistics(TripStatistics statistics) {
if (statistics == null) {
Log.e(MyTracksConstants.TAG, "StatusAnnouncer stats not initialized.");
Log.e(TAG, "StatusAnnouncer stats not initialized.");
return;
}
if (!ready || tts == null) {
Log.e(MyTracksConstants.TAG, "StatusAnnouncer Tts not ready.");
Log.e(TAG, "StatusAnnouncer Tts not ready.");
return;
}
if (!speechAllowed) {
Log.i(MyTracksConstants.TAG,
Log.i(Constants.TAG,
"Not making announcement - not allowed at this time");
return;
}
String announcement = getAnnouncement(statistics);
Log.d(MyTracksConstants.TAG, "Announcement: " + announcement);
Log.d(Constants.TAG, "Announcement: " + announcement);
speakAnnouncment(announcement);
}
@@ -175,11 +175,11 @@ public class StatusAnnouncerTask implements PeriodicTask {
// @VisibleForTesting
protected String getAnnouncement(TripStatistics stats) {
SharedPreferences preferences =
context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
boolean metricUnits = true;
boolean reportSpeed = true;
if (preferences != null) {
metricUnits =
metricUnits =
preferences.getBoolean(context.getString(R.string.metric_units_key),
true);
reportSpeed =
@@ -218,7 +218,7 @@ public class StatusAnnouncerTask implements PeriodicTask {
speed = String.format("%.1f", s);
} else {
double pace = 3600000.0 / s;
Log.w(MyTracksConstants.TAG,
Log.w(Constants.TAG,
"Converted speed: " + s + " to pace: " + pace);
speed = stringUtils.formatTimeLong((long) pace);
}
@@ -237,7 +237,7 @@ public class StatusAnnouncerTask implements PeriodicTask {
@Override
public void start() {
Log.i(MyTracksConstants.TAG, "Starting TTS");
Log.i(Constants.TAG, "Starting TTS");
if (tts == null) {
// We can't have this class also be the listener, otherwise it's unsafe to
// reference it in Cupcake (even if we don't instantiate it).
@@ -264,7 +264,7 @@ public class StatusAnnouncerTask implements PeriodicTask {
tts = null;
}
Log.i(MyTracksConstants.TAG, "TTS shut down");
Log.i(Constants.TAG, "TTS shut down");
}
/**
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.services;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.Constants;
import android.util.Log;
@@ -49,14 +49,14 @@ public class TaskExecuterManager {
*/
public void setFrequency(int frequency, TrackRecordingService service) {
this.frequency = frequency;
Log.i(MyTracksConstants.TAG, "Frequency set to " + frequency
Log.i(Constants.TAG, "Frequency set to " + frequency
+ " for task " + task.getClass().getSimpleName());
if (frequency == -1) {
if (executer != null) {
executer.shutdown();
executer = null;
Log.i(MyTracksConstants.TAG,
Log.i(Constants.TAG,
"Shut down service: " + task.getClass().getSimpleName());
}
} else {
@@ -15,27 +15,27 @@
*/
package com.google.android.apps.mytracks.services;
import static com.google.android.apps.mytracks.MyTracksConstants.RESUME_TRACK_EXTRA_NAME;
import static com.google.android.apps.mytracks.Constants.TAG;
import static com.google.android.apps.mytracks.Constants.RESUME_TRACK_EXTRA_NAME;
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.MyTracksLocation;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.content.WaypointsColumns;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.services.sensors.SensorManager;
import com.google.android.apps.mytracks.services.sensors.SensorManagerFactory;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.apps.mytracks.util.ApiPlatformAdapter;
import com.google.android.apps.mytracks.util.MyTracksUtils;
import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
@@ -80,14 +80,14 @@ public class TrackRecordingService extends Service implements LocationListener {
private WakeLock wakeLock;
private int minRecordingDistance =
MyTracksSettings.DEFAULT_MIN_RECORDING_DISTANCE;
Constants.DEFAULT_MIN_RECORDING_DISTANCE;
private int maxRecordingDistance =
MyTracksSettings.DEFAULT_MAX_RECORDING_DISTANCE;
Constants.DEFAULT_MAX_RECORDING_DISTANCE;
private int minRequiredAccuracy =
MyTracksSettings.DEFAULT_MIN_REQUIRED_ACCURACY;
Constants.DEFAULT_MIN_REQUIRED_ACCURACY;
private int autoResumeTrackTimeout =
MyTracksSettings.DEFAULT_AUTO_RESUME_TRACK_TIMEOUT;
Constants.DEFAULT_AUTO_RESUME_TRACK_TIMEOUT;
private long recordingTrackId = -1;
private long currentWaypointId = -1;
@@ -117,9 +117,9 @@ public class TrackRecordingService extends Service implements LocationListener {
private SplitManager splitManager;
private SensorManager sensorManager;
private PreferenceManager prefManager;
/**
* The interval in milliseconds that we have requested to be notified of gps
* readings.
@@ -144,7 +144,7 @@ public class TrackRecordingService extends Service implements LocationListener {
if (isRecording()) {
handler.post(new Runnable() {
public void run() {
Log.d(MyTracksConstants.TAG,
Log.d(Constants.TAG,
"Re-registering location listener with TrackRecordingService.");
unregisterLocationListener();
registerLocationListener();
@@ -168,7 +168,7 @@ public class TrackRecordingService extends Service implements LocationListener {
* The most recent recording track.
*/
private Track recordingTrack;
/**
* Is the service currently recording a track?
*/
@@ -214,7 +214,7 @@ public class TrackRecordingService extends Service implements LocationListener {
// Keep track of length along recorded track (needed when a waypoint is
// inserted):
if (MyTracksUtils.isValidLocation(location)) {
if (LocationUtils.isValidLocation(location)) {
if (lastValidLocation != null) {
length += location.distanceTo(lastValidLocation);
}
@@ -269,7 +269,7 @@ public class TrackRecordingService extends Service implements LocationListener {
// Insert failed, most likely because of SqlLite error code 5
// (SQLite_BUSY). This is expected to happen extremely rarely (if our
// listener gets invoked twice at about the same time).
Log.w(MyTracksConstants.TAG,
Log.w(TAG,
"Caught SQLiteException: " + e.getMessage(), e);
return false;
}
@@ -314,15 +314,15 @@ public class TrackRecordingService extends Service implements LocationListener {
try {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (pm == null) {
Log.e(MyTracksConstants.TAG,
Log.e(TAG,
"TrackRecordingService: Power manager not found!");
return;
}
if (wakeLock == null) {
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
MyTracksConstants.TAG);
TAG);
if (wakeLock == null) {
Log.e(MyTracksConstants.TAG,
Log.e(TAG,
"TrackRecordingService: Could not create wake lock (null).");
return;
}
@@ -330,12 +330,12 @@ public class TrackRecordingService extends Service implements LocationListener {
if (!wakeLock.isHeld()) {
wakeLock.acquire();
if (!wakeLock.isHeld()) {
Log.e(MyTracksConstants.TAG,
Log.e(TAG,
"TrackRecordingService: Could not acquire wake lock.");
}
}
} catch (RuntimeException e) {
Log.e(MyTracksConstants.TAG,
Log.e(TAG,
"TrackRecordingService: Caught unexpected exception: "
+ e.getMessage(), e);
}
@@ -376,40 +376,40 @@ public class TrackRecordingService extends Service implements LocationListener {
public void registerLocationListener() {
if (locationManager == null) {
Log.e(MyTracksConstants.TAG,
Log.e(TAG,
"TrackRecordingService: Do not have any location manager.");
return;
}
Log.d(MyTracksConstants.TAG,
Log.d(TAG,
"Preparing to register location listener w/ TrackRecordingService...");
try {
long desiredInterval = locationListenerPolicy.getDesiredPollingInterval();
locationManager.requestLocationUpdates(
MyTracksConstants.GPS_PROVIDER, desiredInterval,
Constants.GPS_PROVIDER, desiredInterval,
locationListenerPolicy.getMinDistance(),
// , 0 /* minDistance, get all updates to properly time pauses */
TrackRecordingService.this);
currentRecordingInterval = desiredInterval;
Log.d(MyTracksConstants.TAG,
Log.d(TAG,
"...location listener now registered w/ TrackRecordingService @ "
+ currentRecordingInterval);
} catch (RuntimeException e) {
Log.e(MyTracksConstants.TAG,
Log.e(TAG,
"Could not register location listener: " + e.getMessage(), e);
}
}
public void unregisterLocationListener() {
if (locationManager == null) {
Log.e(MyTracksConstants.TAG,
Log.e(TAG,
"TrackRecordingService: Do not have any location manager.");
return;
}
locationManager.removeUpdates(this);
Log.d(MyTracksConstants.TAG,
Log.d(TAG,
"Location listener now unregistered w/ TrackRecordingService.");
}
private Track getRecordingTrack() {
if (recordingTrackId < 0) {
return null;
@@ -419,9 +419,9 @@ public class TrackRecordingService extends Service implements LocationListener {
}
private void restoreStats(Track track) {
Log.d(MyTracksConstants.TAG,
Log.d(TAG,
"Restoring stats of track with ID: " + track.getId());
TripStatistics stats = track.getStatistics();
statsBuilder = new TripStatisticsBuilder(stats.getStartTime());
statsBuilder.setMinRecordingDistance(minRecordingDistance);
@@ -446,13 +446,13 @@ public class TrackRecordingService extends Service implements LocationListener {
Cursor cursor = null;
try {
cursor = providerUtils.getLocationsCursor(
recordingTrackId, -1, MyTracksConstants.MAX_LOADED_TRACK_POINTS,
recordingTrackId, -1, Constants.MAX_LOADED_TRACK_POINTS,
true);
if (cursor != null) {
if (cursor.moveToLast()) {
do {
Location location = providerUtils.createLocation(cursor);
if (MyTracksUtils.isValidLocation(location)) {
if (LocationUtils.isValidLocation(location)) {
statsBuilder.addLocation(location, location.getTime());
if (lastValidLocation != null) {
length += location.distanceTo(lastValidLocation);
@@ -465,10 +465,10 @@ public class TrackRecordingService extends Service implements LocationListener {
statsBuilder.pauseAt(stats.getStopTime());
statsBuilder.resumeAt(System.currentTimeMillis());
} else {
Log.e(MyTracksConstants.TAG, "Could not get track points cursor.");
Log.e(TAG, "Could not get track points cursor.");
}
} catch (RuntimeException e) {
Log.e(MyTracksConstants.TAG, "Error while restoring track.", e);
Log.e(TAG, "Error while restoring track.", e);
} finally {
if (cursor != null) {
cursor.close();
@@ -493,12 +493,12 @@ public class TrackRecordingService extends Service implements LocationListener {
}
private void onLocationChangedAsync(Location location) {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.onLocationChanged");
Log.d(TAG, "TrackRecordingService.onLocationChanged");
try {
// Don't record if the service has been asked to pause recording:
if (!isRecording) {
Log.w(MyTracksConstants.TAG,
Log.w(TAG,
"Not recording because recording has been paused.");
return;
}
@@ -506,14 +506,14 @@ public class TrackRecordingService extends Service implements LocationListener {
// This should never happen, but just in case (we really don't want the
// service to crash):
if (location == null) {
Log.w(MyTracksConstants.TAG,
Log.w(TAG,
"Location changed, but location is null.");
return;
}
// Don't record if the accuracy is too bad:
if (location.getAccuracy() > minRequiredAccuracy) {
Log.d(MyTracksConstants.TAG,
Log.d(TAG,
"Not recording. Bad accuracy.");
return;
}
@@ -521,7 +521,7 @@ public class TrackRecordingService extends Service implements LocationListener {
// At least one track must be available for appending points:
recordingTrack = getRecordingTrack();
if (recordingTrack == null) {
Log.d(MyTracksConstants.TAG,
Log.d(TAG,
"Not recording. No track to append to available.");
return;
}
@@ -555,7 +555,7 @@ public class TrackRecordingService extends Service implements LocationListener {
// maxRecordingDistance = 0
if (distanceToLast == 0 && !hasSensorData) {
if (isMoving) {
Log.d(MyTracksConstants.TAG, "Found two identical locations.");
Log.d(TAG, "Found two identical locations.");
isMoving = false;
if (lastLocation != null && lastRecordedLocation != null
&& !lastRecordedLocation.equals(lastLocation)) {
@@ -570,7 +570,7 @@ public class TrackRecordingService extends Service implements LocationListener {
lastRecordedLocationId++;
}
} else {
Log.d(MyTracksConstants.TAG,
Log.d(TAG,
"Not recording. More than two identical locations.");
}
} else if (distanceToLastRecorded > minRecordingDistance
@@ -595,8 +595,8 @@ public class TrackRecordingService extends Service implements LocationListener {
&& recordingTrack.getStartId() >= 0;
if (startNewSegment) {
// Insert a separator point to indicate start of new track:
Log.d(MyTracksConstants.TAG, "Inserting a separator.");
Location separator = new Location(MyTracksConstants.GPS_PROVIDER);
Log.d(TAG, "Inserting a separator.");
Location separator = new Location(Constants.GPS_PROVIDER);
separator.setLongitude(0);
separator.setLatitude(100);
separator.setTime(lastRecordedLocation.getTime());
@@ -608,7 +608,7 @@ public class TrackRecordingService extends Service implements LocationListener {
return;
}
} else {
Log.d(MyTracksConstants.TAG, String.format(
Log.d(TAG, String.format(
"Not recording. Distance to last recorded point (%f m) is less than"
+ " %d m.", distanceToLastRecorded, minRecordingDistance));
// Return here so that the location is NOT recorded as the last location.
@@ -616,11 +616,11 @@ public class TrackRecordingService extends Service implements LocationListener {
}
} catch (Error e) {
// Probably important enough to rethrow.
Log.e(MyTracksConstants.TAG, "Error in onLocationChanged", e);
Log.e(TAG, "Error in onLocationChanged", e);
throw e;
} catch (RuntimeException e) {
// Safe usually to trap exceptions.
Log.e(MyTracksConstants.TAG,
Log.e(TAG,
"Trapping exception in onLocationChanged", e);
throw e;
}
@@ -628,7 +628,7 @@ public class TrackRecordingService extends Service implements LocationListener {
}
private void addLocationToStats(Location location) {
if (MyTracksUtils.isValidLocation(location)) {
if (LocationUtils.isValidLocation(location)) {
long now = System.currentTimeMillis();
statsBuilder.addLocation(location, now);
waypointStatsBuilder.addLocation(location, now);
@@ -657,7 +657,7 @@ public class TrackRecordingService extends Service implements LocationListener {
@Override
public void onCreate() {
super.onCreate();
Log.d(MyTracksConstants.TAG, "TrackRecordingService.onCreate");
Log.d(TAG, "TrackRecordingService.onCreate");
providerUtils = MyTracksProviderUtils.Factory.get(this);
notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
@@ -682,7 +682,7 @@ public class TrackRecordingService extends Service implements LocationListener {
} else {
if (recordingTrackId != -1) {
// Make sure we have consistent state in shared preferences.
Log.w(MyTracksConstants.TAG, "TrackRecordingService.onCreate: "
Log.w(TAG, "TrackRecordingService.onCreate: "
+ "Resetting an orphaned recording track = " + recordingTrackId);
}
prefManager.setRecordingTrack(recordingTrackId = -1);
@@ -697,7 +697,7 @@ public class TrackRecordingService extends Service implements LocationListener {
* the announcements, otherwise this method is no-op.
*/
private void setUpAnnouncer() {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.setUpAnnouncer: "
Log.d(TAG, "TrackRecordingService.setUpAnnouncer: "
+ announcementExecuter);
if (announcementFrequency != -1 && recordingTrackId != -1) {
handler.post(new Runnable() {
@@ -721,9 +721,9 @@ public class TrackRecordingService extends Service implements LocationListener {
});
}
}
private void shutdownAnnouncer() {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.shutdownAnnouncer: "
Log.d(TAG, "TrackRecordingService.shutdownAnnouncer: "
+ announcementExecuter);
if (announcementExecuter != null) {
try {
@@ -736,7 +736,7 @@ public class TrackRecordingService extends Service implements LocationListener {
@Override
public void onDestroy() {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.onDestroy");
Log.d(TAG, "TrackRecordingService.onDestroy");
isRecording = false;
showNotification();
@@ -764,29 +764,29 @@ public class TrackRecordingService extends Service implements LocationListener {
// This should be the last operation.
releaseWakeLock();
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.onBind");
Log.d(TAG, "TrackRecordingService.onBind");
return binder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.onUnbind");
Log.d(TAG, "TrackRecordingService.onUnbind");
return super.onUnbind(intent);
}
@Override
public boolean stopService(Intent name) {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.stopService");
Log.d(TAG, "TrackRecordingService.stopService");
unregisterLocationListener();
return super.stopService(name);
}
@Override
public void onStart(Intent intent, int startId) {
handleStartCommand(intent, startId);
@@ -799,50 +799,50 @@ public class TrackRecordingService extends Service implements LocationListener {
}
private void handleStartCommand(Intent intent, int startId) {
Log.d(MyTracksConstants.TAG,
Log.d(TAG,
"TrackRecordingService.handleStartCommand: " + startId);
// Check if called on phone reboot with resume intent.
if (intent != null &&
intent.getBooleanExtra(RESUME_TRACK_EXTRA_NAME, false)) {
Log.d(MyTracksConstants.TAG, "TrackRecordingService: requested resume");
Log.d(TAG, "TrackRecordingService: requested resume");
// Make sure that the current track exists and is fresh enough.
if (recordingTrack == null || !shouldResumeTrack(recordingTrack)) {
Log.i(MyTracksConstants.TAG,
Log.i(TAG,
"TrackRecordingService: Not resuming, because the previous track ("
+ recordingTrack + ") doesn't exist or is too old");
isRecording = false;
prefManager.setRecordingTrack(recordingTrackId = -1);
prefManager.setRecordingTrack(recordingTrackId = -1);
stopSelfResult(startId);
return;
}
Log.i(MyTracksConstants.TAG, "TrackRecordingService: resuming");
Log.i(TAG, "TrackRecordingService: resuming");
}
}
private void setAutoResumeTrackRetries(
SharedPreferences sharedPreferences, int retryAttempts) {
Log.d(MyTracksConstants.TAG,
Log.d(TAG,
"Updating auto-resume retry attempts to: " + retryAttempts);
prefManager.setAutoResumeTrackCurrentRetry(retryAttempts);
}
private boolean shouldResumeTrack(Track track) {
Log.d(MyTracksConstants.TAG, "shouldResumeTrack: autoResumeTrackTimeout = "
Log.d(TAG, "shouldResumeTrack: autoResumeTrackTimeout = "
+ autoResumeTrackTimeout);
// Check if we haven't exceeded the maximum number of retry attempts.
SharedPreferences sharedPreferences =
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
getSharedPreferences(Constants.SETTINGS_NAME, 0);
int retries = sharedPreferences.getInt(
getString(R.string.auto_resume_track_current_retry_key), 0);
Log.d(MyTracksConstants.TAG,
Log.d(TAG,
"shouldResumeTrack: Attempting to auto-resume the track ("
+ (retries + 1) + "/" + MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS + ")");
if (retries >= MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS) {
Log.i(MyTracksConstants.TAG,
Log.i(TAG,
"shouldResumeTrack: Not resuming because exceeded the maximum "
+ "number of auto-resume retries");
return false;
@@ -853,13 +853,13 @@ public class TrackRecordingService extends Service implements LocationListener {
// Check for special cases.
if (autoResumeTrackTimeout == 0) {
// Never resume.
Log.d(MyTracksConstants.TAG,
// Never resume.
Log.d(TAG,
"shouldResumeTrack: Auto-resume disabled (never resume)");
return false;
} else if (autoResumeTrackTimeout == -1) {
// Always resume.
Log.d(MyTracksConstants.TAG,
Log.d(TAG,
"shouldResumeTrack: Auto-resume forced (always resume)");
return true;
}
@@ -867,11 +867,11 @@ public class TrackRecordingService extends Service implements LocationListener {
// Check if the last modified time is within the acceptable range.
long lastModified =
track.getStatistics() != null ? track.getStatistics().getStopTime() : 0;
Log.d(MyTracksConstants.TAG,
Log.d(TAG,
"shouldResumeTrack: lastModified = " + lastModified
+ ", autoResumeTrackTimeout: " + autoResumeTrackTimeout);
return lastModified > 0 && System.currentTimeMillis() - lastModified <=
autoResumeTrackTimeout * 60 * 1000;
autoResumeTrackTimeout * 60 * 1000;
}
public boolean isRecording() {
@@ -897,7 +897,8 @@ public class TrackRecordingService extends Service implements LocationListener {
}
wpt.setTrackId(recordingTrackId);
wpt.setLength(length);
if (lastValidLocation == null) {
if (lastLocation == null
|| statsBuilder == null || statsBuilder.getStatistics() == null) {
// A null location is ok, and expected on track start.
// Make it an impossible location.
Location l = new Location("");
@@ -905,11 +906,9 @@ public class TrackRecordingService extends Service implements LocationListener {
l.setLongitude(180);
wpt.setLocation(l);
} else {
// A null location is ok, and expected on track start.
wpt.setLocation(lastLocation);
if (lastLocation != null) {
wpt.setDuration(lastLocation.getTime() - statsBuilder.getStatistics().getStartTime());
}
wpt.setDuration(lastLocation.getTime()
- statsBuilder.getStatistics().getStartTime());
}
Uri uri = providerUtils.insertWaypoint(wpt);
return Long.parseLong(uri.getLastPathSegment());
@@ -962,27 +961,27 @@ public class TrackRecordingService extends Service implements LocationListener {
// Create a new stats keeper for the next marker.
waypointStatsBuilder = new TripStatisticsBuilder(time);
}
private ServiceBinder binder = new ServiceBinder(this);
/**
* TODO: There is a bug in Android that leaks Binder instances. This bug is
* especially visible if we have a non-static class, as there is no way to
* nullify reference to the outer class (the service).
* A workaround is to use a static class and explicitly clear service
* and detach it from the underlying Binder. With this approach, we minimize
* the leak to 24 bytes per each service instance.
* the leak to 24 bytes per each service instance.
*
* For more details, see the following bug:
* http://code.google.com/p/android/issues/detail?id=6426.
*/
private static class ServiceBinder extends ITrackRecordingService.Stub {
private TrackRecordingService service;
public ServiceBinder(TrackRecordingService service) {
this.service = service;
}
/**
* Clears the reference to the outer class to minimize the leak.
*/
@@ -990,7 +989,7 @@ public class TrackRecordingService extends Service implements LocationListener {
this.service = null;
attachInterface(null, null);
}
@Override
public boolean isRecording() {
checkService();
@@ -1005,13 +1004,13 @@ public class TrackRecordingService extends Service implements LocationListener {
@Override
public long getRecordingTrackId() {
checkService();
checkService();
return service.recordingTrackId;
}
@Override
public boolean hasRecorded() {
checkService();
checkService();
return service.providerUtils.getLastTrackId() >= 0;
}
@@ -1049,19 +1048,19 @@ public class TrackRecordingService extends Service implements LocationListener {
@Override
public void recordLocation(Location loc) {
checkService();
checkService();
service.onLocationChanged(loc);
}
@Override
public byte[] getSensorData() {
checkService();
checkService();
if (service.sensorManager == null) {
Log.d(MyTracksConstants.TAG, "No sensor manager for data.");
Log.d(TAG, "No sensor manager for data.");
return null;
}
if (service.sensorManager.getSensorDataSet() == null) {
Log.d(MyTracksConstants.TAG, "Sensor data set is null.");
Log.d(TAG, "Sensor data set is null.");
return null;
}
return service.sensorManager.getSensorDataSet().toByteArray();
@@ -1069,9 +1068,9 @@ public class TrackRecordingService extends Service implements LocationListener {
@Override
public int getSensorState() {
checkService();
checkService();
if (service.sensorManager == null) {
Log.d(MyTracksConstants.TAG, "No sensor manager for data.");
Log.d(TAG, "No sensor manager for data.");
return Sensor.SensorState.NONE.getNumber();
}
return service.sensorManager.getSensorState().getNumber();
@@ -1079,7 +1078,7 @@ public class TrackRecordingService extends Service implements LocationListener {
}
public long startNewTrack() {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.startNewTrack");
Log.d(TAG, "TrackRecordingService.startNewTrack");
if (recordingTrackId != -1 || isRecording) {
throw new IllegalStateException("A track is already in progress!");
}
@@ -1117,7 +1116,7 @@ public class TrackRecordingService extends Service implements LocationListener {
// Reset the number of auto-resume retries.
setAutoResumeTrackRetries(
getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0), 0);
getSharedPreferences(Constants.SETTINGS_NAME, 0), 0);
// Persist the current recording track.
prefManager.setRecordingTrack(recordingTrackId);
@@ -1129,7 +1128,7 @@ public class TrackRecordingService extends Service implements LocationListener {
}
private void endCurrentTrack() {
Log.d(MyTracksConstants.TAG, "TrackRecordingService.endCurrentTrack");
Log.d(TAG, "TrackRecordingService.endCurrentTrack");
if (recordingTrackId == -1 || !isRecording) {
throw new IllegalStateException("No recording track in progress!");
}
@@ -1156,12 +1155,12 @@ public class TrackRecordingService extends Service implements LocationListener {
showNotification();
long recordedTrackId = recordingTrackId;
prefManager.setRecordingTrack(recordingTrackId = -1);
if (sensorManager != null) {
sensorManager.shutdown();
sensorManager = null;
}
releaseWakeLock();
// Notify the world that we're no longer recording.
@@ -1243,11 +1242,11 @@ public class TrackRecordingService extends Service implements LocationListener {
LocationListenerPolicy locationListenerPolicy) {
this.locationListenerPolicy = locationListenerPolicy;
}
public int getAutoResumeTrackTimeout() {
return autoResumeTrackTimeout;
}
public void setAutoResumeTrackTimeout(int autoResumeTrackTimeout) {
this.autoResumeTrackTimeout = autoResumeTrackTimeout;
}
@@ -15,17 +15,18 @@
*/
package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.dsi.ant.AntDefine;
import com.dsi.ant.AntMesg;
import com.dsi.ant.exception.AntInterfaceException;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.services.sensors.ant.AntChannelIdMessage;
import com.google.android.apps.mytracks.services.sensors.ant.AntChannelResponseMessage;
import com.google.android.maps.mytracks.R;
import com.dsi.ant.AntDefine;
import com.dsi.ant.AntMesg;
import com.dsi.ant.exception.AntInterfaceException;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
@@ -58,7 +59,7 @@ public class AntDirectSensorManager extends AntSensorManager {
// First read the the device id that we will be pairing with.
SharedPreferences prefs = context.getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, 0);
Constants.SETTINGS_NAME, 0);
if (prefs != null) {
deviceNumberHRM =
(short) prefs.getInt(context.getString(R.string.ant_heart_rate_sensor_id_key), 0);
@@ -133,7 +134,7 @@ public class AntDirectSensorManager extends AntSensorManager {
Log.i(TAG, "Found device id: " + deviceNumberHRM);
SharedPreferences prefs = context.getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, Context.MODE_PRIVATE);
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putInt(context.getString(R.string.ant_heart_rate_sensor_id_key), deviceNumberHRM);
editor.commit();
@@ -15,14 +15,13 @@
*/
package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.maps.mytracks.R;
import com.dsi.ant.AntDefine;
import com.dsi.ant.AntMesg;
import com.dsi.ant.exception.AntInterfaceException;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.SharedPreferences;
@@ -71,7 +70,7 @@ public class AntSRMSensorManager extends AntSensorManager {
// First read the the device id that we will be announcing.
SharedPreferences prefs = context.getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, 0);
Constants.SETTINGS_NAME, 0);
if (prefs != null) {
deviceId = (byte) prefs.getInt(
context.getString(R.string.ant_srm_bridge_sensor_id_key),
@@ -82,10 +81,10 @@ public class AntSRMSensorManager extends AntSensorManager {
@Override
public void handleMessage(byte[] antMessage) {
// Parse channel number
byte receivedChannel = (byte) (antMessage[AntMesg.MESG_DATA_OFFSET]
byte recievedChannel = (byte) (antMessage[AntMesg.MESG_DATA_OFFSET]
& AntDefine.CHANNEL_NUMBER_MASK);
if (receivedChannel != channel) {
Log.d(TAG, "Unexpected channel: " + receivedChannel);
if (recievedChannel != channel) {
Log.d(Constants.TAG, "Unexpected channel: " + recievedChannel);
return;
}
switch (antMessage[AntMesg.MESG_ID_OFFSET]) {
@@ -99,17 +98,18 @@ public class AntSRMSensorManager extends AntSensorManager {
handleChannelId(antMessage);
break;
default:
Log.e(TAG, "Unexpected message id: " + antMessage[3]);
Log.e(Constants.TAG,
"Unexpected message id: " + antMessage[3]);
}
}
private void handleBroadcastData(byte[] antMessage) {
if (deviceId == WILDCARD) {
try {
Log.d(TAG, "Requesting channel id id.");
Log.d(Constants.TAG, "Requesting channel id id.");
getAntReceiver().ANTRequestMessage(channel, AntMesg.MESG_CHANNEL_ID_ID);
} catch (AntInterfaceException e) {
Log.e(TAG, "Failed to request channel id id", e);
Log.e(Constants.TAG, "Failed to request channel id id", e);
}
}
setSensorState(Sensor.SensorState.CONNECTED);
@@ -121,17 +121,18 @@ public class AntSRMSensorManager extends AntSensorManager {
parseSensorData(antMessage);
break;
default:
Log.e(TAG, "Unexpected message type: " + antMessage[MESSAGE_TYPE_INDEX]);
Log.e(Constants.TAG,
"Unexpected message type: " + antMessage[MESSAGE_TYPE_INDEX]);
}
}
private void handleChannelId(byte[] antMessage) {
// Store the device id.
deviceId = antMessage[3];
Log.i(TAG, "Found device id: " + deviceId);
Log.i(Constants.TAG, "Found device id: " + deviceId);
SharedPreferences prefs = context.getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, Context.MODE_PRIVATE);
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putInt(context.getString(R.string.ant_srm_bridge_sensor_id_key), deviceId);
editor.commit();
@@ -141,34 +142,38 @@ public class AntSRMSensorManager extends AntSensorManager {
if (antMessage[3] == AntMesg.MESG_EVENT_ID
&& antMessage[4] == AntDefine.EVENT_RX_SEARCH_TIMEOUT) {
// Search timeout
Log.w(TAG, "Search timed out. Unassigning channel.");
Log.w(Constants.TAG, "Search timed out. Unassigning channel.");
try {
getAntReceiver().ANTUnassignChannel(channel);
} catch (AntInterfaceException e) {
Log.e(TAG, "Failed to unassign ANT channel", e);
Log.e(Constants.TAG, "Failed to unassign ANT channel", e);
}
setSensorState(Sensor.SensorState.DISCONNECTED);
} else if (antMessage[3] == AntMesg.MESG_UNASSIGN_CHANNEL_ID) {
setSensorState(Sensor.SensorState.DISCONNECTED);
Log.i(TAG, "Disconnected from the sensor: " + getSensorState());
Log.i(Constants.TAG,
"Disconnected from the sensor: " + getSensorState());
}
}
private void parseSensorData(byte[] antMessage) {
if (antMessage.length != 11) {
Log.e(TAG, "Unexpected ant message length: " + antMessage.length);
Log.e(Constants.TAG,
"Unexpected ant message length: " + antMessage.length);
return;
}
int newMessageId = antMessage[MESSAGE_ID_INDEX] & 0xFF;
if (lastMessageId == newMessageId) {
// Repeated message.
Log.i(TAG, String.format("SRM ignoring repeat: 0x%X", newMessageId));
Log.i(Constants.TAG,
String.format("SRM ignoring repeat: 0x%X", newMessageId));
return;
}
if (newMessageId < lastMessageId) {
if (!(newMessageId < 20 && lastMessageId > 200)) {
Log.i(TAG, String.format("SRM ignoring repeat: 0x%X", newMessageId));
Log.i(Constants.TAG,
String.format("SRM ignoring repeat: 0x%X", newMessageId));
return;
} // else assume the byte overflowed to 0.
}
@@ -15,16 +15,16 @@
*/
package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.services.sensors.ant.AntStartupMessage;
import com.dsi.ant.AntDefine;
import com.dsi.ant.AntInterface;
import com.dsi.ant.AntInterfaceIntent;
import com.dsi.ant.AntMesg;
import com.dsi.ant.exception.AntInterfaceException;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.services.sensors.ant.AntStartupMessage;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -84,7 +84,7 @@ public abstract class AntSensorManager extends SensorManager {
@Override
public void onReceive(Context context, Intent intent) {
String antAction = intent.getAction();
Log.i(TAG, "enter status onReceive" + antAction);
Log.i(Constants.TAG, "enter status onReceive" + antAction);
}
};
@@ -93,12 +93,12 @@ public abstract class AntSensorManager extends SensorManager {
@Override
public void onReceive(Context context, Intent intent) {
String antAction = intent.getAction();
Log.i(TAG, "enter data onReceive" + antAction);
Log.i(Constants.TAG, "enter data onReceive" + antAction);
if (antAction.equals(AntInterfaceIntent.ANT_RX_MESSAGE_ACTION)) {
byte[] antMessage = intent.getByteArrayExtra(AntInterfaceIntent.ANT_MESSAGE);
if (DEBUGGING) {
Log.d(TAG, "Received RX message " + messageToString(antMessage));
Log.d(Constants.TAG, "Received RX message " + messageToString(antMessage));
}
handleMessage(antMessage);
@@ -119,7 +119,7 @@ public abstract class AntSensorManager extends SensorManager {
@Override
public void onServiceDisconnected() {
Log.d(TAG, "ANT interface reports disconnection");
Log.d(Constants.TAG, "ANT interface reports disconnection");
}
};
@@ -129,14 +129,14 @@ public abstract class AntSensorManager extends SensorManager {
@Override
public void onDestroy() {
Log.i(TAG, "destroying AntSensorManager");
Log.i(Constants.TAG, "destroying AntSensorManager");
context.unregisterReceiver(statusReceiver);
context.unregisterReceiver(dataReceiver);
try {
antReceiver.releaseInterface();
} catch (AntInterfaceException e) {
Log.e(TAG, "failed to release ANT interface", e);
Log.e(Constants.TAG, "failed to release ANT interface", e);
}
antReceiver.destroy();
@@ -177,7 +177,7 @@ public abstract class AntSensorManager extends SensorManager {
antReceiver = AntInterface.getInstance(context, antServiceListener);
if (antReceiver == null) {
Log.e(TAG, "Failed to get ANT Receiver");
Log.e(Constants.TAG, "Failed to get ANT Receiver");
return;
}
@@ -190,11 +190,11 @@ public abstract class AntSensorManager extends SensorManager {
* to initiate any ANT commands.
*/
private synchronized void serviceConnected() {
Log.d(TAG, "ANT service connected");
Log.d(Constants.TAG, "ANT service connected");
try {
if (!antReceiver.claimInterface()) {
Log.e(TAG, "failed to claim ANT interface");
Log.e(Constants.TAG, "failed to claim ANT interface");
return;
}
@@ -202,14 +202,14 @@ public abstract class AntSensorManager extends SensorManager {
// Make sure not to call AntInterface.enable() again, if it has been
// already called before
if (antInterrupted == false) {
Log.i(TAG, "Powering on Radio");
Log.i(Constants.TAG, "Powering on Radio");
antReceiver.enable();
}
} else {
Log.i(TAG, "Radio already enabled");
Log.i(Constants.TAG, "Radio already enabled");
}
} catch (AntInterfaceException e) {
Log.e(TAG, "failed to enable ANT", e);
Log.e(Constants.TAG, "failed to enable ANT", e);
}
try {
@@ -220,7 +220,7 @@ public abstract class AntSensorManager extends SensorManager {
// that message.
antReceiver.ANTResetSystem();
} catch (AntInterfaceException e) {
Log.e(TAG, "failed to reset ANT (expected exception)", e);
Log.e(Constants.TAG, "failed to reset ANT (expected exception)", e);
}
}
@@ -232,7 +232,7 @@ public abstract class AntSensorManager extends SensorManager {
protected void handleMessage(byte[] antMessage) {
int len = antMessage[0];
if (len != antMessage.length - 2 || antMessage.length <= 2) {
Log.e(TAG, "Invalid message: " + messageToString(antMessage));
Log.e(Constants.TAG, "Invalid message: " + messageToString(antMessage));
return;
}
@@ -253,7 +253,8 @@ public abstract class AntSensorManager extends SensorManager {
*/
protected boolean handleMessage(byte messageId, byte[] messageData) {
if (messageId == AntMesg.MESG_STARTUP_MESG_ID) {
Log.d(TAG, String.format("Received startup message (reason %02x); initializing channel",
Log.d(Constants.TAG, String.format(
"Received startup message (reason %02x); initializing channel",
new AntStartupMessage(messageData).getMessage()));
setupAntSensorChannels();
return true;
@@ -304,13 +305,13 @@ public abstract class AntSensorManager extends SensorManager {
return true;
} catch (AntInterfaceException e) {
Log.e(TAG, "failed to setup ANT channel", e);
Log.e(Constants.TAG, "failed to setup ANT channel", e);
return false;
}
}
private void registerForAntIntents() {
Log.i(TAG, "Registering for ant intents.");
Log.i(Constants.TAG, "Registering for ant intents.");
// Register for ANT intent broadcasts.
IntentFilter statusIntentFilter = new IntentFilter();
statusIntentFilter.addAction(AntInterfaceIntent.ANT_ENABLED_ACTION);
@@ -16,8 +16,7 @@
package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.Sensor;
import android.bluetooth.BluetoothAdapter;
@@ -86,7 +85,7 @@ public class BluetoothConnectionManager {
*/
private synchronized void setState(Sensor.SensorState state) {
// TODO pretty print this.
Log.d(TAG, "setState(" + state + ")");
Log.d(Constants.TAG, "setState(" + state + ")");
this.state = state;
// Give the new state to the Handler so the UI Activity can update
@@ -105,7 +104,7 @@ public class BluetoothConnectionManager {
* in listening (server) mode. Called by the Activity onResume()
*/
public synchronized void start() {
Log.d(TAG, "BluetoothConnectionManager.start()");
Log.d(Constants.TAG, "BluetoothConnectionManager.start()");
// Cancel any thread attempting to make a connection
if (connectThread != null) {
@@ -128,7 +127,7 @@ public class BluetoothConnectionManager {
* @param device The BluetoothDevice to connect
*/
public synchronized void connect(BluetoothDevice device) {
Log.d(TAG, "connect to: " + device);
Log.d(Constants.TAG, "connect to: " + device);
// Cancel any thread attempting to make a connection
if (state == Sensor.SensorState.CONNECTING) {
@@ -158,7 +157,7 @@ public class BluetoothConnectionManager {
*/
public synchronized void connected(BluetoothSocket socket,
BluetoothDevice device) {
Log.d(TAG, "connected");
Log.d(Constants.TAG, "connected");
// Cancel the thread that completed the connection
if (connectThread != null) {
@@ -190,7 +189,7 @@ public class BluetoothConnectionManager {
* Stop all threads
*/
public synchronized void stop() {
Log.d(TAG, "stop()");
Log.d(Constants.TAG, "stop()");
if (connectThread != null) {
connectThread.cancel();
connectThread = null;
@@ -227,7 +226,7 @@ public class BluetoothConnectionManager {
*/
private void connectionFailed() {
setState(Sensor.SensorState.DISCONNECTED);
Log.i(TAG, "Bluetooth connection failed.");
Log.i(Constants.TAG, "Bluetooth connection failed.");
}
/**
@@ -235,7 +234,7 @@ public class BluetoothConnectionManager {
*/
private void connectionLost() {
setState(Sensor.SensorState.DISCONNECTED);
Log.i(TAG, "Bluetooth connection lost.");
Log.i(Constants.TAG, "Bluetooth connection lost.");
}
/**
@@ -256,7 +255,7 @@ public class BluetoothConnectionManager {
try {
tmp = getSocket();
} catch (IOException e) {
Log.e(TAG, "create() failed", e);
Log.e(Constants.TAG, "create() failed", e);
}
socket = tmp;
}
@@ -269,22 +268,22 @@ public class BluetoothConnectionManager {
insecure.setAccessible(true);
return (BluetoothSocket) insecure.invoke(device, 1);
} catch (SecurityException e) {
Log.e(TAG, "Unable to get insecure connect.", e);
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
} catch (NoSuchMethodException e) {
Log.e(TAG, "Unable to get insecure connect.", e);
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Unable to get insecure connect.", e);
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
} catch (IllegalAccessException e) {
Log.e(TAG, "Unable to get insecure connect.", e);
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
} catch (InvocationTargetException e) {
Log.e(TAG, "Unable to get insecure connect.", e);
Log.e(Constants.TAG, "Unable to get insecure connect.", e);
}
return device.createRfcommSocketToServiceRecord(SPP_UUID);
}
@Override
public void run() {
Log.d(TAG, "BEGIN mConnectThread");
Log.d(Constants.TAG, "BEGIN mConnectThread");
// Always cancel discovery because it will slow down a connection
adapter.cancelDiscovery();
@@ -300,7 +299,8 @@ public class BluetoothConnectionManager {
try {
socket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() socket during connection failure", e2);
Log.e(Constants.TAG,
"unable to close() socket during connection failure", e2);
}
// Start the service over to restart listening mode
BluetoothConnectionManager.this.start();
@@ -320,7 +320,7 @@ public class BluetoothConnectionManager {
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
Log.e(Constants.TAG, "close() of connect socket failed", e);
}
}
}
@@ -335,7 +335,7 @@ public class BluetoothConnectionManager {
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "create ConnectedThread");
Log.d(Constants.TAG, "create ConnectedThread");
btSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
@@ -345,7 +345,7 @@ public class BluetoothConnectionManager {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
Log.e(Constants.TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
@@ -354,7 +354,7 @@ public class BluetoothConnectionManager {
@Override
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
Log.i(Constants.TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[parser.getFrameSize()];
int bytes;
int offset = 0;
@@ -383,10 +383,11 @@ public class BluetoothConnectionManager {
// re-align
offset = parser.getFrameSize() - index;
System.arraycopy(buffer, index, buffer, 0, offset);
Log.w(TAG, "Misaligned data, found new message at " + index + " recovering...");
Log.w(Constants.TAG, "Misaligned data, found new message at " +
index + " recovering...");
continue;
}
Log.w(TAG, "Could not find valid data, dropping data");
Log.w(Constants.TAG, "Could not find valid data, dropping data");
offset = 0;
continue;
}
@@ -397,7 +398,7 @@ public class BluetoothConnectionManager {
handler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
Log.e(Constants.TAG, "disconnected", e);
connectionLost();
break;
}
@@ -416,7 +417,7 @@ public class BluetoothConnectionManager {
// Share the sent message back to the UI Activity
handler.obtainMessage(MESSAGE_WRITE, -1, -1, buffer).sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
Log.e(Constants.TAG, "Exception during write", e);
}
}
@@ -424,7 +425,7 @@ public class BluetoothConnectionManager {
try {
btSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
Log.e(Constants.TAG, "close() of connect socket failed", e);
}
}
}
@@ -15,9 +15,7 @@
*/
package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.maps.mytracks.R;
@@ -51,7 +49,7 @@ public class BluetoothSensorManager extends SensorManager {
private Sensor.SensorDataSet sensorDataSet = null;
private MessageParser parser;
public BluetoothSensorManager(
Context context, MessageParser parser) {
this.context = context;
@@ -67,7 +65,7 @@ public class BluetoothSensorManager extends SensorManager {
}
private void setupSensor() {
Log.d(TAG, "setupSensor()");
Log.d(Constants.TAG, "setupSensor()");
// Initialize the BluetoothSensorAdapter to perform bluetooth connections.
connectionManager = new BluetoothConnectionManager(messageHandler, parser);
@@ -79,17 +77,17 @@ public class BluetoothSensorManager extends SensorManager {
public void setupChannel() {
if (!isEnabled() || connectionManager == null) {
Log.w(TAG, "Disabled manager onStartTrack");
Log.w(Constants.TAG, "Disabled manager onStartTrack");
return;
}
SharedPreferences prefs =
context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
String address =
prefs.getString(context.getString(R.string.bluetooth_sensor_key), null);
if (address == null) {
return;
}
Log.w(TAG, "Connecting to bluetooth sensor: " + address);
Log.w(Constants.TAG, "Connecting to bluetooth sensor: " + address);
// Get the BluetoothDevice object
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
// Attempt to connect to the device
@@ -103,7 +101,7 @@ public class BluetoothSensorManager extends SensorManager {
// already
if (connectionManager.getState() == Sensor.SensorState.NONE) {
// Start the Bluetooth sensor services
Log.w(TAG, "Disabled manager onStartTrack");
Log.w(Constants.TAG, "Disabled manager onStartTrack");
connectionManager.start();
}
}
@@ -133,7 +131,7 @@ public class BluetoothSensorManager extends SensorManager {
switch (msg.what) {
case BluetoothConnectionManager.MESSAGE_STATE_CHANGE:
// TODO should we update the SensorManager state var?
Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
Log.i(Constants.TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
break;
case BluetoothConnectionManager.MESSAGE_WRITE:
break;
@@ -142,14 +140,15 @@ public class BluetoothSensorManager extends SensorManager {
try {
readBuf = (byte[]) msg.obj;
sensorDataSet = parser.parseBuffer(readBuf);
Log.d(TAG, "MESSAGE_READ: " + sensorDataSet.toString());
Log.d(Constants.TAG, "MESSAGE_READ: " + sensorDataSet.toString());
} catch (IllegalArgumentException iae) {
sensorDataSet = null;
Log.i(TAG, "Got bad sensor data: " + new String(readBuf, 0, readBuf.length),
Log.i(Constants.TAG,
"Got bad sensor data: " + new String(readBuf, 0, readBuf.length),
iae);
} catch (RuntimeException re) {
sensorDataSet = null;
Log.i(TAG, "Unexpected exception on read.", re);
Log.i(Constants.TAG, "Unexpected exception on read.", re);
}
break;
case BluetoothConnectionManager.MESSAGE_DEVICE_NAME:
@@ -15,14 +15,13 @@
*/
package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import com.google.android.apps.mytracks.content.Sensor;
import java.util.Timer;
import java.util.TimerTask;
import android.util.Log;
import java.util.Timer;
import java.util.TimerTask;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.Sensor;
/**
* Manage the connection to a sensor.
@@ -51,17 +50,19 @@ public abstract class SensorManager {
private TimerTask checkSensorManager = new TimerTask() {
@Override
public void run() {
Log.i(TAG, "SensorManager state: " + getSensorState());
Log.i(Constants.TAG,
"SensorManager state: " + getSensorState());
switch (getSensorState()) {
case CONNECTING:
long age = System.currentTimeMillis() - getSensorStateTimestamp();
if (age > 2 * RETRY_PERIOD) {
Log.i(TAG, "Retrying connecting SensorManager.");
Log.i(Constants.TAG, "Retrying connecting SensorManager.");
setupChannel();
}
break;
case DISCONNECTED:
Log.i(TAG, "Re-registering disconnected SensorManager.");
Log.i(Constants.TAG,
"Re-registering disconnected SensoManager.");
setupChannel();
break;
}
@@ -1,12 +1,12 @@
/*
* Copyright 2009 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
@@ -15,9 +15,7 @@
*/
package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.Constants;
import com.google.android.maps.mytracks.R;
import android.content.Context;
@@ -30,7 +28,9 @@ import android.util.Log;
* @author Sandor Dornbush
*/
public class SensorManagerFactory {
private SensorManagerFactory() {}
private SensorManagerFactory() {
}
/**
* Get a new sensor manager.
@@ -39,13 +39,13 @@ public class SensorManagerFactory {
*/
public static SensorManager getSensorManager(Context context) {
SharedPreferences prefs =
context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
if (prefs == null) {
return null;
}
String sensor = prefs.getString(context.getString(R.string.sensor_type_key), null);
Log.i(TAG, "Creating sensor of type: " + sensor);
Log.i(Constants.TAG, "Creating sensor of type: " + sensor);
if (sensor == null) {
return null;
@@ -56,7 +56,7 @@ public class SensorManagerFactory {
} else if (sensor.equals(context.getString(R.string.zephyr_sensor_type))) {
return new ZephyrSensorManager(context);
} else {
Log.w(TAG, "Unable to find sensor type: " + sensor);
Log.w(Constants.TAG, "Unable to find sensor type: " + sensor);
return null;
}
}
@@ -15,12 +15,11 @@
*/
package com.google.android.apps.mytracks.services.sensors;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import com.google.android.apps.mytracks.content.Sensor;
import android.util.Log;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.Sensor;
/**
* An implementation of a SensorData parser for Zephyr HRM.
*
@@ -34,7 +33,7 @@ public class ZephyrMessageParser implements MessageParser {
for (int i = 0; i < buffer.length; i++) {
sb.append(String.format("%02X", buffer[i]));
}
Log.w(TAG, "Got zephyr data: " + sb);
Log.w(Constants.TAG, "Got zephyr data: " + sb);
// The provided units are 1/16 strides per minute.
// TODO: Fix the cadence calculation.
// int cadence = SensorUtils.unsignedShortToInt(buffer, 56);
@@ -50,7 +49,7 @@ public class ZephyrMessageParser implements MessageParser {
.setCreationTime(System.currentTimeMillis())
.setHeartRate(b)
.build();
return sds;
}
@@ -16,8 +16,10 @@
package com.google.android.apps.mytracks.stats;
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.SettingsActivity;
import android.location.Location;
import android.util.Log;
@@ -65,25 +67,25 @@ public class TripStatisticsBuilder {
* A buffer of the last speed readings in meters/second.
*/
private final DoubleBuffer speedBuffer =
new DoubleBuffer(MyTracksConstants.SPEED_SMOOTHING_FACTOR);
new DoubleBuffer(Constants.SPEED_SMOOTHING_FACTOR);
/**
* A buffer of the recent elevation readings in meters.
*/
private final DoubleBuffer elevationBuffer =
new DoubleBuffer(MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
new DoubleBuffer(Constants.ELEVATION_SMOOTHING_FACTOR);
/**
* A buffer of the distance between recent gps readings in meters.
*/
private final DoubleBuffer distanceBuffer =
new DoubleBuffer(MyTracksConstants.DISTANCE_SMOOTHING_FACTOR);
new DoubleBuffer(Constants.DISTANCE_SMOOTHING_FACTOR);
/**
* A buffer of the recent grade calculations.
*/
private final DoubleBuffer gradeBuffer =
new DoubleBuffer(MyTracksConstants.GRADE_SMOOTHING_FACTOR);
new DoubleBuffer(Constants.GRADE_SMOOTHING_FACTOR);
/**
* The total number of locations in this trip.
@@ -91,7 +93,7 @@ public class TripStatisticsBuilder {
private long totalLocations = 0;
private int minRecordingDistance =
MyTracksSettings.DEFAULT_MIN_RECORDING_DISTANCE;
Constants.DEFAULT_MIN_RECORDING_DISTANCE;
/**
* Creates a new trip starting at the given time.
@@ -126,7 +128,7 @@ public class TripStatisticsBuilder {
*/
public boolean addLocation(Location currentLocation, long systemTime) {
if (paused) {
Log.w(MyTracksConstants.TAG,
Log.w(TAG,
"Tried to account for location while track is paused");
return false;
}
@@ -151,7 +153,7 @@ public class TripStatisticsBuilder {
// Don't do anything if we didn't move since last fix:
double distance = lastLocation.distanceTo(currentLocation);
if (distance < minRecordingDistance &&
currentSpeed < MyTracksConstants.MAX_NO_MOVEMENT_SPEED) {
currentSpeed < Constants.MAX_NO_MOVEMENT_SPEED) {
lastLocation = currentLocation;
return false;
}
@@ -208,7 +210,7 @@ public class TripStatisticsBuilder {
// We are now sure the user is moving.
long timeDifference = updateTime - lastLocationTime;
if (timeDifference < 0) {
Log.e(MyTracksConstants.TAG,
Log.e(TAG,
"Found negative time change: " + timeDifference);
}
data.addMovingTime(timeDifference);
@@ -224,7 +226,7 @@ public class TripStatisticsBuilder {
data.setMaxSpeed(movingSpeed);
}
} else {
Log.d(MyTracksConstants.TAG,
Log.d(TAG,
"TripStatistics ignoring big change: Raw Speed: " + speed
+ " old: " + lastLocationSpeed + " [" + toString() + "]");
}
@@ -263,7 +265,7 @@ public class TripStatisticsBuilder {
// likely. Ignore any speeds that imply accelaration greater than 2g's
// Really who can accelerate faster?
double speedDifference = Math.abs(lastLocationSpeed - speed);
if (speedDifference > MyTracksConstants.MAX_ACCELERATION * timeDifference) {
if (speedDifference > Constants.MAX_ACCELERATION * timeDifference) {
return false;
}
@@ -275,7 +277,7 @@ public class TripStatisticsBuilder {
double smoothedDiff = Math.abs(smoothedSpeed - speed);
return !speedBuffer.isFull() ||
(speed < smoothedSpeed * 10
&& smoothedDiff < MyTracksConstants.MAX_ACCELERATION * timeDifference);
&& smoothedDiff < Constants.MAX_ACCELERATION * timeDifference);
}
/**
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.Constants;
import android.os.Build;
import android.util.Log;
@@ -72,7 +72,7 @@ public class ApiFeatures {
apiPlatformAdapter = new CupcakePlatformAdapter();
}
Log.i(MyTracksConstants.TAG, "Using platform adapter " + apiPlatformAdapter.getClass());
Log.i(Constants.TAG, "Using platform adapter " + apiPlatformAdapter.getClass());
}
public ApiPlatformAdapter getApiPlatformAdapter() {
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.Constants;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
@@ -158,14 +158,14 @@ public abstract class BluetoothDeviceUtils {
public static BluetoothDeviceUtils getInstance() {
if (instance == null) {
if (!isBluetoothMethodSupported()) {
Log.d(MyTracksConstants.TAG, "Using dummy bluetooth utils");
Log.d(Constants.TAG, "Using dummy bluetooth utils");
instance = new DummyImpl();
} else {
Log.d(MyTracksConstants.TAG, "Using real bluetooth utils");
Log.d(Constants.TAG, "Using real bluetooth utils");
try {
instance = new RealImpl();
} catch (IllegalStateException ise) {
Log.w(MyTracksConstants.TAG, "Oops, I mean, using dummy bluetooth utils", ise);
Log.w(Constants.TAG, "Oops, I mean, using dummy bluetooth utils", ise);
instance = new DummyImpl();
}
}
@@ -16,7 +16,7 @@
package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.maps.mytracks.R;
@@ -50,7 +50,7 @@ public class ChartURLGenerator {
public static String getChartUrl(Vector<Double> distances,
Vector<Double> elevations, Track track, Context context) {
SharedPreferences preferences =
context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
boolean metricUnits = true;
if (preferences != null) {
metricUnits = preferences.getBoolean(
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.util;
import static com.google.android.apps.mytracks.MyTracksConstants.TAG;
import static com.google.android.apps.mytracks.Constants.TAG;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.Constants;
import android.os.Environment;
@@ -49,7 +49,7 @@ public class FileUtils {
StringBuilder dirNameBuilder = new StringBuilder();
dirNameBuilder.append(Environment.getExternalStorageDirectory());
dirNameBuilder.append(File.separatorChar);
dirNameBuilder.append(MyTracksConstants.SDCARD_TOP_DIR);
dirNameBuilder.append(Constants.SDCARD_TOP_DIR);
for (String component : components) {
dirNameBuilder.append(File.separatorChar);
dirNameBuilder.append(component);
@@ -1,6 +1,6 @@
package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.Constants;
import android.content.SharedPreferences.Editor;
import android.os.StrictMode;
@@ -21,7 +21,7 @@ public class GingerbreadPlatformAdapter extends EclairPlatformAdapter {
@Override
public void enableStrictMode() {
Log.d(MyTracksConstants.TAG, "Enabling strict mode");
Log.d(Constants.TAG, "Enabling strict mode");
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskWrites()
.detectNetwork()
@@ -1,12 +1,12 @@
/*
* 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
@@ -15,20 +15,13 @@
*/
package com.google.android.apps.mytracks.util;
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.stats.TripStatistics;
import com.google.android.maps.GeoPoint;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.location.Location;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import java.util.ArrayList;
@@ -37,16 +30,14 @@ import java.util.Stack;
/**
* Utility class for decimating tracks at a given level of precision.
*
*
* @author Leif Hendrik Wilden
*/
public class MyTracksUtils {
private static final int RELEASE_SIGNATURE_HASHCODE = -1855564782;
public class LocationUtils {
/**
* Computes the distance on the two sphere between the point c0 and the line
* segment c1 to c2.
*
*
* @param c0 the first coordinate
* @param c1 the beginning of the line segment
* @param c2 the end of the lone segment
@@ -88,7 +79,7 @@ public class MyTracksUtils {
/**
* Decimates the given locations for a given zoom level. This uses a
* Douglas-Peucker decimation algorithm.
*
*
* @param tolerance in meters
* @param locations input
* @param decimated output
@@ -116,7 +107,7 @@ public class MyTracksUtils {
current = stack.pop();
maxDist = 0;
for (idx = current[0] + 1; idx < current[1]; ++idx) {
dist = MyTracksUtils.distance(
dist = LocationUtils.distance(
locations.get(idx),
locations.get(current[0]),
locations.get(current[1]));
@@ -145,13 +136,13 @@ public class MyTracksUtils {
}
idx++;
}
Log.d(MyTracksConstants.TAG, "Decimating " + n + " points to " + i
Log.d(Constants.TAG, "Decimating " + n + " points to " + i
+ " w/ tolerance = " + tolerance);
}
/**
* Decimates the given track for the given precision.
*
*
* @param track a track
* @param precision desired precision in meters
*/
@@ -164,7 +155,7 @@ public class MyTracksUtils {
/**
* Limits number of points by dropping any points beyond the given number of
* points. Note: That'll actually discard points.
*
*
* @param track a track
* @param numberOfPoints maximum number of points
*/
@@ -178,7 +169,7 @@ public class MyTracksUtils {
/**
* Splits a track in multiple tracks where each piece has less or equal than
* maxPoints.
*
*
* @param track the track to split
* @param maxPoints maximum number of points for each piece
* @return a list of one or more track pieces
@@ -213,7 +204,7 @@ public class MyTracksUtils {
/**
* Test if a given GeoPoint is valid, i.e. within physical bounds.
*
*
* @param geoPoint the point to be tested
* @return true, if it is a physical location on earth.
*/
@@ -227,7 +218,7 @@ public class MyTracksUtils {
* on Earth. Note: The special separator locations (which have latitude =
* 100) will not qualify as valid. Neither will locations with lat=0 and lng=0
* as these are most likely "bad" measurements which often cause trouble.
*
*
* @param location the location to test
* @return true if the location is a valid location.
*/
@@ -238,7 +229,7 @@ public class MyTracksUtils {
/**
* Gets a location from a GeoPoint.
*
*
* @param p a GeoPoint
* @return the corresponding location
*/
@@ -254,97 +245,9 @@ public class MyTracksUtils {
(int) (location.getLongitude() * 1E6));
}
/**
* Returns whether or not this is a release build.
*/
public static boolean isRelease(Context context) {
PackageInfo packageInfo = getPackageInfo(context, PackageManager.GET_SIGNATURES);
if (packageInfo == null) {
return false;
}
for (Signature sig : packageInfo.signatures) {
if (sig.hashCode() == RELEASE_SIGNATURE_HASHCODE) {
return true;
}
}
return false;
}
/**
* Get the My Tracks version from the manifest.
*
* @return the version, or an empty string in case of failure.
*/
public static String getMyTracksVersion(Context context) {
PackageInfo packageInfo = getPackageInfo(context, PackageManager.GET_META_DATA);
return packageInfo == null ? "" : packageInfo.versionName;
}
/**
* Return the My Tracks version code from the manifest.
*
* @return the version code, or an empty string in case of failure.
*/
public static int getMyTracksVersionCode(Context context) {
PackageInfo packageInfo = getPackageInfo(context, PackageManager.GET_META_DATA);
return packageInfo == null ? -1 : packageInfo.versionCode;
}
private static PackageInfo getPackageInfo(Context context, int flags) {
if (context == null) {
Log.w(MyTracksConstants.TAG, "No context found when attempting to get PackageInfo");
return null;
}
try {
return context.getPackageManager().getPackageInfo(
"com.google.android.maps.mytracks", flags);
} catch (NameNotFoundException e) {
Log.w(MyTracksConstants.TAG, "Failed to get version info.", e);
return null;
}
}
/**
* Tries to acquire a partial wake lock if not already acquired. Logs errors
* and gives up trying in case the wake lock cannot be acquired.
*/
public static WakeLock acquireWakeLock(Activity activity, WakeLock wakeLock) {
Log.i(MyTracksConstants.TAG, "MyTracksUtils: Acquiring wake lock.");
try {
PowerManager pm = (PowerManager) activity
.getSystemService(Context.POWER_SERVICE);
if (pm == null) {
Log.e(MyTracksConstants.TAG, "MyTracksUtils: Power manager not found!");
return wakeLock;
}
if (wakeLock == null) {
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
MyTracksConstants.TAG);
if (wakeLock == null) {
Log.e(MyTracksConstants.TAG,
"MyTracksUtils: Could not create wake lock (null).");
}
return wakeLock;
}
if (!wakeLock.isHeld()) {
wakeLock.acquire();
if (!wakeLock.isHeld()) {
Log.e(MyTracksConstants.TAG,
"MyTracksUtils: Could not acquire wake lock.");
}
}
} catch (RuntimeException e) {
Log.e(MyTracksConstants.TAG,
"MyTracksUtils: Caught unexpected exception: " + e.getMessage(), e);
}
return wakeLock;
}
/**
* This is a utility class w/ only static members.
*/
protected MyTracksUtils() {
private LocationUtils() {
}
}
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.DescriptionGenerator;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
@@ -245,7 +245,7 @@ public class StringUtils implements DescriptionGenerator {
Vector<Double> elevations) {
boolean displaySpeed = true;
SharedPreferences preferences =
context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
context.getSharedPreferences(Constants.SETTINGS_NAME, 0);
if (preferences != null) {
displaySpeed =
preferences.getBoolean(context.getString(R.string.report_speed_key), true);
@@ -0,0 +1,111 @@
/*
* 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.util;
import com.google.android.apps.mytracks.Constants;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
/**
* Utility class for acessing basic Android functionality.
*
* @author Rodrigo Damazio
*/
public class SystemUtils {
private static final int RELEASE_SIGNATURE_HASHCODE = -1855564782;
/**
* Returns whether or not this is a release build.
*/
public static boolean isRelease(Context context) {
try {
Signature [] sigs = context.getPackageManager().getPackageInfo(
context.getPackageName(), PackageManager.GET_SIGNATURES).signatures;
for (Signature sig : sigs) {
if (sig.hashCode() == RELEASE_SIGNATURE_HASHCODE) {
return true;
}
}
} catch (NameNotFoundException e) {
Log.e(Constants.TAG, "Unable to get signatures", e);
}
return false;
}
/**
* Get the My Tracks version from the manifest.
*
* @return the version, or an empty string in case of failure.
*/
public static String getMyTracksVersion(Context context) {
try {
PackageInfo pi = context.getPackageManager().getPackageInfo(
"com.google.android.maps.mytracks",
PackageManager.GET_META_DATA);
return pi.versionName;
} catch (NameNotFoundException e) {
Log.w(Constants.TAG, "Failed to get version info.", e);
return "";
}
}
/**
* Tries to acquire a partial wake lock if not already acquired. Logs errors
* and gives up trying in case the wake lock cannot be acquired.
*/
public static WakeLock acquireWakeLock(Activity activity, WakeLock wakeLock) {
Log.i(Constants.TAG, "LocationUtils: Acquiring wake lock.");
try {
PowerManager pm = (PowerManager) activity
.getSystemService(Context.POWER_SERVICE);
if (pm == null) {
Log.e(Constants.TAG, "LocationUtils: Power manager not found!");
return wakeLock;
}
if (wakeLock == null) {
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
Constants.TAG);
if (wakeLock == null) {
Log.e(Constants.TAG,
"LocationUtils: Could not create wake lock (null).");
}
return wakeLock;
}
if (!wakeLock.isHeld()) {
wakeLock.acquire();
if (!wakeLock.isHeld()) {
Log.e(Constants.TAG,
"LocationUtils: Could not acquire wake lock.");
}
}
} catch (RuntimeException e) {
Log.e(Constants.TAG,
"LocationUtils: Caught unexpected exception: " + e.getMessage(), e);
}
return wakeLock;
}
private SystemUtils() {}
}
@@ -36,8 +36,8 @@ public class MyTracksLocation extends Location {
this.sensorDataSet = sd;
}
public MyTracksLocation(String string) {
super(string);
public MyTracksLocation(String provider) {
super(provider);
}
public Sensor.SensorDataSet getSensorDataSet() {
@@ -301,7 +301,7 @@ public interface MyTracksProviderUtils {
* @return a new waypoint object
*/
Waypoint createWaypoint(Cursor cursor);
/**
* A lightweight wrapper around the original {@link Cursor} with a method to clean up.
*/
@@ -312,13 +312,14 @@ public interface MyTracksProviderUtils {
* @return the ID of the most recent track point ID.
*/
long getLocationId();
/**
* Should be called in case the underlying iterator hasn't reached the last record.
* Calling it if it has reached the last record is a no-op.
*/
void close();
}
/**
* A factory for creating new {@class Location}s.
*/
@@ -342,6 +343,24 @@ public interface MyTracksProviderUtils {
return new Location("gps");
}
};
/**
* A location factory which uses two location instances (one for the current location,
* and one for the previous), useful when we need to keep the last location.
*/
public class DoubleBufferedLocationFactory implements LocationFactory {
private final Location locs[] = new MyTracksLocation[] {
new MyTracksLocation("gps"),
new MyTracksLocation("gps")
};
private int lastLoc = 0;
@Override
public Location createLocation() {
lastLoc = (lastLoc + 1) % locs.length;
return locs[lastLoc];
}
}
/**
* Creates a new read-only iterator over all track points for the given track. It provides
@@ -1024,7 +1024,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
cursor = null;
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
@@ -39,17 +39,17 @@ import java.util.List;
*
* @author Bartlomiej Niechwiej
*/
public class MyTracksOverlayTest extends AndroidTestCase {
public class MapOverlayTest extends AndroidTestCase {
private Canvas canvas;
private MockMyTracksOverlay myTracksOverlay;
private MapView mockView;
private Projection mockProjection;
/**
* A mock version of {@code MyTracksOverlay} that does not use
* A mock version of {@code MapOverlay} that does not use
* {@class MapView}.
*/
private class MockMyTracksOverlay extends MyTracksOverlay {
private class MockMyTracksOverlay extends MapOverlay {
public MockMyTracksOverlay(Context context) {
super(context);
}
@@ -165,7 +165,7 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2<MyTracks>{
// Watch for MyTracksDetails activity.
ActivityMonitor monitor = getInstrumentation().addMonitor(
MyTracksDetails.class.getName(), null, false);
TrackDetails.class.getName(), null, false);
// Now, stop the track and make sure that it is still selected, but
// no longer recording.
@@ -173,7 +173,7 @@ public class MyTracksTest extends ActivityInstrumentationTestCase2<MyTracks>{
// Check if we got back MyTracksDetails activity.
Activity activity = getInstrumentation().waitForMonitor(monitor);
assertTrue(activity instanceof MyTracksDetails);
assertTrue(activity instanceof TrackDetails);
// TODO: Update track name and other properties and test if they were
// properly saved.
@@ -29,7 +29,7 @@ public class TcxTrackWriterTest extends TrackFormatWriterTest {
}
public void testXmlOutput() throws Exception {
TrackFormatWriter writer = new TcxTrackWriter(null);
TrackFormatWriter writer = new TcxTrackWriter(getContext());
String result = writeTrack(writer);
Document doc = parseXmlDocument(result);
@@ -82,7 +82,6 @@ public class PreferenceBackupHelperTest extends TestCase {
return put(key, value);
}
@Override
public Editor putStringSet(String key, Set<String> value) {
return put(key, value);
}
@@ -143,7 +142,6 @@ public class PreferenceBackupHelperTest extends TestCase {
return get(key, defValue);
}
@Override
public Set<String> getStringSet(String key, Set<String> defValue) {
return get(key, defValue);
}
@@ -15,9 +15,9 @@
*/
package com.google.android.apps.mytracks.services;
import static com.google.android.apps.mytracks.MyTracksConstants.RESUME_TRACK_EXTRA_NAME;
import static com.google.android.apps.mytracks.Constants.RESUME_TRACK_EXTRA_NAME;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.MyTracksProvider;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
@@ -152,7 +152,7 @@ public class TrackRecordingServiceTest
providerUtils = MyTracksProviderUtils.Factory.get(context);
sharedPreferences = context.getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, 0);
Constants.SETTINGS_NAME, 0);
// Let's use default values.
sharedPreferences.edit().clear().commit();
@@ -16,7 +16,7 @@
package com.google.android.apps.mytracks.services.sensors;
import com.dsi.ant.AntMesg;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.maps.mytracks.R;
@@ -31,7 +31,7 @@ public class AntDirectSensorManagerTest extends AndroidTestCase {
public void setUp() {
sharedPreferences = getContext().getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, 0);
Constants.SETTINGS_NAME, 0);
// Let's use default values.
sharedPreferences.edit().clear().commit();
manager = new AntDirectSensorManager(getContext());
@@ -1,6 +1,6 @@
package com.google.android.apps.mytracks.services.sensors;
import com.google.android.apps.mytracks.MyTracksSettings;
import com.google.android.apps.mytracks.Constants;
import com.google.android.maps.mytracks.R;
import android.content.SharedPreferences;
@@ -16,7 +16,7 @@ public class SensorManagerFactoryTest extends AndroidTestCase {
super.setUp();
sharedPreferences = getContext().getSharedPreferences(
MyTracksSettings.SETTINGS_NAME, 0);
Constants.SETTINGS_NAME, 0);
// Let's use default values.
sharedPreferences.edit().clear().commit();
}
@@ -2,7 +2,7 @@
package com.google.android.apps.mytracks.stats;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.Constants;
import android.location.Location;
@@ -56,18 +56,18 @@ public class TripStatisticsBuilderTest extends TestCase {
assertEquals(10000 * i, stats.getTotalTime());
assertEquals(10000 * i, stats.getMovingTime());
assertEquals(i, builder.getSmoothedElevation(),
MyTracksConstants.ELEVATION_SMOOTHING_FACTOR / 2);
Constants.ELEVATION_SMOOTHING_FACTOR / 2);
assertEquals(0.0, stats.getMinElevation());
assertEquals(i, stats.getMaxElevation(),
MyTracksConstants.ELEVATION_SMOOTHING_FACTOR / 2);
Constants.ELEVATION_SMOOTHING_FACTOR / 2);
assertEquals(i, stats.getTotalElevationGain(),
MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
Constants.ELEVATION_SMOOTHING_FACTOR);
if (i > MyTracksConstants.SPEED_SMOOTHING_FACTOR) {
if (i > Constants.SPEED_SMOOTHING_FACTOR) {
assertEquals(11.1f, stats.getMaxSpeed(), 0.1);
}
if ((i > MyTracksConstants.GRADE_SMOOTHING_FACTOR)
&& (i > MyTracksConstants.ELEVATION_SMOOTHING_FACTOR)) {
if ((i > Constants.GRADE_SMOOTHING_FACTOR)
&& (i > Constants.ELEVATION_SMOOTHING_FACTOR)) {
assertEquals(0.009, stats.getMinGrade(), 0.0001);
assertEquals(0.009, stats.getMaxGrade(), 0.0001);
}
@@ -97,9 +97,9 @@ public class TripStatisticsBuilderTest extends TestCase {
public void testElevationGain() throws Exception {
for (double i = 0; i < 1000; i++) {
double expectedGain;
if (i < (MyTracksConstants.ELEVATION_SMOOTHING_FACTOR - 1)) {
if (i < (Constants.ELEVATION_SMOOTHING_FACTOR - 1)) {
expectedGain = 0;
} else if (i < MyTracksConstants.ELEVATION_SMOOTHING_FACTOR) {
} else if (i < Constants.ELEVATION_SMOOTHING_FACTOR) {
expectedGain = 0.5;
} else {
expectedGain = 1.0;
@@ -110,9 +110,9 @@ public class TripStatisticsBuilderTest extends TestCase {
TripStatistics data = builder.getStatistics();
assertEquals(0.0, data.getMinElevation(), 0.0);
assertEquals(i, data.getMaxElevation(),
MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
Constants.ELEVATION_SMOOTHING_FACTOR);
assertEquals(i, data.getTotalElevationGain(),
MyTracksConstants.ELEVATION_SMOOTHING_FACTOR);
Constants.ELEVATION_SMOOTHING_FACTOR);
}
}
@@ -122,8 +122,8 @@ public class TripStatisticsBuilderTest extends TestCase {
// buffer.
builder.updateElevation(i);
builder.updateGrade(100, 100);
if ((i > MyTracksConstants.GRADE_SMOOTHING_FACTOR)
&& (i > MyTracksConstants.ELEVATION_SMOOTHING_FACTOR)) {
if ((i > Constants.GRADE_SMOOTHING_FACTOR)
&& (i > Constants.ELEVATION_SMOOTHING_FACTOR)) {
assertEquals(1.0, builder.getStatistics().getMaxGrade());
assertEquals(1.0, builder.getStatistics().getMinGrade());
}
@@ -133,8 +133,8 @@ public class TripStatisticsBuilderTest extends TestCase {
// buffer.
builder.updateElevation(i);
builder.updateGrade(100, -100);
if ((i > MyTracksConstants.GRADE_SMOOTHING_FACTOR)
&& (i > MyTracksConstants.ELEVATION_SMOOTHING_FACTOR)) {
if ((i > Constants.GRADE_SMOOTHING_FACTOR)
&& (i > Constants.ELEVATION_SMOOTHING_FACTOR)) {
assertEquals(1.0, builder.getStatistics().getMaxGrade());
assertEquals(-1.0, builder.getStatistics().getMinGrade());
}
@@ -176,7 +176,7 @@ public class TripStatisticsBuilderTest extends TestCase {
for (int i = 0; i < 1000; i++) {
builder.updateSpeed(i + 1000, 4.0, i, 4.0);
assertEquals((i + 1) * 1000, builder.getStatistics().getMovingTime());
if (i > MyTracksConstants.SPEED_SMOOTHING_FACTOR) {
if (i > Constants.SPEED_SMOOTHING_FACTOR) {
assertEquals(4.0, builder.getStatistics().getMaxSpeed());
}
}
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.Constants;
import android.os.Environment;
@@ -53,7 +53,7 @@ public class FileUtilsTest extends TestCase {
public void testBuildExternalDirectoryPath() {
String expectedName = Environment.getExternalStorageDirectory()
+ File.separator
+ MyTracksConstants.SDCARD_TOP_DIR
+ Constants.SDCARD_TOP_DIR
+ File.separator
+ "a"
+ File.separator