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