Merge heads

This commit is contained in:
youtaol
2012-05-09 11:01:22 +08:00
226 changed files with 5603 additions and 5614 deletions
@@ -0,0 +1,55 @@
/*
* Copyright 2012 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.util.ApiAdapterFactory;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.support.v4.app.FragmentActivity;
import android.view.MenuItem;
/**
* An abstract class for all My Tracks activities.
*
* @author Jimmy Shih
*/
public class AbstractMyTracksActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
ApiAdapterFactory.getApiAdapter().configureActionBarHomeAsUp(this);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() != android.R.id.home) {
return super.onOptionsItemSelected(item);
}
onHomeSelected();
return true;
}
/**
* Callback when the home menu item is selected.
*/
protected void onHomeSelected() {
finish();
}
}
@@ -1,128 +1,59 @@
/*
* Copyright 2012 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.stats.TripStatistics;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.StatsUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MenuItem;
import android.widget.ScrollView;
import android.widget.TextView;
import java.util.List;
/**
* Activity for viewing the combined statistics for all the recorded tracks.
*
* Other features to add - menu items to change setings.
* An activity to view aggregated stats from all recorded tracks.
*
* @author Fergus Nelson
*/
public class AggregatedStatsActivity extends Activity implements
OnSharedPreferenceChangeListener {
private final StatsUtilities utils;
private MyTracksProviderUtils tracksProvider;
private boolean metricUnits = true;
public AggregatedStatsActivity() {
this.utils = new StatsUtilities(this);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
Log.d(Constants.TAG, "StatsActivity: onSharedPreferences changed "
+ key);
if (key != null) {
if (key.equals(getString(R.string.metric_units_key))) {
metricUnits = sharedPreferences.getBoolean(
getString(R.string.metric_units_key), true);
utils.setMetricUnits(metricUnits);
utils.updateUnits();
loadAggregatedStats();
}
}
}
public class AggregatedStatsActivity extends AbstractMyTracksActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.tracksProvider = MyTracksProviderUtils.Factory.get(this);
ApiAdapterFactory.getApiAdapter().configureActionBarHomeAsUp(this);
setContentView(R.layout.stats);
ScrollView sv = ((ScrollView) findViewById(R.id.scrolly));
sv.setScrollBarStyle(ScrollView.SCROLLBARS_OUTSIDE_INSET);
SharedPreferences preferences = getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
if (preferences != null) {
metricUnits = preferences.getBoolean(getString(R.string.metric_units_key), true);
preferences.registerOnSharedPreferenceChangeListener(this);
}
utils.setMetricUnits(metricUnits);
utils.updateUnits();
utils.setSpeedLabel(R.id.speed_label, R.string.stat_speed, R.string.stat_pace);
utils.setSpeedLabels();
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
if (metrics.heightPixels > 600) {
((TextView) findViewById(R.id.speed_register)).setTextSize(80.0f);
}
loadAggregatedStats();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() != android.R.id.home) {
return false;
}
startActivity(new Intent(this, TrackListActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
return true;
setContentView(R.layout.aggregated_stats);
StatsUtils.setTripStatisticsValues(this, getTripStatistics());
StatsUtils.setLocationValues(this, null, false);
}
/**
* 1. Reads tracks from the db
* 2. Merges the trip stats from the tracks
* 3. Updates the view
* Gets the aggregated trip statistics for all the recorded tracks or null if
* there is no track.
*/
private void loadAggregatedStats() {
List<Track> tracks = retrieveTracks();
TripStatistics rollingStats = null;
private TripStatistics getTripStatistics() {
List<Track> tracks = MyTracksProviderUtils.Factory.get(this).getAllTracks();
TripStatistics tripStatistics = null;
if (!tracks.isEmpty()) {
rollingStats = new TripStatistics(tracks.iterator().next()
.getStatistics());
tripStatistics = new TripStatistics(tracks.iterator().next().getStatistics());
for (int i = 1; i < tracks.size(); i++) {
rollingStats.merge(tracks.get(i).getStatistics());
tripStatistics.merge(tracks.get(i).getStatistics());
}
}
updateView(rollingStats);
}
private List<Track> retrieveTracks() {
return tracksProvider.getAllTracks();
}
private void updateView(TripStatistics aggStats) {
if (aggStats != null) {
utils.setAllStats(aggStats);
}
return tripStatistics;
}
}
@@ -1,5 +1,6 @@
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.content.Context;
@@ -31,9 +32,9 @@ public class AutoCompleteTextPreference extends EditTextPreference {
mEditText.setThreshold(0);
// Gets autocomplete values for 'Default Activity' preference
if (getKey().equals(context.getString(R.string.default_activity_key))) {
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(context,
R.array.activity_types, android.R.layout.simple_dropdown_item_1line);
if (PreferencesUtils.getKey(context, R.string.default_activity_key).equals(getKey())) {
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
context, R.array.activity_types, android.R.layout.simple_dropdown_item_1line);
mEditText.setAdapter(adapter);
}
}
@@ -48,8 +48,8 @@ public class BootReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
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);
Intent startIntent = new Intent(context, TrackRecordingService.class)
.putExtra(RESUME_TRACK_EXTRA_NAME, true);
context.startService(startIntent);
Intent removeTempFilesIntent = new Intent(context, RemoveTempFilesService.class);
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.ChartValueSeries.ZoomSettings;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.stats.ExtremityMonitor;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
@@ -75,7 +76,7 @@ public class ChartView extends View {
/**
* Unscaled top border of the chart.
*/
private static final int TOP_BORDER = 15;
private static final int TOP_BORDER = 16;
/**
* Device scaled top border of the chart.
@@ -85,7 +86,7 @@ public class ChartView extends View {
/**
* Unscaled bottom border of the chart.
*/
private static final float BOTTOM_BORDER = 40;
private static final float BOTTOM_BORDER = 8;
/**
* Device scaled bottom border of the chart.
@@ -155,12 +156,7 @@ public class ChartView extends View {
private boolean metricUnits = true;
private boolean showPointer = false;
/** Display chart versus distance or time */
public enum Mode {
BY_DISTANCE, BY_TIME
}
private Mode mode = Mode.BY_DISTANCE;
private boolean chartByDistance = true;
public ChartView(Context context) {
super(context);
@@ -190,7 +186,7 @@ public class ChartView extends View {
pointer.setBounds(0, 0,
pointer.getIntrinsicWidth(), pointer.getIntrinsicHeight());
statsMarker = getResources().getDrawable(R.drawable.ylw_pushpin);
statsMarker = getResources().getDrawable(R.drawable.yellow_pushpin);
markerWidth = statsMarker.getIntrinsicWidth();
markerHeight = statsMarker.getIntrinsicHeight();
statsMarker.setBounds(0, 0, markerWidth, markerHeight);
@@ -214,7 +210,7 @@ public class ChartView extends View {
R.color.elevation_border,
new ZoomSettings(MAX_INTERVALS,
new int[] {5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000}),
R.string.stat_elevation);
R.string.stats_elevation);
series[SPEED_SERIES] =
new ChartValueSeries(context,
@@ -222,7 +218,7 @@ public class ChartView extends View {
R.color.speed_border,
new ZoomSettings(MAX_INTERVALS, 0, Integer.MIN_VALUE,
new int[] {1, 5, 10, 20, 50}),
R.string.stat_speed);
R.string.stats_speed);
series[POWER_SERIES] =
new ChartValueSeries(context,
R.color.power_fill,
@@ -269,8 +265,8 @@ public class ChartView extends View {
public void setReportSpeed(boolean reportSpeed, Context c) {
series[SPEED_SERIES].setTitle(c.getString(reportSpeed
? R.string.stat_speed
: R.string.stat_pace));
? R.string.stats_speed
: R.string.stats_pace));
}
private void addDataPointInternal(double[] theData) {
@@ -393,22 +389,17 @@ public class ChartView extends View {
}
/**
* @return the current display mode (by distance, by time)
* Sets chart by distance value. It is expected that after changing this
* value, data will be reloaded.
*
* @param value true for by distance, false for by time.
*/
public Mode getMode() {
return mode;
}
/**
* Sets the display mode (by distance, by time).
* It is expected that after the mode change, data will be reloaded.
*/
public void setMode(Mode mode) {
this.mode = mode;
public void setChartByDistance(boolean value) {
this.chartByDistance = value;
}
private int getWaypointX(Waypoint waypoint) {
if (mode == Mode.BY_DISTANCE) {
if (chartByDistance) {
double lenghtInKm = waypoint.getLength() * UnitConversions.M_TO_KM;
return getX(metricUnits ? lenghtInKm : lenghtInKm * UnitConversions.KM_TO_MI);
} else {
@@ -485,8 +476,7 @@ public class ChartView extends View {
}
}
if (nearestWaypoint != null && dmin < 100) {
Intent intent = new Intent(getContext(), MarkerDetailActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
Intent intent = IntentUtils.newIntent(getContext(), MarkerDetailActivity.class)
.putExtra(MarkerDetailActivity.EXTRA_MARKER_ID, nearestWaypoint.getId());
getContext().startActivity(intent);
return true;
@@ -509,10 +499,16 @@ public class ChartView extends View {
return true;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
updateEffectiveDimensionsIfChanged(
View.MeasureSpec.getSize(widthMeasureSpec), View.MeasureSpec.getSize(heightMeasureSpec));
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas c) {
synchronized (data) {
updateEffectiveDimensionsIfChanged(c);
// Keep original state.
c.save();
@@ -742,13 +738,16 @@ public class ChartView extends View {
/**
* Updates the effective dimensions where the graph will be drawn, only if the
* dimensions of the given canvas have changed since the last call.
* dimensions have changed since the last call.
*
* @param newWidth the new width
* @param newHeight the new height
*/
private void updateEffectiveDimensionsIfChanged(Canvas c) {
if (w != c.getWidth() || h != c.getHeight()) {
private void updateEffectiveDimensionsIfChanged(int newWidth, int newHeight) {
if (w != newWidth || h != newHeight) {
// Dimensions have changed (for example due to orientation change).
w = c.getWidth();
h = c.getHeight();
w = newWidth;
h = newHeight;
updateEffectiveDimensions();
setUpPath();
}
@@ -804,8 +803,7 @@ public class ChartView extends View {
if (x < 0) {
return;
}
String s =
(mode == Mode.BY_DISTANCE)
String s = chartByDistance
? (shortFormat ? X_SHORT_FORMAT.format(x) : X_FORMAT.format(x))
: StringUtils.formatElapsedTime((long) x);
c.drawText(s,
@@ -832,7 +830,7 @@ public class ChartView extends View {
final int y = effectiveHeight + topBorder;
canvas.drawLine(leftBorder, y, rightEdge, y, borderPaint);
Context c = getContext();
String s = mode == Mode.BY_DISTANCE
String s = chartByDistance
? (metricUnits ? c.getString(R.string.unit_kilometer) : c.getString(R.string.unit_mile))
: c.getString(R.string.unit_minute);
canvas.drawText(s, rightEdge, effectiveHeight + .2f * UNIT_BORDER + topBorder, labelPaint);
@@ -866,17 +864,6 @@ public class ChartView extends View {
}
}
/**
* Returns whether a given time series is enabled for drawing.
*
* @param index the time series, one of {@link #ELEVATION_SERIES},
* {@link #SPEED_SERIES}, {@link #POWER_SERIES}, etc.
* @return true if drawn, false otherwise
*/
public boolean isChartValueSeriesEnabled(int index) {
return series[index].isEnabled();
}
/**
* Sets whether a given time series will be enabled for drawing.
*
@@ -33,14 +33,6 @@ public abstract class Constants {
*/
public static final String SDCARD_TOP_DIR = "MyTracks";
/*
* Main screen tab tags:
*/
public static final String MAP_TAB_TAG = "map";
public static final String STATS_TAB_TAG = "stats";
public static final String CHART_TAB_TAG = "chart";
/**
* The number of distance readings to smooth to get a stable signal.
*/
@@ -129,23 +121,10 @@ public abstract class Constants {
* The name of extra intent property to indicate whether we want to resume
* a previously recorded track.
*/
public static final String RESUME_TRACK_EXTRA_NAME =
"com.google.android.apps.mytracks.RESUME_TRACK";
public static final String
RESUME_TRACK_EXTRA_NAME = "com.google.android.apps.mytracks.RESUME_TRACK";
public static final String MAPSHOP_BASE_URL =
"https://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 MAPSHOP_BASE_URL = "https://maps.google.com/maps/ms";
public static final String SETTINGS_NAME = "SettingsActivity";
@@ -27,7 +27,8 @@ public interface ContextualActionModeCallback {
* Invoked when an item is selected.
*
* @param itemId the context menu item id
* @param id the row id of the item that is selected
* @param position the position of the selected row
* @param id the id of the selected row, if available
*/
public boolean onClick(int itemId, long id);
public boolean onClick(int itemId, int position, long id);
}
@@ -17,14 +17,9 @@
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.fragments.AboutDialogFragment;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.maps.mytracks.R;
import android.content.Intent;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.support.v4.app.FragmentActivity;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
@@ -33,13 +28,11 @@ import android.view.View.OnClickListener;
*
* @author Sandor Dornbush
*/
public class HelpActivity extends FragmentActivity {
public class HelpActivity extends AbstractMyTracksActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
ApiAdapterFactory.getApiAdapter().configureActionBarHomeAsUp(this);
setContentView(R.layout.help);
findViewById(R.id.help_ok).setOnClickListener(new OnClickListener() {
@@ -54,14 +47,4 @@ public class HelpActivity extends FragmentActivity {
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() != android.R.id.home) {
return false;
}
startActivity(new Intent(this, TrackListActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
return true;
}
}
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.apps.mytracks.util.FileUtils;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.UriUtils;
import com.google.android.maps.mytracks.R;
@@ -140,8 +141,8 @@ public class ImportActivity extends Activity {
@Override
public void onClick(DialogInterface dialog, int which) {
if (!importAll && trackId != -1L) {
Intent intent = new Intent(ImportActivity.this, TrackDetailActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
Intent intent = IntentUtils.newIntent(
ImportActivity.this, TrackDetailActivity.class)
.putExtra(TrackDetailActivity.EXTRA_TRACK_ID, trackId);
startActivity(intent);
}
@@ -21,6 +21,7 @@ import com.google.android.apps.mytracks.io.file.GpxImporter;
import com.google.android.apps.mytracks.util.FileUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.SystemUtils;
import com.google.android.maps.mytracks.R;
import android.os.AsyncTask;
import android.os.PowerManager.WakeLock;
@@ -82,7 +83,8 @@ public class ImportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(importActivity);
// Get the wake lock if not recording
if (PreferencesUtils.getRecordingTrackId(importActivity) == -1L) {
if (PreferencesUtils.getLong(importActivity, R.string.recording_track_id_key)
== PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) {
wakeLock = SystemUtils.acquireWakeLock(importActivity, wakeLock);
}
@@ -21,7 +21,9 @@ import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.maps.TrackPathPainter;
import com.google.android.apps.mytracks.maps.TrackPathPainterFactory;
import com.google.android.apps.mytracks.maps.TrackPathUtilities;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
@@ -145,7 +147,7 @@ public class MapOverlay extends Overlay implements OnSharedPreferenceChangeListe
arrow.setBounds(0, 0, arrowWidth, arrowHeight);
}
statsMarker = resources.getDrawable(R.drawable.ylw_pushpin);
statsMarker = resources.getDrawable(R.drawable.yellow_pushpin);
markerWidth = statsMarker.getIntrinsicWidth();
markerHeight = statsMarker.getIntrinsicHeight();
statsMarker.setBounds(0, 0, markerWidth, markerHeight);
@@ -442,10 +444,8 @@ public class MapOverlay extends Overlay implements OnSharedPreferenceChangeListe
}
}
if (waypoint != null &&
dmin < 15000000 / Math.pow(2, mapView.getZoomLevel())) {
Intent intent = new Intent(context, MarkerDetailActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
if (waypoint != null && dmin < 15000000 / Math.pow(2, mapView.getZoomLevel())) {
Intent intent = IntentUtils.newIntent(context, MarkerDetailActivity.class)
.putExtra(MarkerDetailActivity.EXTRA_MARKER_ID, waypoint.getId());
context.startActivity(intent);
return true;
@@ -463,10 +463,8 @@ public class MapOverlay extends Overlay implements OnSharedPreferenceChangeListe
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Log.d(TAG, "MapOverlay: onSharedPreferences changed " + key);
if (key != null) {
if (key.equals(context.getString(R.string.track_color_mode_key))) {
trackPathPainter = TrackPathPainterFactory.getTrackPathPainter(context);
}
if (PreferencesUtils.getKey(context, R.string.track_color_mode_key).equals(key)) {
trackPathPainter = TrackPathPainterFactory.getTrackPathPainter(context);
}
}
}
@@ -19,17 +19,12 @@ package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.fragments.DeleteOneMarkerDialogFragment;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.StatsUtils;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -41,18 +36,17 @@ import android.widget.TextView;
*
* @author Leif Hendrik Wilden
*/
public class MarkerDetailActivity extends FragmentActivity {
public class MarkerDetailActivity extends AbstractMyTracksActivity {
public static final String EXTRA_MARKER_ID = "marker_id";
private static final String TAG = MarkerDetailActivity.class.getSimpleName();
private long markerId;
private Waypoint waypoint;
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
ApiAdapterFactory.getApiAdapter().configureActionBarHomeAsUp(this);
setContentView(R.layout.marker_detail);
markerId = getIntent().getLongExtra(EXTRA_MARKER_ID, -1L);
@@ -62,7 +56,7 @@ public class MarkerDetailActivity extends FragmentActivity {
return;
}
Waypoint waypoint = MyTracksProviderUtils.Factory.get(this).getWaypoint(markerId);
waypoint = MyTracksProviderUtils.Factory.get(this).getWaypoint(markerId);
if (waypoint == null) {
Log.d(TAG, "waypoint is null");
finish();
@@ -78,58 +72,17 @@ public class MarkerDetailActivity extends FragmentActivity {
waypointSection.setVisibility(View.VISIBLE);
statisticsSection.setVisibility(View.GONE);
TextView markerType = (TextView) findViewById(R.id.marker_detail_marker_type);
markerType.setText(getString(R.string.marker_detail_marker_type, waypoint.getCategory()));
TextView description = (TextView) findViewById(R.id.marker_detail_description);
description.setText(getString(R.string.marker_detail_description, waypoint.getDescription()));
TextView markerType = (TextView) findViewById(R.id.marker_detail_waypoint_marker_type);
markerType.setText(getString(
R.string.marker_detail_waypoint_marker_type, waypoint.getCategory()));
TextView description = (TextView) findViewById(R.id.marker_detail_waypoint_description);
description.setText(getString(
R.string.marker_detail_waypoint_description, waypoint.getDescription()));
} else {
waypointSection.setVisibility(View.GONE);
statisticsSection.setVisibility(View.VISIBLE);
SharedPreferences preferences = getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
boolean metricUnits = preferences.getBoolean(getString(R.string.metric_units_key), true);
boolean reportSpeed = preferences.getBoolean(getString(R.string.report_speed_key), true);
StatsUtils.setSpeedLabel(this, R.id.marker_detail_max_speed_label, R.string.stat_max_speed,
R.string.stat_fastest_pace, reportSpeed);
StatsUtils.setSpeedLabel(this, R.id.marker_detail_average_speed_label,
R.string.stat_average_speed, R.string.stat_average_pace, reportSpeed);
StatsUtils.setSpeedLabel(this, R.id.marker_detail_average_moving_speed_label,
R.string.stat_average_moving_speed, R.string.stat_average_moving_pace, reportSpeed);
TripStatistics tripStatistics = waypoint.getStatistics();
StatsUtils.setDistanceValue(this, R.id.marker_detail_total_distance_value,
tripStatistics.getTotalDistance(), metricUnits);
StatsUtils.setSpeedValue(this, R.id.marker_detail_max_speed_value,
tripStatistics.getMaxSpeed(), reportSpeed, metricUnits);
StatsUtils.setTimeValue(
this, R.id.marker_detail_total_time_value, tripStatistics.getTotalTime());
StatsUtils.setSpeedValue(this, R.id.marker_detail_average_speed_value,
tripStatistics.getAverageSpeed(), reportSpeed, metricUnits);
StatsUtils.setTimeValue(
this, R.id.marker_detail_moving_time_value, tripStatistics.getMovingTime());
StatsUtils.setSpeedValue(this, R.id.marker_detail_average_moving_speed_value,
tripStatistics.getAverageMovingSpeed(), reportSpeed, metricUnits);
StatsUtils.setAltitudeValue(this, R.id.marker_detail_elevation_value,
waypoint.getLocation().getAltitude(), metricUnits);
StatsUtils.setAltitudeValue(this, R.id.marker_detail_elevation_gain_value,
tripStatistics.getTotalElevationGain(), metricUnits);
StatsUtils.setAltitudeValue(this, R.id.marker_detail_min_elevation_value,
tripStatistics.getMinElevation(), metricUnits);
StatsUtils.setAltitudeValue(this, R.id.marker_detail_max_elevation_value,
tripStatistics.getMaxElevation(), metricUnits);
StatsUtils.setGradeValue(
this, R.id.marker_detail_min_grade_value, tripStatistics.getMinGrade());
StatsUtils.setGradeValue(
this, R.id.marker_detail_max_grade_value, tripStatistics.getMaxGrade());
StatsUtils.setTripStatisticsValues(this, waypoint.getStatistics());
StatsUtils.setLocationValues(this, waypoint.getLocation(), false);
}
}
@@ -139,24 +92,30 @@ public class MarkerDetailActivity extends FragmentActivity {
return true;
}
@Override
protected void onHomeSelected() {
Intent intent = IntentUtils.newIntent(this, MarkerListActivity.class)
.putExtra(MarkerListActivity.EXTRA_TRACK_ID, waypoint.getTrackId());
startActivity(intent);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent intent;
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
case R.id.marker_detail_show_on_map:
startActivity(new Intent(this, TrackDetailActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(TrackDetailActivity.EXTRA_MARKER_ID, markerId));
return true;
intent = IntentUtils.newIntent(this, TrackDetailActivity.class)
.putExtra(TrackDetailActivity.EXTRA_MARKER_ID, markerId);
startActivity(intent);
return true;
case R.id.marker_detail_edit:
startActivity(new Intent(this, MarkerEditActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, markerId));
intent = IntentUtils.newIntent(this, MarkerEditActivity.class)
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, markerId);
startActivity(intent);
return true;
case R.id.marker_detail_delete:
DeleteOneMarkerDialogFragment.newInstance(markerId).show(getSupportFragmentManager(),
DeleteOneMarkerDialogFragment.newInstance(markerId, waypoint.getTrackId()).show(
getSupportFragmentManager(),
DeleteOneMarkerDialogFragment.DELETE_ONE_MARKER_DIALOG_TAG);
return true;
default:
@@ -20,81 +20,98 @@ import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.content.WaypointCreationRequest.WaypointType;
import com.google.android.apps.mytracks.services.ITrackRecordingService;
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.os.Bundle;
import android.os.RemoteException;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioGroup;
import android.widget.Toast;
/**
* An activity to add/edit a marker.
*
* @author Jimmy Shih
*/
public class MarkerEditActivity extends Activity {
public class MarkerEditActivity extends AbstractMyTracksActivity {
private static final String TAG = MarkerEditActivity.class.getSimpleName();
public static final String EXTRA_TRACK_ID = "track_id";
public static final String EXTRA_MARKER_ID = "marker_id";
public static final String EXTRA_STATISTICS_MARKER = "statistics_marker";
private long trackId;
private long markerId;
private boolean statisticsMarker;
private TrackRecordingServiceConnection trackRecordingServiceConnection;
private Waypoint waypoint;
// UI elements
private View typeSection;
private RadioGroup type;
private EditText name;
private View statisticsSection;
private EditText statisticsName;
private View waypointSection;
private AutoCompleteTextView markerType;
private EditText description;
private EditText waypointName;
private AutoCompleteTextView waypointMarkerType;
private EditText waypointDescription;
private Button done;
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
ApiAdapterFactory.getApiAdapter().configureActionBarHomeAsUp(this);
setContentView(R.layout.marker_edit);
trackId = getIntent().getLongExtra(EXTRA_TRACK_ID, -1L);
markerId = getIntent().getLongExtra(EXTRA_MARKER_ID, -1L);
trackRecordingServiceConnection = new TrackRecordingServiceConnection(this, null);
statisticsMarker = getIntent().getBooleanExtra(EXTRA_STATISTICS_MARKER, true);
trackRecordingServiceConnection = new TrackRecordingServiceConnection(this, null);
// Setup UI elements
typeSection = findViewById(R.id.marker_edit_type_section);
type = (RadioGroup) findViewById(R.id.marker_edit_type);
type.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
boolean statistics = checkedId == R.id.marker_edit_type_statistics;
name.setText(
statistics ? R.string.marker_edit_type_statistics : R.string.marker_edit_type_waypoint);
updateUiByMarkerType(statistics);
boolean statistics = checkedId == R.id.marker_edit_statistics;
statisticsSection.setVisibility(statistics ? View.VISIBLE : View.GONE);
waypointSection.setVisibility(statistics ? View.GONE : View.VISIBLE);
int nextMarkerNumber = trackId == -1L ? -1
: MyTracksProviderUtils.Factory.get(MarkerEditActivity.this)
.getNextMarkerNumber(trackId, statistics);
if (statistics) {
String name = nextMarkerNumber == -1 ? getString(R.string.marker_type_statistics)
: getString(R.string.marker_statistics_name_format, nextMarkerNumber);
statisticsName.setText(name);
statisticsName.selectAll();
} else {
String name = nextMarkerNumber == -1 ? getString(R.string.marker_type_waypoint)
: getString(R.string.marker_waypoint_name_format, nextMarkerNumber);
waypointName.setText(name);
waypointName.selectAll();
waypointMarkerType.setText("");
waypointDescription.setText("");
}
}
});
name = (EditText) findViewById(R.id.marker_edit_name);
statisticsSection = findViewById(R.id.marker_edit_statistics_section);
statisticsName = (EditText) findViewById(R.id.marker_edit_statistics_name);
waypointSection = findViewById(R.id.marker_edit_waypoint_section);
markerType = (AutoCompleteTextView) findViewById(R.id.marker_edit_marker_type);
waypointName = (EditText) findViewById(R.id.marker_edit_waypoint_name);
waypointMarkerType = (AutoCompleteTextView) findViewById(R.id.marker_edit_waypoint_marker_type);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this, R.array.waypoint_types, android.R.layout.simple_dropdown_item_1line);
markerType.setAdapter(adapter);
description = (EditText) findViewById(R.id.marker_edit_description);
waypointMarkerType.setAdapter(adapter);
waypointDescription = (EditText) findViewById(R.id.marker_edit_waypoint_description);
Button cancel = (Button) findViewById(R.id.marker_edit_cancel);
cancel.setOnClickListener(new OnClickListener() {
@@ -113,9 +130,9 @@ public class MarkerEditActivity extends Activity {
private void updateUiByMarkerId() {
final boolean newMarker = markerId == -1L;
setTitle(newMarker ? R.string.marker_edit_add_title : R.string.menu_edit);
setTitle(newMarker ? R.string.menu_insert_marker : R.string.menu_edit);
typeSection.setVisibility(newMarker ? View.VISIBLE : View.GONE);
done.setText(newMarker ? R.string.marker_edit_add : R.string.generic_save);
done.setText(newMarker ? R.string.generic_add : R.string.generic_save);
done.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -129,7 +146,7 @@ public class MarkerEditActivity extends Activity {
});
if (newMarker) {
type.check(R.id.marker_edit_type_statistics);
type.check(statisticsMarker ? R.id.marker_edit_statistics : R.id.marker_edit_waypoint);
} else {
waypoint = MyTracksProviderUtils.Factory.get(this).getWaypoint(markerId);
if (waypoint == null) {
@@ -137,29 +154,19 @@ public class MarkerEditActivity extends Activity {
finish();
return;
}
name.setText(waypoint.getName());
boolean statistics = waypoint.getType() == Waypoint.TYPE_STATISTICS;
updateUiByMarkerType(statistics);
if (!statistics) {
markerType.setText(waypoint.getCategory());
description.setText(waypoint.getDescription());
}
statisticsSection.setVisibility(statistics ? View.VISIBLE : View.GONE);
waypointSection.setVisibility(statistics ? View.GONE : View.VISIBLE);
if (statistics) {
statisticsName.setText(waypoint.getName());
} else {
waypointName.setText(waypoint.getName());
waypointMarkerType.setText(waypoint.getCategory());
waypointDescription.setText(waypoint.getDescription());
}
}
}
/**
* Updates the UI by marker type.
*
* @param statistics true for a statistics marker
*/
private void updateUiByMarkerType(boolean statistics) {
name.setCompoundDrawablesWithIntrinsicBounds(
statistics ? R.drawable.ylw_pushpin : R.drawable.blue_pushpin, 0, 0, 0);
name.setImeOptions(statistics ? EditorInfo.IME_ACTION_DONE : EditorInfo.IME_ACTION_NEXT);
waypointSection.setVisibility(statistics ? View.GONE : View.VISIBLE);
}
@Override
protected void onResume() {
super.onResume();
@@ -172,54 +179,37 @@ public class MarkerEditActivity extends Activity {
trackRecordingServiceConnection.unbind();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() != android.R.id.home) {
return false;
}
finish();
return true;
}
/**
* Adds a marker.
*/
private void addMarker() {
boolean statistics = type.getCheckedRadioButtonId() == R.id.marker_edit_type_statistics;
WaypointType waypointType = statistics ? WaypointType.STATISTICS : WaypointType.MARKER;
String markerCategory = statistics ? null : markerType.getText().toString();
String markerDescription = statistics ? null : description.getText().toString();
String markerIconUrl = getString(
statistics ? R.string.marker_statistics_icon_url : R.string.marker_waypoint_icon_url);
boolean statistics = type.getCheckedRadioButtonId() == R.id.marker_edit_statistics;
PreferencesUtils.setBoolean(this, R.string.pick_statistics_marker_key, statistics);
WaypointType waypointType = statistics ? WaypointType.STATISTICS : WaypointType.WAYPOINT;
String markerName = statistics ? statisticsName.getText().toString()
: waypointName.getText().toString();
String markerCategory = statistics ? null : waypointMarkerType.getText().toString();
String markerDescription = statistics ? null : waypointDescription.getText().toString();
String markerIconUrl = getString(statistics ? R.string.marker_statistics_icon_url
: R.string.marker_waypoint_icon_url);
WaypointCreationRequest waypointCreationRequest = new WaypointCreationRequest(
waypointType, name.getText().toString(), markerCategory, markerDescription, markerIconUrl);
ITrackRecordingService trackRecordingService =
trackRecordingServiceConnection.getServiceIfBound();
if (trackRecordingService == null) {
Log.d(TAG, "Unable to add marker, no track recording service");
} else {
try {
if (trackRecordingService.insertWaypoint(waypointCreationRequest) != -1L) {
Toast.makeText(this, R.string.marker_edit_add_success, Toast.LENGTH_SHORT).show();
return;
}
} catch (RemoteException e) {
Log.e(TAG, "Unable to add marker", e);
} catch (IllegalStateException e) {
Log.e(TAG, "Unable to add marker.", e);
}
}
Toast.makeText(this, R.string.marker_edit_add_error, Toast.LENGTH_LONG).show();
waypointType, markerName, markerCategory, markerDescription, markerIconUrl);
TrackRecordingServiceConnectionUtils.addMarker(
this, trackRecordingServiceConnection, waypointCreationRequest);
}
/**
* Saves a marker.
*/
private void saveMarker() {
waypoint.setName(name.getText().toString());
if (waypoint.getType() == Waypoint.TYPE_WAYPOINT) {
waypoint.setCategory(markerType.getText().toString());
waypoint.setDescription(description.getText().toString());
boolean statistics = waypoint.getType() == Waypoint.TYPE_STATISTICS;
if (statistics) {
waypoint.setName(statisticsName.getText().toString());
} else {
waypoint.setName(waypointName.getText().toString());
waypoint.setCategory(waypointMarkerType.getText().toString());
waypoint.setDescription(waypointDescription.getText().toString());
}
MyTracksProviderUtils.Factory.get(this).updateWaypoint(waypoint);
}
@@ -20,7 +20,10 @@ import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.WaypointsColumns;
import com.google.android.apps.mytracks.fragments.DeleteOneMarkerDialogFragment;
import com.google.android.apps.mytracks.fragments.MarkerAddDialogFragment;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.ListItemUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
@@ -31,8 +34,6 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.database.Cursor;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
@@ -48,14 +49,13 @@ import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;
/**
* Activity to show a list of markers in a track.
*
* @author Leif Hendrik Wilden
*/
public class MarkerListActivity extends FragmentActivity {
public class MarkerListActivity extends AbstractMyTracksActivity {
public static final String EXTRA_TRACK_ID = "track_id";
@@ -72,7 +72,7 @@ public class MarkerListActivity extends FragmentActivity {
private ContextualActionModeCallback contextualActionModeCallback =
new ContextualActionModeCallback() {
@Override
public boolean onClick(int itemId, long id) {
public boolean onClick(int itemId, int position, long id) {
return handleContextItem(itemId, id);
}
};
@@ -81,16 +81,17 @@ public class MarkerListActivity extends FragmentActivity {
* Note that sharedPreferenceChangeListener cannot be an anonymous inner
* class. Anonymous inner class will get garbage collected.
*/
private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener =
new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
// Note that key can be null
if (PreferencesUtils.getRecordingTrackIdKey(MarkerListActivity.this).equals(key)) {
updateMenu();
}
}
};
private final OnSharedPreferenceChangeListener
sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
// Note that key can be null
if (PreferencesUtils.getKey(MarkerListActivity.this, R.string.recording_track_id_key)
.equals(key)) {
updateMenu();
}
}
};
private long trackId = -1;
private ResourceCursorAdapter resourceCursorAdapter;
@@ -110,26 +111,23 @@ public class MarkerListActivity extends FragmentActivity {
return;
}
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
ApiAdapterFactory.getApiAdapter().configureActionBarHomeAsUp(this);
setContentView(R.layout.marker_list);
SharedPreferences sharedPreferences = getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE)
.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
ListView listView = (ListView) findViewById(R.id.marker_list);
listView.setEmptyView(findViewById(R.id.marker_list_empty));
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
startActivity(new Intent(MarkerListActivity.this, MarkerDetailActivity.class).addFlags(
Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(MarkerDetailActivity.EXTRA_MARKER_ID, id));
Intent intent = IntentUtils.newIntent(MarkerListActivity.this, MarkerDetailActivity.class)
.putExtra(MarkerDetailActivity.EXTRA_MARKER_ID, id);
startActivity(intent);
}
});
resourceCursorAdapter = new ResourceCursorAdapter(this, R.layout.marker_list_item, null, 0) {
resourceCursorAdapter = new ResourceCursorAdapter(this, R.layout.list_item, null, 0) {
@Override
public void bindView(View view, Context context, Cursor cursor) {
int typeIndex = cursor.getColumnIndex(WaypointsColumns.TYPE);
@@ -139,40 +137,22 @@ public class MarkerListActivity extends FragmentActivity {
int descriptionIndex = cursor.getColumnIndex(WaypointsColumns.DESCRIPTION);
boolean statistics = cursor.getInt(typeIndex) == Waypoint.TYPE_STATISTICS;
TextView name = (TextView) view.findViewById(R.id.marker_list_item_name);
name.setText(cursor.getString(nameIndex));
name.setCompoundDrawablesWithIntrinsicBounds(statistics ? R.drawable.ylw_pushpin
: R.drawable.blue_pushpin, 0, 0, 0);
TextView category = (TextView) view.findViewById(R.id.marker_list_item_category);
if (!statistics) {
category.setText(cursor.getString(categoryIndex));
}
category.setVisibility(statistics || category.getText().length() == 0 ? View.GONE : View.VISIBLE);
TextView time = (TextView) view.findViewById(R.id.marker_list_item_time);
long timeValue = cursor.getLong(timeIndex);
if (timeValue == 0) {
time.setVisibility(View.GONE);
} else {
time.setText(StringUtils.formatDateTime(MarkerListActivity.this, timeValue));
time.setVisibility(View.VISIBLE);
}
TextView description = (TextView) view.findViewById(R.id.marker_list_item_description);
if (!statistics) {
description.setText(cursor.getString(descriptionIndex));
}
description.setVisibility(statistics || description.getText().length() == 0 ? View.GONE : View.VISIBLE);
String name = cursor.getString(nameIndex);
int iconId = statistics ? R.drawable.yellow_pushpin : R.drawable.blue_pushpin;
String category = statistics ? null : cursor.getString(categoryIndex);
long time = cursor.getLong(timeIndex);
String startTime = time == 0
? null : StringUtils.formatDateTime(MarkerListActivity.this, time);
String description = statistics ? null : cursor.getString(descriptionIndex);
ListItemUtils.setListItem(view, name, iconId, category, null, null, startTime, description);
}
};
listView.setAdapter(resourceCursorAdapter);
ApiAdapterFactory.getApiAdapter().configureListViewContextualMenu(
this, listView, R.menu.marker_list_context_menu, R.id.marker_list_item_name,
contextualActionModeCallback);
ApiAdapterFactory.getApiAdapter().configureListViewContextualMenu(this, listView,
R.menu.list_context_menu, R.id.list_item_name, contextualActionModeCallback);
final long firstWaypointId = MyTracksProviderUtils.Factory.get(this).getFirstWaypointId(trackId);
final long firstWaypointId = MyTracksProviderUtils.Factory.get(this)
.getFirstWaypointId(trackId);
getSupportLoaderManager().initLoader(0, null, new LoaderCallbacks<Cursor>() {
@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
@@ -208,19 +188,17 @@ public class MarkerListActivity extends FragmentActivity {
private void updateMenu() {
if (insertMarkerMenuItem != null) {
insertMarkerMenuItem.setVisible(trackId == PreferencesUtils.getRecordingTrackId(this));
insertMarkerMenuItem.setVisible(
trackId == PreferencesUtils.getLong(this, R.string.recording_track_id_key));
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
case R.id.marker_list_insert_marker:
startActivity(new Intent(this, MarkerEditActivity.class).addFlags(
Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
MarkerAddDialogFragment.newInstance(trackId)
.show(getSupportFragmentManager(), MarkerAddDialogFragment.MARKER_ADD_DIALOG_TAG);
return true;
case R.id.marker_list_search:
return ApiAdapterFactory.getApiAdapter().handleSearchMenuSelection(this);
@@ -232,7 +210,7 @@ public class MarkerListActivity extends FragmentActivity {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
getMenuInflater().inflate(R.menu.marker_list_context_menu, menu);
getMenuInflater().inflate(R.menu.list_context_menu, menu);
}
@Override
@@ -252,19 +230,21 @@ public class MarkerListActivity extends FragmentActivity {
* @return true if handled.
*/
private boolean handleContextItem(int itemId, long markerId) {
Intent intent;
switch (itemId) {
case R.id.marker_list_context_menu_show_on_map:
startActivity(new Intent(this, TrackDetailActivity.class).addFlags(
Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(TrackDetailActivity.EXTRA_MARKER_ID, markerId));
case R.id.list_context_menu_show_on_map:
intent = IntentUtils.newIntent(this, TrackDetailActivity.class)
.putExtra(TrackDetailActivity.EXTRA_MARKER_ID, markerId);
startActivity(intent);
return true;
case R.id.marker_list_context_menu_edit:
startActivity(new Intent(this, MarkerEditActivity.class).addFlags(
Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, markerId));
case R.id.list_context_menu_edit:
intent = IntentUtils.newIntent(this, MarkerEditActivity.class)
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, markerId);
startActivity(intent);
return true;
case R.id.marker_list_context_menu_delete:
DeleteOneMarkerDialogFragment.newInstance(markerId).show(getSupportFragmentManager(),
case R.id.list_context_menu_delete:
DeleteOneMarkerDialogFragment.newInstance(markerId, trackId).show(
getSupportFragmentManager(),
DeleteOneMarkerDialogFragment.DELETE_ONE_MARKER_DIALOG_TAG);
return true;
default:
@@ -39,7 +39,8 @@ public class MyTracksApplication extends Application {
ApiAdapterFactory.getApiAdapter().enableStrictMode();
}
AnalyticsUtils.sendPageViews(this, "/appstart");
startService(new Intent(this, RemoveTempFilesService.class));
Intent intent = new Intent(this, RemoveTempFilesService.class);
startService(intent);
}
/**
@@ -28,17 +28,17 @@ import android.os.Bundle;
import android.widget.Toast;
/**
* An activity to export all the tracks to the SD card.
* An activity to save all the tracks to the SD card.
*
* @author Sandor Dornbush
*/
public class ExportActivity extends Activity {
public class SaveAllActivity extends Activity {
public static final String EXTRA_TRACK_FILE_FORMAT = "track_file_format";
private static final int DIALOG_PROGRESS_ID = 0;
private ExportAsyncTask exportAsyncTask;
private SaveAllAsyncTask saveAllAsyncTask;
private ProgressDialog progressDialog;
@Override
@@ -46,22 +46,22 @@ public class ExportActivity extends Activity {
super.onCreate(savedInstanceState);
Object retained = getLastNonConfigurationInstance();
if (retained instanceof ExportAsyncTask) {
exportAsyncTask = (ExportAsyncTask) retained;
exportAsyncTask.setActivity(this);
if (retained instanceof SaveAllAsyncTask) {
saveAllAsyncTask = (SaveAllAsyncTask) retained;
saveAllAsyncTask.setActivity(this);
} else {
Intent intent = getIntent();
TrackFileFormat trackFileFormat = intent.getParcelableExtra(EXTRA_TRACK_FILE_FORMAT);
exportAsyncTask = new ExportAsyncTask(this, trackFileFormat);
exportAsyncTask.execute();
saveAllAsyncTask = new SaveAllAsyncTask(this, trackFileFormat);
saveAllAsyncTask.execute();
}
}
@Override
public Object onRetainNonConfigurationInstance() {
exportAsyncTask.setActivity(null);
return exportAsyncTask;
saveAllAsyncTask.setActivity(null);
return saveAllAsyncTask;
}
@Override
@@ -70,10 +70,10 @@ public class ExportActivity extends Activity {
return null;
}
progressDialog = DialogUtils.createHorizontalProgressDialog(
this, R.string.export_progress_message, new DialogInterface.OnCancelListener() {
this, R.string.save_all_progress_message, new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
exportAsyncTask.cancel(true);
saveAllAsyncTask.cancel(true);
finish();
}
});
@@ -102,7 +102,7 @@ public class ExportActivity extends Activity {
/**
* Sets the progress dialog value.
*
* @param number the number of tracks exported
* @param number the number of tracks saved
* @param max the maximum number of tracks
*/
public void setProgressDialogValue(int number, int max) {
@@ -31,13 +31,13 @@ import android.os.AsyncTask;
import android.os.PowerManager.WakeLock;
/**
* AsyncTask to export all the tracks to the SD card.
* AsyncTask to save all the tracks to the SD card.
*
* @author Jimmy Shih
*/
public class ExportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
public class SaveAllAsyncTask extends AsyncTask<Void, Integer, Boolean> {
private ExportActivity exportActivity;
private SaveAllActivity saveAllActivity;
private final TrackFileFormat trackFileFormat;
private final Context context;
private final MyTracksProviderUtils myTracksProviderUtils;
@@ -56,40 +56,41 @@ public class ExportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
/**
* Creates an AsyncTask.
*
* @param exportActivity the activity currently associated with this AsyncTask
* @param saveAllActivity the activity currently associated with this AsyncTask
* @param trackFileFormat the track file format
*/
public ExportAsyncTask(ExportActivity exportActivity, TrackFileFormat trackFileFormat) {
this.exportActivity = exportActivity;
public SaveAllAsyncTask(SaveAllActivity saveAllActivity, TrackFileFormat trackFileFormat) {
this.saveAllActivity = saveAllActivity;
this.trackFileFormat = trackFileFormat;
context = exportActivity.getApplicationContext();
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(exportActivity);
context = saveAllActivity.getApplicationContext();
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(saveAllActivity);
// Get the wake lock if not recording
if (PreferencesUtils.getRecordingTrackId(exportActivity) == -1L) {
wakeLock = SystemUtils.acquireWakeLock(exportActivity, wakeLock);
if (PreferencesUtils.getLong(saveAllActivity, R.string.recording_track_id_key)
== PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) {
wakeLock = SystemUtils.acquireWakeLock(saveAllActivity, wakeLock);
}
success = false;
completed = false;
messageId = R.string.export_error;
messageId = R.string.save_all_error;
}
/**
* Sets the current {@link ExportActivity} associated with this AyncTask.
* Sets the current {@link SaveAllActivity} associated with this AyncTask.
*
* @param exportActivity the current {@link ExportActivity}, can be null
* @param saveAllActivity the current {@link SaveAllActivity}, can be null
*/
public void setActivity(ExportActivity exportActivity) {
this.exportActivity = exportActivity;
if (completed && exportActivity != null) {
exportActivity.onAsyncTaskCompleted(success, messageId);
public void setActivity(SaveAllActivity saveAllActivity) {
this.saveAllActivity = saveAllActivity;
if (completed && saveAllActivity != null) {
saveAllActivity.onAsyncTaskCompleted(success, messageId);
}
}
@Override
protected void onPreExecute() {
if (exportActivity != null) {
exportActivity.showProgressDialog();
if (saveAllActivity != null) {
saveAllActivity.showProgressDialog();
}
}
@@ -99,7 +100,7 @@ public class ExportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
try {
cursor = myTracksProviderUtils.getTracksCursor(null, null, TracksColumns._ID);
if (cursor == null) {
messageId = R.string.export_success;
messageId = R.string.save_all_success;
return true;
}
int count = cursor.getCount();
@@ -123,7 +124,7 @@ public class ExportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
}
publishProgress(i + 1, count);
}
messageId = R.string.export_success;
messageId = R.string.save_all_success;
return true;
} finally {
if (cursor != null) {
@@ -138,8 +139,8 @@ public class ExportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
@Override
protected void onProgressUpdate(Integer... values) {
if (exportActivity != null) {
exportActivity.setProgressDialogValue(values[0], values[1]);
if (saveAllActivity != null) {
saveAllActivity.setProgressDialogValue(values[0], values[1]);
}
}
@@ -147,8 +148,8 @@ public class ExportAsyncTask extends AsyncTask<Void, Integer, Boolean> {
protected void onPostExecute(Boolean result) {
success = result;
completed = true;
if (exportActivity != null) {
exportActivity.onAsyncTaskCompleted(success, messageId);
if (saveAllActivity != null) {
saveAllActivity.onAsyncTaskCompleted(success, messageId);
}
}
@@ -1,260 +0,0 @@
/*
* 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.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.SearchEngine;
import com.google.android.apps.mytracks.content.SearchEngine.ScoredResult;
import com.google.android.apps.mytracks.content.SearchEngine.SearchQuery;
import com.google.android.apps.mytracks.content.SearchEngineProvider;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
import android.app.ListActivity;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.SearchRecentSuggestions;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
/**
* Activity to search for tracks or waypoints.
*
* @author Rodrigo Damazio
*/
public class SearchActivity extends ListActivity {
private static final String ICON_FIELD = "icon";
private static final String NAME_FIELD = "name";
private static final String DESCRIPTION_FIELD = "description";
private static final String CATEGORY_FIELD = "category";
private static final String TIME_FIELD = "time";
private static final String STATS_FIELD = "stats";
private static final String TRACK_ID_FIELD = "trackId";
private static final String WAYPOINT_ID_FIELD = "waypointId";
public static final String EXTRA_TRACK_ID = "track_id";
private static final boolean LOG_SCORES = true;
private MyTracksProviderUtils providerUtils;
private SearchEngine engine;
private LocationManager locationManager;
private SharedPreferences preferences;
private SearchRecentSuggestions suggestions;
private boolean metricUnits;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
providerUtils = MyTracksProviderUtils.Factory.get(this);
engine = new SearchEngine(providerUtils);
suggestions = SearchEngineProvider.newHelper(this);
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
preferences = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
setContentView(R.layout.search_list);
handleIntent(getIntent());
}
@Override
protected void onResume() {
super.onResume();
metricUnits =
preferences.getBoolean(getString(R.string.metric_units_key), true);
}
@Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
handleIntent(intent);
}
private void handleIntent(Intent intent) {
if (!Intent.ACTION_SEARCH.equals(intent.getAction())) {
Log.e(TAG, "Got bad search intent: " + intent);
finish();
return;
}
String textQuery = intent.getStringExtra(SearchManager.QUERY);
Location currentLocation = locationManager.getLastKnownLocation("gps");
long currentTrackId = intent.getLongExtra(EXTRA_TRACK_ID, -1L);
long currentTimestamp = System.currentTimeMillis();
final SearchQuery query =
new SearchQuery(textQuery, currentLocation, currentTrackId, currentTimestamp);
// Do the actual search in a separate thread.
new Thread() {
@Override
public void run() {
doSearch(query);
}
}.start();
}
private void doSearch(SearchQuery query) {
SortedSet<ScoredResult> scoredResults = engine.search(query);
final List<? extends Map<String, ?>> displayResults = prepareResultsforDisplay(scoredResults);
if (LOG_SCORES) {
Log.i(TAG, "Search scores: " + displayResults);
}
// Then go back to the UI thread to display them.
runOnUiThread(new Runnable() {
@Override
public void run() {
showSearchResults(displayResults);
}
});
// Save the query as a suggestion for the future.
suggestions.saveRecentQuery(query.textQuery, null);
}
private List<Map<String, Object>> prepareResultsforDisplay(
Collection<ScoredResult> scoredResults) {
ArrayList<Map<String, Object>> output = new ArrayList<Map<String, Object>>(scoredResults.size());
for (ScoredResult result : scoredResults) {
Map<String, Object> resultMap = new HashMap<String, Object>();
if (result.track != null) {
prepareTrackForDisplay(result.track, resultMap);
} else {
prepareWaypointForDisplay(result.waypoint, resultMap);
}
resultMap.put("score", result.score);
output.add(resultMap);
}
return output;
}
private void prepareWaypointForDisplay(Waypoint waypoint, Map<String, Object> resultMap) {
// Look up the owner track.
// TODO: It may be more appropriate to do this as a join in the retrieval phase of the search.
String trackName = null;
long trackId = waypoint.getTrackId();
if (trackId > 0) {
Track track = providerUtils.getTrack(trackId);
if (track != null) {
trackName = track.getName();
}
}
resultMap.put(ICON_FIELD, waypoint.getType() == Waypoint.TYPE_STATISTICS
? R.drawable.ylw_pushpin : R.drawable.blue_pushpin);
resultMap.put(NAME_FIELD, waypoint.getName());
resultMap.put(DESCRIPTION_FIELD, waypoint.getDescription());
resultMap.put(CATEGORY_FIELD, waypoint.getCategory());
// In the same place as we show time for tracks, show the track name for waypoints.
resultMap.put(TIME_FIELD, getString(R.string.search_track_location, trackName));
resultMap.put(STATS_FIELD, StringUtils.formatDateTime(this, waypoint.getLocation().getTime()));
resultMap.put(TRACK_ID_FIELD, waypoint.getTrackId());
resultMap.put(WAYPOINT_ID_FIELD, waypoint.getId());
}
private void prepareTrackForDisplay(Track track, Map<String, Object> resultMap) {
TripStatistics stats = track.getStatistics();
resultMap.put(ICON_FIELD, R.drawable.track);
resultMap.put(NAME_FIELD, track.getName());
resultMap.put(DESCRIPTION_FIELD, track.getDescription());
resultMap.put(CATEGORY_FIELD, track.getCategory());
resultMap.put(TIME_FIELD, StringUtils.formatDateTime(this, stats.getStartTime()));
resultMap.put(STATS_FIELD, StringUtils.formatTimeDistance(
this, stats.getTotalTime(), stats.getTotalDistance(), metricUnits));
resultMap.put(TRACK_ID_FIELD, track.getId());
}
/**
* Shows the given search results.
* Must be run from the UI thread.
*
* @param data the results to show, properly ordered
*/
private void showSearchResults(List<? extends Map<String, ?>> data) {
SimpleAdapter adapter = new SimpleAdapter(this, data,
// TODO: Custom view for search results.
R.layout.mytracks_list_item,
new String[] {
ICON_FIELD,
NAME_FIELD,
DESCRIPTION_FIELD,
CATEGORY_FIELD,
TIME_FIELD,
STATS_FIELD,
},
new int[] {
R.id.track_list_item_icon,
R.id.track_list_item_name,
R.id.track_list_item_description,
R.id.track_list_item_category,
R.id.track_list_item_time,
R.id.track_list_item_stats,
});
setListAdapter(adapter);
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
@SuppressWarnings("unchecked")
Map<String, Object> clickedData = (Map<String, Object>) getListAdapter().getItem(position);
startActivity(createViewDataIntent(clickedData));
}
private Intent createViewDataIntent(Map<String, Object> clickedData) {
Intent intent = new Intent(this, TrackDetailActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
if (clickedData.containsKey(WAYPOINT_ID_FIELD)) {
intent.putExtra(
TrackDetailActivity.EXTRA_MARKER_ID, (Long) clickedData.get(WAYPOINT_ID_FIELD));
} else {
intent.putExtra(TrackDetailActivity.EXTRA_TRACK_ID, (Long) clickedData.get(TRACK_ID_FIELD));
}
return intent;
}
}
@@ -0,0 +1,425 @@
/*
* 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.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.SearchEngine;
import com.google.android.apps.mytracks.content.SearchEngine.ScoredResult;
import com.google.android.apps.mytracks.content.SearchEngine.SearchQuery;
import com.google.android.apps.mytracks.content.SearchEngineProvider;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.fragments.DeleteOneMarkerDialogFragment;
import com.google.android.apps.mytracks.fragments.DeleteOneTrackDialogFragment;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.ListItemUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.SearchRecentSuggestions;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
/**
* An activity to display a list of search results.
*
* @author Rodrigo Damazio
*/
public class SearchListActivity extends AbstractMyTracksActivity {
private static final String TAG = SearchListActivity.class.getSimpleName();
private static final String NAME_FIELD = "name";
private static final String ICON_FIELD = "icon";
private static final String CATEGORY_FIELD = "category";
private static final String TOTAL_TIME_FIELD = "totalTime";
private static final String TOTAL_DISTANCE_FIELD = "totalDistance";
private static final String START_TIME_FIELD = "startTime";
private static final String DESCRIPTION_FIELD = "description";
private static final String TRACK_ID_FIELD = "trackId";
private static final String MARKER_ID_FIELD = "markerId";
private final OnSharedPreferenceChangeListener
sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (PreferencesUtils.getKey(SearchListActivity.this, R.string.recording_track_id_key)
.equals(key)) {
recordingTrackId = PreferencesUtils.getLong(
SearchListActivity.this, R.string.recording_track_id_key);
arrayAdapter.notifyDataSetChanged();
}
}
};
// Callback when an item is selected in the contextual action mode
private ContextualActionModeCallback
contextualActionModeCallback = new ContextualActionModeCallback() {
@Override
public boolean onClick(int itemId, int position, long id) {
return handleContextItem(itemId, position);
}
};
private MyTracksProviderUtils myTracksProviderUtils;
private SearchEngine searchEngine;
private SearchRecentSuggestions searchRecentSuggestions;
private LocationManager locationManager;
private long recordingTrackId;
private boolean metricUnits;
private ArrayAdapter<Map<String, Object>> arrayAdapter;
// UI elements
private ListView listView;
private MenuItem searchMenuItem;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
setContentView(R.layout.search_list);
myTracksProviderUtils = MyTracksProviderUtils.Factory.get(this);
searchEngine = new SearchEngine(myTracksProviderUtils);
searchRecentSuggestions = SearchEngineProvider.newHelper(this);
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE)
.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
recordingTrackId = PreferencesUtils.getLong(this, R.string.recording_track_id_key);
listView = (ListView) findViewById(R.id.search_list);
listView.setEmptyView(findViewById(R.id.search_list_empty));
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Map<String, Object> item = arrayAdapter.getItem(position);
Long trackId = (Long) item.get(TRACK_ID_FIELD);
Long markerId = (Long) item.get(MARKER_ID_FIELD);
Intent intent;
if (markerId != null) {
intent = IntentUtils.newIntent(SearchListActivity.this, TrackDetailActivity.class)
.putExtra(TrackDetailActivity.EXTRA_MARKER_ID, markerId);
} else {
intent = IntentUtils.newIntent(SearchListActivity.this, TrackDetailActivity.class)
.putExtra(TrackDetailActivity.EXTRA_TRACK_ID, trackId);
}
startActivity(intent);
}
});
arrayAdapter = new ArrayAdapter<Map<String, Object>>(
this, R.layout.list_item, R.id.list_item_name) {
@Override
public View getView(int position, View convertView, android.view.ViewGroup parent) {
View view;
if (convertView == null) {
view = getLayoutInflater().inflate(R.layout.list_item, parent, false);
} else {
view = convertView;
}
Map<String, Object> resultMap = getItem(position);
String name = (String) resultMap.get(NAME_FIELD);
int iconId = (Integer) resultMap.get(ICON_FIELD);
String category = (String) resultMap.get(CATEGORY_FIELD);
String totalTime = (String) resultMap.get(TOTAL_TIME_FIELD);
String totalDistance = (String) resultMap.get(TOTAL_DISTANCE_FIELD);
String startTime = (String) resultMap.get(START_TIME_FIELD);
String description = (String) resultMap.get(DESCRIPTION_FIELD);
ListItemUtils.setListItem(view,
name,
iconId,
category,
totalTime,
totalDistance,
startTime,
description);
return view;
}
};
listView.setAdapter(arrayAdapter);
ApiAdapterFactory.getApiAdapter().configureListViewContextualMenu(this, listView,
R.menu.list_context_menu, R.id.list_item_name, contextualActionModeCallback);
handleIntent(getIntent());
}
@Override
protected void onResume() {
super.onResume();
metricUnits = PreferencesUtils.getBoolean(
this, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
}
@Override
public void onNewIntent(Intent intent) {
setIntent(intent);
handleIntent(intent);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search_list, menu);
searchMenuItem = menu.findItem(R.id.search_list_search);
ApiAdapterFactory.getApiAdapter().configureSearchWidget(this, searchMenuItem);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.search_list_search:
return ApiAdapterFactory.getApiAdapter().handleSearchMenuSelection(this);
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
getMenuInflater().inflate(R.menu.list_context_menu, menu);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo adapterContextMenuInfo = (AdapterContextMenuInfo) item.getMenuInfo();
if (handleContextItem(item.getItemId(), adapterContextMenuInfo.position)) {
return true;
}
return super.onContextItemSelected(item);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_SEARCH) {
if (ApiAdapterFactory.getApiAdapter().handleSearchKey(searchMenuItem)) {
return true;
}
}
return super.onKeyUp(keyCode, event);
}
/**
* Handles a context item selection.
*
* @param itemId the menu item id
* @param position the position of the selected row
* @return true if handled.
*/
private boolean handleContextItem(int itemId, int position) {
Map<String, Object> item = arrayAdapter.getItem(position);
Long trackId = (Long) item.get(TRACK_ID_FIELD);
Long markerId = (Long) item.get(MARKER_ID_FIELD);
Intent intent;
switch (itemId) {
case R.id.list_context_menu_show_on_map:
if (markerId != null) {
intent = IntentUtils.newIntent(this, TrackDetailActivity.class)
.putExtra(TrackDetailActivity.EXTRA_MARKER_ID, markerId);
} else {
intent = IntentUtils.newIntent(this, TrackDetailActivity.class)
.putExtra(TrackDetailActivity.EXTRA_TRACK_ID, trackId);
}
startActivity(intent);
return true;
case R.id.list_context_menu_edit:
if (markerId != null) {
intent = IntentUtils.newIntent(this, MarkerEditActivity.class)
.putExtra(MarkerEditActivity.EXTRA_MARKER_ID, markerId);
} else {
intent = IntentUtils.newIntent(this, TrackEditActivity.class)
.putExtra(TrackEditActivity.EXTRA_TRACK_ID, trackId);
}
startActivity(intent);
// Close the search result since its content can change after edit.
finish();
return true;
case R.id.list_context_menu_delete:
if (markerId != null) {
DeleteOneMarkerDialogFragment.newInstance(markerId, trackId).show(
getSupportFragmentManager(),
DeleteOneMarkerDialogFragment.DELETE_ONE_MARKER_DIALOG_TAG);
} else {
DeleteOneTrackDialogFragment.newInstance(trackId).show(getSupportFragmentManager(),
DeleteOneTrackDialogFragment.DELETE_ONE_TRACK_DIALOG_TAG);
}
return true;
default:
return false;
}
}
/**
* Handles the intent.
*
* @param intent the intent
*/
private void handleIntent(Intent intent) {
if (!Intent.ACTION_SEARCH.equals(intent.getAction())) {
Log.e(TAG, "Invalid intent action: " + intent);
finish();
return;
}
String textQuery = intent.getStringExtra(SearchManager.QUERY);
setTitle(textQuery);
Location currentLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
final SearchQuery query = new SearchQuery(textQuery, currentLocation, -1L, System
.currentTimeMillis());
new Thread() {
@Override
public void run() {
doSearch(query);
}
}.start();
}
/**
* Do the search.
*
* @param query the query
*/
private void doSearch(SearchQuery query) {
SortedSet<ScoredResult> scoredResults = searchEngine.search(query);
final List<Map<String, Object>> displayResults = prepareResultsforDisplay(scoredResults);
// Use the UI thread to display the results
runOnUiThread(new Runnable() {
@Override
public void run() {
arrayAdapter.clear();
ApiAdapterFactory.getApiAdapter().addAllToArrayAdapter(arrayAdapter, displayResults);
}
});
// Save the query as a suggestion for the future
searchRecentSuggestions.saveRecentQuery(query.textQuery, null);
}
/**
* Prepares the result for display.
*
* @param scoredResults a list of score results
* @return a list of result maps
*/
private List<Map<String, Object>> prepareResultsforDisplay(
Collection<ScoredResult> scoredResults) {
ArrayList<Map<String, Object>> output = new ArrayList<Map<String, Object>>(scoredResults
.size());
for (ScoredResult result : scoredResults) {
Map<String, Object> resultMap = new HashMap<String, Object>();
if (result.track != null) {
prepareTrackForDisplay(result.track, resultMap);
} else {
prepareMarkerForDisplay(result.waypoint, resultMap);
}
output.add(resultMap);
}
return output;
}
/**
* Prepares a marker for display by filling in a result map.
*
* @param waypoint the marker
* @param resultMap the result map
*/
private void prepareMarkerForDisplay(Waypoint waypoint, Map<String, Object> resultMap) {
/*
* TODO: It may be more appropriate to obtain the track name as a join in
* the retrieval phase of the search.
*/
String trackName = null;
long trackId = waypoint.getTrackId();
if (trackId != -1L) {
Track track = myTracksProviderUtils.getTrack(trackId);
if (track != null) {
trackName = track.getName();
}
}
boolean statistics = waypoint.getType() == Waypoint.TYPE_STATISTICS;
resultMap.put(NAME_FIELD, waypoint.getName());
resultMap.put(ICON_FIELD, statistics ? R.drawable.yellow_pushpin : R.drawable.blue_pushpin);
resultMap.put(CATEGORY_FIELD, statistics ? null : waypoint.getCategory());
long time = waypoint.getLocation().getTime();
String startTime = StringUtils.formatDateTime(this, time);
resultMap.put(START_TIME_FIELD, time == 0 || startTime.equals(trackName) ? null : startTime);
// Display the marker's track name in the total time field
resultMap.put(TOTAL_TIME_FIELD, trackName == null ? null
: getString(R.string.search_list_marker_track_location, trackName));
resultMap.put(TOTAL_DISTANCE_FIELD, null);
resultMap.put(DESCRIPTION_FIELD, statistics ? null : waypoint.getDescription());
resultMap.put(TRACK_ID_FIELD, waypoint.getTrackId());
resultMap.put(MARKER_ID_FIELD, waypoint.getId());
}
/**
* Prepares a track for display by filling in a result map.
*
* @param track the track
* @param resultMap the result map
*/
private void prepareTrackForDisplay(Track track, Map<String, Object> resultMap) {
boolean isRecording = track.getId() == recordingTrackId;
TripStatistics tripStatitics = track.getStatistics();
resultMap.put(NAME_FIELD, track.getName());
resultMap.put(ICON_FIELD, isRecording ? R.drawable.menu_record_track : R.drawable.track);
resultMap.put(CATEGORY_FIELD, track.getCategory());
resultMap.put(TOTAL_TIME_FIELD, isRecording ? null : StringUtils.formatElapsedTime(
tripStatitics.getTotalTime()));
resultMap.put(TOTAL_DISTANCE_FIELD, isRecording ? null : StringUtils.formatDistance(
this, tripStatitics.getTotalDistance(), metricUnits));
String startTime = StringUtils.formatDateTime(this, tripStatitics.getStartTime());
if (startTime.equals(track.getName())) {
startTime = null;
}
resultMap.put(START_TIME_FIELD, startTime);
resultMap.put(DESCRIPTION_FIELD, track.getDescription());
resultMap.put(TRACK_ID_FIELD, track.getId());
resultMap.put(MARKER_ID_FIELD, null);
}
}
@@ -27,7 +27,6 @@ import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
import com.google.protobuf.InvalidProtocolBufferException;
import android.app.Activity;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
@@ -41,12 +40,10 @@ import java.util.TimerTask;
*
* @author Sandor Dornbush
*/
public class SensorStateActivity extends Activity {
public class SensorStateActivity extends AbstractMyTracksActivity {
private static final long REFRESH_PERIOD_MS = 250;
private final StatsUtilities utils;
/**
* This timer periodically invokes the refresh timer task.
*/
@@ -91,11 +88,6 @@ public class SensorStateActivity extends Activity {
*/
private boolean isVisible = false;
public SensorStateActivity() {
utils = new StatsUtilities(this);
Log.w(TAG, "SensorStateActivity()");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -239,18 +231,18 @@ public class SensorStateActivity extends Activity {
}
private void updateSensorData(Sensor.SensorDataSet sds) {
if (sds == null) {
utils.setUnknown(R.id.sensor_state_last_sensor_time);
utils.setUnknown(R.id.sensor_state_power);
utils.setUnknown(R.id.sensor_state_cadence);
utils.setUnknown(R.id.sensor_state_battery);
} else {
((TextView) findViewById(R.id.sensor_state_last_sensor_time)).setText(getLastSensorTime(sds));
((TextView) findViewById(R.id.sensor_state_power)).setText(getPower(sds));
((TextView) findViewById(R.id.sensor_state_cadence)).setText(getCadence(sds));
((TextView) findViewById(R.id.sensor_state_heart_rate)).setText(getHeartRate(sds));
((TextView) findViewById(R.id.sensor_state_battery)).setText(getBattery(sds));
}
String lastSensorTime = sds == null ? getString(R.string.value_unknown)
: getLastSensorTime(sds);
String power = sds == null ? getString(R.string.value_unknown) : getPower(sds);
String cadence = sds == null ? getString(R.string.value_unknown) : getCadence(sds);
String heartRate = sds == null ? getString(R.string.value_unknown) : getHeartRate(sds);
String battery = sds == null ? getString(R.string.value_unknown) : getBattery(sds);
((TextView) findViewById(R.id.sensor_state_last_sensor_time)).setText(lastSensorTime);
((TextView) findViewById(R.id.sensor_state_power)).setText(power);
((TextView) findViewById(R.id.sensor_state_cadence)).setText(cadence);
((TextView) findViewById(R.id.sensor_state_heart_rate)).setText(heartRate);
((TextView) findViewById(R.id.sensor_state_battery)).setText(battery);
}
/**
@@ -325,8 +317,7 @@ public class SensorStateActivity extends Activity {
String value;
if (sds.hasBatteryLevel() && sds.getBatteryLevel().hasValue()
&& sds.getBatteryLevel().getState() == Sensor.SensorState.SENDING) {
String format = getString(R.string.value_integer_percent);
value = String.format(format, sds.getBatteryLevel().getValue());
value = getString(R.string.value_integer_percent, sds.getBatteryLevel().getValue());
} else {
value = SensorUtils.getStateAsString(
sds.hasBatteryLevel() ? sds.getBatteryLevel().getState() : Sensor.SensorState.NONE, this);
@@ -1,720 +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 static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.io.backup.BackupActivity;
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
import com.google.android.apps.mytracks.io.backup.RestoreChooserActivity;
import com.google.android.apps.mytracks.services.sensors.ant.AntUtils;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.BluetoothDeviceUtils;
import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
import android.app.Dialog;
import android.bluetooth.BluetoothAdapter;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.provider.Settings;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* An activity that let's the user see and edit the settings.
*
* @author Leif Hendrik Wilden
* @author Rodrigo Damazio
*/
public class SettingsActivity extends PreferenceActivity {
private static final int DIALOG_CONFIRM_RESET_ID = 0;
private static final int DIALOG_CONFIRM_ACCESS_ID = 1;
private static final int DIALOG_CONFIRM_RESTORE_ID = 2;
// Value when the task frequency is off.
private static final String TASK_FREQUENCY_OFF = "0";
// Value when the recording interval is 'Adapt battery life'.
private static final String RECORDING_INTERVAL_ADAPT_BATTERY_LIFE = "-2";
// Value when the recording interval is 'Adapt accuracy'.
private static final String RECORDING_INTERVAL_ADAPT_ACCURACY = "-1";
// Value for the recommended recording interval.
private static final String RECORDING_INTERVAL_RECOMMENDED = "0";
// Value when the auto resume timeout is never.
private static final String AUTO_RESUME_TIMEOUT_NEVER = "0";
// Value when the auto resume timeout is always.
private static final String AUTO_RESUME_TIMEOUT_ALWAYS = "-1";
// Value for the recommended recording distance.
private static final String RECORDING_DISTANCE_RECOMMENDED = "5";
// Value for the recommended track distance.
private static final String TRACK_DISTANCE_RECOMMENDED = "200";
// Value for the recommended GPS accuracy.
private static final String GPS_ACCURACY_RECOMMENDED = "200";
// Value when the GPS accuracy is for excellent GPS signal.
private static final String GPS_ACCURACY_EXCELLENT = "10";
// Value when the GPS accuracy is for poor GPS signal.
private static final String GPS_ACCURACY_POOR = "5000";
private BackupPreferencesListener backupListener;
private SharedPreferences preferences;
/** Called when the activity is first created. */
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
// The volume we want to control is the Text-To-Speech volume
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
// Tell it where to read/write preferences
PreferenceManager preferenceManager = getPreferenceManager();
preferenceManager.setSharedPreferencesName(Constants.SETTINGS_NAME);
preferenceManager.setSharedPreferencesMode(0);
// Set up automatic preferences backup
backupListener = ApiAdapterFactory.getApiAdapter().getBackupPreferencesListener(this);
preferences = preferenceManager.getSharedPreferences();
preferences.registerOnSharedPreferenceChangeListener(backupListener);
// Load the preferences to be displayed
addPreferencesFromResource(R.xml.preferences);
setRecordingIntervalOptions();
setAutoResumeTimeoutOptions();
// Hook up switching of displayed list entries between metric and imperial
// units
CheckBoxPreference metricUnitsPreference =
(CheckBoxPreference) findPreference(
getString(R.string.metric_units_key));
metricUnitsPreference.setOnPreferenceChangeListener(
new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference,
Object newValue) {
boolean isMetric = (Boolean) newValue;
updateDisplayOptions(isMetric);
return true;
}
});
updateDisplayOptions(metricUnitsPreference.isChecked());
customizeSensorOptionsPreferences();
customizeTrackColorModePreferences();
// Hook up action for resetting all settings
Preference resetPreference = findPreference(getString(R.string.reset_key));
resetPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference arg0) {
showDialog(DIALOG_CONFIRM_RESET_ID);
return true;
}
});
// Add a confirmation dialog for the 'Allow access' preference.
CheckBoxPreference allowAccessPreference = (CheckBoxPreference) findPreference(
getString(R.string.allow_access_key));
allowAccessPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if ((Boolean) newValue) {
showDialog(DIALOG_CONFIRM_ACCESS_ID);
return false;
} else {
return true;
}
}
});
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DIALOG_CONFIRM_RESET_ID:
return DialogUtils.createConfirmationDialog(
this, R.string.settings_reset_confirm_message, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int button) {
onResetPreferencesConfirmed();
}
});
case DIALOG_CONFIRM_ACCESS_ID:
return DialogUtils.createConfirmationDialog(this,
R.string.settings_sharing_allow_access_confirm_message,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int button) {
CheckBoxPreference pref = (CheckBoxPreference) findPreference(
getString(R.string.allow_access_key));
pref.setChecked(true);
}
});
case DIALOG_CONFIRM_RESTORE_ID:
return DialogUtils.createConfirmationDialog(this,
R.string.settings_backup_restore_confirm_message,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startActivity(new Intent(SettingsActivity.this, RestoreChooserActivity.class));
}
});
default:
return null;
}
}
/**
* Sets the display options for the 'Time between points' option.
*/
private void setRecordingIntervalOptions() {
String[] values = getResources().getStringArray(R.array.recording_interval_values);
String[] options = new String[values.length];
for (int i = 0; i < values.length; i++) {
if (values[i].equals(RECORDING_INTERVAL_ADAPT_BATTERY_LIFE)) {
options[i] = getString(R.string.value_adapt_battery_life);
} else if (values[i].equals(RECORDING_INTERVAL_ADAPT_ACCURACY)) {
options[i] = getString(R.string.value_adapt_accuracy);
} else if (values[i].equals(RECORDING_INTERVAL_RECOMMENDED)) {
options[i] = getString(R.string.value_smallest_recommended);
} else {
int value = Integer.parseInt(values[i]);
String format;
if (value < 60) {
format = getString(R.string.value_integer_second);
} else {
value = value / 60;
format = getString(R.string.value_integer_minute);
}
options[i] = String.format(format, value);
}
}
ListPreference list = (ListPreference) findPreference(
getString(R.string.min_recording_interval_key));
list.setEntries(options);
}
/**
* Sets the display options for the 'Auto-resume timeout' option.
*/
private void setAutoResumeTimeoutOptions() {
String[] values = getResources().getStringArray(R.array.recording_auto_resume_timeout_values);
String[] options = new String[values.length];
for (int i = 0; i < values.length; i++) {
if (values[i].equals(AUTO_RESUME_TIMEOUT_NEVER)) {
options[i] = getString(R.string.value_never);
} else if (values[i].equals(AUTO_RESUME_TIMEOUT_ALWAYS)) {
options[i] = getString(R.string.value_always);
} else {
int value = Integer.parseInt(values[i]);
String format = getString(R.string.value_integer_minute);
options[i] = String.format(format, value);
}
}
ListPreference list = (ListPreference) findPreference(
getString(R.string.auto_resume_track_timeout_key));
list.setEntries(options);
}
private void customizeSensorOptionsPreferences() {
ListPreference sensorTypePreference =
(ListPreference) findPreference(getString(R.string.sensor_type_key));
sensorTypePreference.setOnPreferenceChangeListener(
new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference,
Object newValue) {
updateSensorSettings((String) newValue);
return true;
}
});
updateSensorSettings(sensorTypePreference.getValue());
if (!AntUtils.hasAntSupport(this)) {
// The sensor options screen has a few ANT-specific options which we
// need to remove. First, we need to remove the ANT sensor types.
// Second, we need to remove the ANT unpairing options.
Set<Integer> toRemove = new HashSet<Integer>();
String[] antValues = getResources().getStringArray(R.array.sensor_type_ant_values);
for (String antValue : antValues) {
toRemove.add(sensorTypePreference.findIndexOfValue(antValue));
}
CharSequence[] entries = sensorTypePreference.getEntries();
CharSequence[] entryValues = sensorTypePreference.getEntryValues();
CharSequence[] filteredEntries = new CharSequence[entries.length - toRemove.size()];
CharSequence[] filteredEntryValues = new CharSequence[filteredEntries.length];
for (int i = 0, last = 0; i < entries.length; i++) {
if (!toRemove.contains(i)) {
filteredEntries[last] = entries[i];
filteredEntryValues[last++] = entryValues[i];
}
}
sensorTypePreference.setEntries(filteredEntries);
sensorTypePreference.setEntryValues(filteredEntryValues);
PreferenceScreen sensorOptionsScreen =
(PreferenceScreen) findPreference(getString(R.string.sensor_options_key));
sensorOptionsScreen.removePreference(findPreference(getString(R.string.ant_options_key)));
}
}
private void customizeTrackColorModePreferences() {
ListPreference trackColorModePreference =
(ListPreference) findPreference(getString(R.string.track_color_mode_key));
trackColorModePreference.setOnPreferenceChangeListener(
new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference,
Object newValue) {
updateTrackColorModeSettings((String) newValue);
return true;
}
});
updateTrackColorModeSettings(trackColorModePreference.getValue());
setTrackColorModePreferenceListeners();
PreferenceCategory speedOptionsCategory = (PreferenceCategory) findPreference(
getString(R.string.track_color_mode_fixed_speed_options_key));
speedOptionsCategory.removePreference(
findPreference(getString(R.string.track_color_mode_fixed_speed_slow_key)));
speedOptionsCategory.removePreference(
findPreference(getString(R.string.track_color_mode_fixed_speed_medium_key)));
}
@Override
protected void onResume() {
super.onResume();
configureBluetoothPreferences();
Preference backupNowPreference =
findPreference(getString(R.string.backup_to_sd_key));
Preference restoreNowPreference =
findPreference(getString(R.string.restore_from_sd_key));
Preference resetPreference = findPreference(getString(R.string.reset_key));
// If recording, disable backup/restore/reset
// (we don't want to get to inconsistent states)
boolean recording = PreferencesUtils.getRecordingTrackId(this) != -1;
backupNowPreference.setEnabled(!recording);
restoreNowPreference.setEnabled(!recording);
resetPreference.setEnabled(!recording);
backupNowPreference.setSummary(
recording ? R.string.settings_not_while_recording
: R.string.settings_backup_now_summary);
restoreNowPreference.setSummary(
recording ? R.string.settings_not_while_recording
: R.string.settings_backup_restore_summary);
resetPreference.setSummary(
recording ? R.string.settings_not_while_recording
: R.string.settings_reset_summary);
// Add actions to the backup preferences
backupNowPreference.setOnPreferenceClickListener(
new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
startActivity(new Intent(SettingsActivity.this, BackupActivity.class));
return true;
}
});
restoreNowPreference.setOnPreferenceClickListener(
new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
showDialog(DIALOG_CONFIRM_RESTORE_ID);
return true;
}
});
}
@Override
protected void onDestroy() {
getPreferenceManager().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(backupListener);
super.onPause();
}
private void updateSensorSettings(String sensorType) {
boolean usesBluetooth =
getString(R.string.sensor_type_value_zephyr).equals(sensorType)
|| getString(R.string.sensor_type_value_polar).equals(sensorType);
findPreference(
getString(R.string.bluetooth_sensor_key)).setEnabled(usesBluetooth);
findPreference(
getString(R.string.bluetooth_pairing_key)).setEnabled(usesBluetooth);
// Update the ANT+ sensors.
// TODO: Only enable on phones that have ANT+.
Preference antHrm = findPreference(getString(R.string.ant_heart_rate_sensor_id_key));
Preference antSrm = findPreference(getString(R.string.ant_srm_bridge_sensor_id_key));
if (antHrm != null && antSrm != null) {
antHrm
.setEnabled(getString(R.string.sensor_type_value_ant).equals(sensorType));
antSrm
.setEnabled(getString(R.string.sensor_type_value_srm_ant_bridge).equals(sensorType));
}
}
private void updateTrackColorModeSettings(String trackColorMode) {
boolean usesFixedSpeed =
trackColorMode.equals(getString(R.string.display_track_color_value_fixed));
boolean usesDynamicSpeed =
trackColorMode.equals(getString(R.string.display_track_color_value_dynamic));
findPreference(getString(R.string.track_color_mode_fixed_speed_slow_display_key))
.setEnabled(usesFixedSpeed);
findPreference(getString(R.string.track_color_mode_fixed_speed_medium_display_key))
.setEnabled(usesFixedSpeed);
findPreference(getString(R.string.track_color_mode_dynamic_speed_variation_key))
.setEnabled(usesDynamicSpeed);
}
/**
* Updates display options that depends on the preferred distance units, metric or imperial.
*
* @param isMetric true to use metric units, false to use imperial
*/
private void updateDisplayOptions(boolean isMetric) {
setTaskOptions(isMetric, R.string.announcement_frequency_key);
setTaskOptions(isMetric, R.string.split_frequency_key);
setRecordingDistanceOptions(isMetric, R.string.min_recording_distance_key);
setTrackDistanceOptions(isMetric, R.string.max_recording_distance_key);
setGpsAccuracyOptions(isMetric, R.string.min_required_accuracy_key);
}
/**
* Sets the display options for a periodic task.
*/
private void setTaskOptions(boolean isMetric, int listId) {
String[] values = getResources().getStringArray(R.array.recording_task_frequency_values);
String[] options = new String[values.length];
for (int i = 0; i < values.length; i++) {
if (values[i].equals(TASK_FREQUENCY_OFF)) {
options[i] = getString(R.string.value_off);
} else if (values[i].startsWith("-")) {
int value = Integer.parseInt(values[i].substring(1));
int stringId = isMetric ? R.string.value_integer_kilometer : R.string.value_integer_mile;
String format = getString(stringId);
options[i] = String.format(format, value);
} else {
int value = Integer.parseInt(values[i]);
String format = getString(R.string.value_integer_minute);
options[i] = String.format(format, value);
}
}
ListPreference list = (ListPreference) findPreference(getString(listId));
list.setEntries(options);
}
/**
* Sets the display options for 'Distance between points' option.
*/
private void setRecordingDistanceOptions(boolean isMetric, int listId) {
String[] values = getResources().getStringArray(R.array.recording_distance_values);
String[] options = new String[values.length];
for (int i = 0; i < values.length; i++) {
int value = Integer.parseInt(values[i]);
if (!isMetric) {
value = (int) (value * UnitConversions.M_TO_FT);
}
String format;
if (values[i].equals(RECORDING_DISTANCE_RECOMMENDED)) {
int stringId = isMetric ? R.string.value_integer_meter_recommended
: R.string.value_integer_feet_recommended;
format = getString(stringId);
} else {
int stringId = isMetric ? R.string.value_integer_meter : R.string.value_integer_feet;
format = getString(stringId);
}
options[i] = String.format(format, value);
}
ListPreference list = (ListPreference) findPreference(getString(listId));
list.setEntries(options);
}
/**
* Sets the display options for 'Distance between Tracks'.
*/
private void setTrackDistanceOptions(boolean isMetric, int listId) {
String[] values = getResources().getStringArray(R.array.recording_track_distance_values);
String[] options = new String[values.length];
for (int i = 0; i < values.length; i++) {
int value = Integer.parseInt(values[i]);
String format;
if (isMetric) {
int stringId = values[i].equals(TRACK_DISTANCE_RECOMMENDED)
? R.string.value_integer_meter_recommended : R.string.value_integer_meter;
format = getString(stringId);
options[i] = String.format(format, value);
} else {
value = (int) (value * UnitConversions.M_TO_FT);
if (value < 2000) {
int stringId = values[i].equals(TRACK_DISTANCE_RECOMMENDED)
? R.string.value_integer_feet_recommended : R.string.value_integer_feet;
format = getString(stringId);
options[i] = String.format(format, value);
} else {
double mile = value * UnitConversions.FT_TO_MI;
format = getString(R.string.value_float_mile);
options[i] = String.format(format, mile);
}
}
}
ListPreference list = (ListPreference) findPreference(getString(listId));
list.setEntries(options);
}
/**
* Sets the display options for 'GPS accuracy'.
*/
private void setGpsAccuracyOptions(boolean isMetric, int listId) {
String[] values = getResources().getStringArray(R.array.recording_gps_accuracy_values);
String[] options = new String[values.length];
for (int i = 0; i < values.length; i++) {
int value = Integer.parseInt(values[i]);
String format;
if (isMetric) {
if (values[i].equals(GPS_ACCURACY_RECOMMENDED)) {
format = getString(R.string.value_integer_meter_recommended);
} else if (values[i].equals(GPS_ACCURACY_EXCELLENT)) {
format = getString(R.string.value_integer_meter_excellent_gps);
} else if (values[i].equals(GPS_ACCURACY_POOR)) {
format = getString(R.string.value_integer_meter_poor_gps);
} else {
format = getString(R.string.value_integer_meter);
}
options[i] = String.format(format, value);
} else {
value = (int) (value * UnitConversions.M_TO_FT);
if (value < 2000) {
if (values[i].equals(GPS_ACCURACY_RECOMMENDED)) {
format = getString(R.string.value_integer_feet_recommended);
} else if (values[i].equals(GPS_ACCURACY_EXCELLENT)) {
format = getString(R.string.value_integer_feet_excellent_gps);
} else {
format = getString(R.string.value_integer_feet);
}
options[i] = String.format(format, value);
} else {
double mile = value * UnitConversions.FT_TO_MI;
if (values[i].equals(GPS_ACCURACY_POOR)) {
format = getString(R.string.value_float_mile_poor_gps);
} else {
format = getString(R.string.value_float_mile);
}
options[i] = String.format(format, mile);
}
}
}
ListPreference list = (ListPreference) findPreference(getString(listId));
list.setEntries(options);
}
/**
* Configures preference actions related to bluetooth.
*/
private void configureBluetoothPreferences() {
// Populate the list of bluetooth devices
populateBluetoothDeviceList();
// Make the pair devices preference go to the system preferences
findPreference(getString(R.string.bluetooth_pairing_key)).setOnPreferenceClickListener(
new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
Intent settingsIntent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
startActivity(settingsIntent);
return false;
}
});
}
/**
* Populates the list preference with all available bluetooth devices.
*/
private void populateBluetoothDeviceList() {
// Build the list of entries and their values
List<String> entries = new ArrayList<String>();
List<String> entryValues = new ArrayList<String>();
// The actual devices
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter != null) {
BluetoothDeviceUtils.populateDeviceLists(bluetoothAdapter, entries, entryValues);
}
CharSequence[] entriesArray = entries.toArray(new CharSequence[entries.size()]);
CharSequence[] entryValuesArray = entryValues.toArray(new CharSequence[entryValues.size()]);
ListPreference devicesPreference =
(ListPreference) findPreference(getString(R.string.bluetooth_sensor_key));
devicesPreference.setEntryValues(entryValuesArray);
devicesPreference.setEntries(entriesArray);
}
/** Callback for when user confirms resetting all settings. */
private void onResetPreferencesConfirmed() {
// Change preferences in a separate thread.
new Thread() {
@Override
public void run() {
Log.i(TAG, "Resetting all settings");
// Actually wipe preferences (and save synchronously).
preferences.edit().clear().commit();
// Give UI feedback in the UI thread.
runOnUiThread(new Runnable() {
@Override
public void run() {
// Give feedback to the user.
Toast.makeText(
SettingsActivity.this,
R.string.settings_reset_done,
Toast.LENGTH_SHORT).show();
// Restart the settings activity so all changes are loaded.
Intent intent = getIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
});
}
}.start();
}
/**
* Set the given edit text preference text.
* If the units are not metric convert the value before displaying.
*/
private void viewTrackColorModeSettings(EditTextPreference preference, int id) {
CheckBoxPreference metricUnitsPreference = (CheckBoxPreference) findPreference(
getString(R.string.metric_units_key));
if(metricUnitsPreference.isChecked()) {
return;
}
// Convert miles/h to km/h
SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
String metricspeed = prefs.getString(getString(id), null);
int englishspeed;
try {
englishspeed = (int) (Double.parseDouble(metricspeed) * UnitConversions.KM_TO_MI);
} catch (NumberFormatException e) {
englishspeed = 0;
}
preference.getEditText().setText(String.valueOf(englishspeed));
}
/**
* Saves the given edit text preference value.
* If the units are not metric convert the value before saving.
*/
private void validateTrackColorModeSettings(String newValue, int id) {
CheckBoxPreference metricUnitsPreference = (CheckBoxPreference) findPreference(
getString(R.string.metric_units_key));
String metricspeed;
if(!metricUnitsPreference.isChecked()) {
// Convert miles/h to km/h
try {
metricspeed = String.valueOf(
(int) (Double.parseDouble(newValue) * UnitConversions.MI_TO_KM));
} catch (NumberFormatException e) {
metricspeed = "0";
}
} else {
metricspeed = newValue;
}
SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
Editor editor = prefs.edit();
editor.putString(getString(id), metricspeed);
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
}
/**
* Sets the TrackColorMode preference listeners.
*/
private void setTrackColorModePreferenceListeners() {
setTrackColorModePreferenceListener(R.string.track_color_mode_fixed_speed_slow_display_key,
R.string.track_color_mode_fixed_speed_slow_key);
setTrackColorModePreferenceListener(R.string.track_color_mode_fixed_speed_medium_display_key,
R.string.track_color_mode_fixed_speed_medium_key);
}
/**
* Sets a TrackColorMode preference listener.
*/
private void setTrackColorModePreferenceListener(int displayKey, final int metricKey) {
EditTextPreference trackColorModePreference =
(EditTextPreference) findPreference(getString(displayKey));
trackColorModePreference.setOnPreferenceChangeListener(
new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference,
Object newValue) {
validateTrackColorModeSettings((String) newValue, metricKey);
return true;
}
});
trackColorModePreference.setOnPreferenceClickListener(
new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
viewTrackColorModeSettings((EditTextPreference) preference, metricKey);
return true;
}
});
}
}
@@ -1,270 +0,0 @@
/*
* 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
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.StatsUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.util.Log;
import android.widget.TextView;
import java.text.NumberFormat;
/**
* Various utility functions for views that display statistics information.
*
* @deprecated use {@link StatsUtils}.
*
* @author Sandor Dornbush
*/
public class StatsUtilities {
private final Activity activity;
private static final NumberFormat LAT_LONG_FORMAT = NumberFormat.getNumberInstance();
private static final NumberFormat ALTITUDE_FORMAT = NumberFormat.getIntegerInstance();
private static final NumberFormat SPEED_FORMAT = NumberFormat.getNumberInstance();
private static final NumberFormat GRADE_FORMAT = NumberFormat.getPercentInstance();
static {
LAT_LONG_FORMAT.setMaximumFractionDigits(5);
LAT_LONG_FORMAT.setMinimumFractionDigits(5);
SPEED_FORMAT.setMaximumFractionDigits(2);
SPEED_FORMAT.setMinimumFractionDigits(2);
GRADE_FORMAT.setMaximumFractionDigits(1);
GRADE_FORMAT.setMinimumFractionDigits(1);
}
/**
* True if distances should be displayed in metric units (from shared
* preferences).
*/
private boolean metricUnits = true;
/**
* True - report speed
* False - report pace
*/
private boolean reportSpeed = true;
public StatsUtilities(Activity a) {
this.activity = a;
}
public boolean isMetricUnits() {
return metricUnits;
}
public void setMetricUnits(boolean metricUnits) {
this.metricUnits = metricUnits;
}
public boolean isReportSpeed() {
return reportSpeed;
}
public void setReportSpeed(boolean reportSpeed) {
this.reportSpeed = reportSpeed;
}
public void setUnknown(int id) {
((TextView) activity.findViewById(id)).setText(R.string.value_unknown);
}
public void setText(int id, double d, NumberFormat format) {
if (!Double.isNaN(d) && !Double.isInfinite(d)) {
setText(id, format.format(d));
} else {
setUnknown(id);
}
}
public void setText(int id, String s) {
int lengthLimit = 8;
String displayString = s.length() > lengthLimit
? s.substring(0, lengthLimit - 3) + "..."
: s;
((TextView) activity.findViewById(id)).setText(displayString);
}
public void setLatLong(int id, double d) {
TextView msgTextView = (TextView) activity.findViewById(id);
msgTextView.setText(LAT_LONG_FORMAT.format(d));
}
public void setAltitude(int id, double d) {
setText(id, (metricUnits ? d : (d * UnitConversions.M_TO_FT)),
ALTITUDE_FORMAT);
}
public void setDistance(int id, double d) {
setText(id, (metricUnits ? d : (d * UnitConversions.KM_TO_MI)),
SPEED_FORMAT);
}
public void setSpeed(int id, double d) {
if (d == 0) {
setUnknown(id);
return;
}
double speed = metricUnits ? d : d * UnitConversions.KM_TO_MI;
if (reportSpeed) {
setText(id, speed, SPEED_FORMAT);
} else {
// Format as milliseconds per unit
long pace = (long) (3600000.0 / speed);
setTime(id, pace);
}
}
public void setAltitudeUnits(int unitLabelId) {
TextView unitTextView = (TextView) activity.findViewById(unitLabelId);
unitTextView.setText(metricUnits ? R.string.unit_meter : R.string.unit_feet);
}
public void setDistanceUnits(int unitLabelId) {
TextView unitTextView = (TextView) activity.findViewById(unitLabelId);
unitTextView.setText(metricUnits ? R.string.unit_kilometer : R.string.unit_mile);
}
public void setSpeedUnits(int unitLabelId, int unitLabelBottomId) {
TextView unitTextView = (TextView) activity.findViewById(unitLabelId);
unitTextView.setText(reportSpeed
? (metricUnits ? R.string.unit_kilometer : R.string.unit_mile)
: R.string.unit_minute);
unitTextView = (TextView) activity.findViewById(unitLabelBottomId);
unitTextView.setText(reportSpeed
? R.string.unit_hour
: (metricUnits ? R.string.unit_kilometer : R.string.unit_mile));
}
public void setTime(int id, long l) {
setText(id, StringUtils.formatElapsedTime(l));
}
public void setGrade(int id, double d) {
setText(id, d, GRADE_FORMAT);
}
/**
* Updates the unit fields.
*/
public void updateUnits() {
setSpeedUnits(R.id.speed_unit_label_top, R.id.speed_unit_label_bottom);
updateWaypointUnits();
}
/**
* Updates the units fields used by waypoints.
*/
public void updateWaypointUnits() {
setSpeedUnits(R.id.average_moving_speed_unit_label_top,
R.id.average_moving_speed_unit_label_bottom);
setSpeedUnits(R.id.average_speed_unit_label_top,
R.id.average_speed_unit_label_bottom);
setDistanceUnits(R.id.total_distance_unit_label);
setSpeedUnits(R.id.max_speed_unit_label_top,
R.id.max_speed_unit_label_bottom);
setAltitudeUnits(R.id.elevation_unit_label);
setAltitudeUnits(R.id.elevation_gain_unit_label);
setAltitudeUnits(R.id.min_elevation_unit_label);
setAltitudeUnits(R.id.max_elevation_unit_label);
}
/**
* Sets all fields to "-" (unknown).
*/
public void setAllToUnknown() {
// "Instant" values:
setUnknown(R.id.elevation_register);
setUnknown(R.id.latitude_register);
setUnknown(R.id.longitude_register);
setUnknown(R.id.speed_register);
// Values from provider:
setUnknown(R.id.total_time_register);
setUnknown(R.id.moving_time_register);
setUnknown(R.id.total_distance_register);
setUnknown(R.id.average_speed_register);
setUnknown(R.id.average_moving_speed_register);
setUnknown(R.id.max_speed_register);
setUnknown(R.id.min_elevation_register);
setUnknown(R.id.max_elevation_register);
setUnknown(R.id.elevation_gain_register);
setUnknown(R.id.min_grade_register);
setUnknown(R.id.max_grade_register);
}
public void setAllStats(long movingTime, double totalDistance,
double averageSpeed, double averageMovingSpeed, double maxSpeed,
double minElevation, double maxElevation, double elevationGain,
double minGrade, double maxGrade) {
setTime(R.id.moving_time_register, movingTime);
setDistance(R.id.total_distance_register, totalDistance * UnitConversions.M_TO_KM);
setSpeed(R.id.average_speed_register, averageSpeed * UnitConversions.MS_TO_KMH);
setSpeed(R.id.average_moving_speed_register, averageMovingSpeed * UnitConversions.MS_TO_KMH);
setSpeed(R.id.max_speed_register, maxSpeed * UnitConversions.MS_TO_KMH);
setAltitude(R.id.min_elevation_register, minElevation);
setAltitude(R.id.max_elevation_register, maxElevation);
setAltitude(R.id.elevation_gain_register, elevationGain);
setGrade(R.id.min_grade_register, minGrade);
setGrade(R.id.max_grade_register, maxGrade);
}
public void setAllStats(TripStatistics stats) {
setTime(R.id.moving_time_register, stats.getMovingTime());
setDistance(R.id.total_distance_register, stats.getTotalDistance() * UnitConversions.M_TO_KM);
setSpeed(R.id.average_speed_register, stats.getAverageSpeed() * UnitConversions.MS_TO_KMH);
setSpeed(R.id.average_moving_speed_register,
stats.getAverageMovingSpeed() * UnitConversions.MS_TO_KMH);
setSpeed(R.id.max_speed_register, stats.getMaxSpeed() * UnitConversions.MS_TO_KMH);
setAltitude(R.id.min_elevation_register, stats.getMinElevation());
setAltitude(R.id.max_elevation_register, stats.getMaxElevation());
setAltitude(R.id.elevation_gain_register, stats.getTotalElevationGain());
setGrade(R.id.min_grade_register, stats.getMinGrade());
setGrade(R.id.max_grade_register, stats.getMaxGrade());
setTime(R.id.total_time_register, stats.getTotalTime());
}
public void setSpeedLabel(int id, int speedString, int paceString) {
Log.w(Constants.TAG, "Setting view " + id +
" to " + reportSpeed +
" speed: " + speedString +
" pace: " + paceString);
TextView tv = ((TextView) activity.findViewById(id));
if (tv != null) {
tv.setText(reportSpeed ? speedString : paceString);
} else {
Log.w(Constants.TAG, "Could not find id: " + id);
}
}
public void setSpeedLabels() {
setSpeedLabel(R.id.average_speed_label,
R.string.stat_average_speed,
R.string.stat_average_pace);
setSpeedLabel(R.id.average_moving_speed_label,
R.string.stat_average_moving_speed,
R.string.stat_average_moving_pace);
setSpeedLabel(R.id.max_speed_label,
R.string.stat_max_speed,
R.string.stat_fastest_pace);
}
}
@@ -16,28 +16,25 @@
package com.google.android.apps.mytracks;
import static com.google.android.apps.mytracks.Constants.CHART_TAB_TAG;
import static com.google.android.apps.mytracks.Constants.MAP_TAB_TAG;
import static com.google.android.apps.mytracks.Constants.STATS_TAB_TAG;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.TrackDataHub;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.fragments.ChartFragment;
import com.google.android.apps.mytracks.fragments.ChartSettingsDialogFragment;
import com.google.android.apps.mytracks.fragments.DeleteOneTrackDialogFragment;
import com.google.android.apps.mytracks.fragments.InstallEarthDialogFragment;
import com.google.android.apps.mytracks.fragments.MapFragment;
import com.google.android.apps.mytracks.fragments.MarkerAddDialogFragment;
import com.google.android.apps.mytracks.fragments.StatsFragment;
import com.google.android.apps.mytracks.io.file.SaveActivity;
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.io.sendtogoogle.UploadServiceChooserActivity;
import com.google.android.apps.mytracks.services.ITrackRecordingService;
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
import com.google.android.apps.mytracks.settings.SettingsActivity;
import com.google.android.apps.mytracks.util.AnalyticsUtils;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
import com.google.android.maps.mytracks.R;
@@ -50,9 +47,6 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.RemoteException;
import android.speech.tts.TextToSpeech;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -60,7 +54,6 @@ import android.view.MotionEvent;
import android.view.View;
import android.widget.TabHost;
import android.widget.TabHost.TabSpec;
import android.widget.Toast;
import java.util.List;
@@ -70,7 +63,7 @@ import java.util.List;
* @author Leif Hendrik Wilden
* @author Rodrigo Damazio
*/
public class TrackDetailActivity extends FragmentActivity {
public class TrackDetailActivity extends AbstractMyTracksActivity {
public static final String EXTRA_TRACK_ID = "track_id";
public static final String EXTRA_MARKER_ID = "marker_id";
@@ -78,7 +71,6 @@ public class TrackDetailActivity extends FragmentActivity {
private static final String TAG = TrackDetailActivity.class.getSimpleName();
private static final String CURRENT_TAG_KEY = "tab";
private SharedPreferences sharedPreferences;
private TrackDataHub trackDataHub;
private TrackRecordingServiceConnection trackRecordingServiceConnection;
private TabHost tabHost;
@@ -100,16 +92,17 @@ public class TrackDetailActivity extends FragmentActivity {
* Note that sharedPreferenceChangeListener cannot be an anonymous inner
* class. Anonymous inner class will get garbage collected.
*/
private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener =
new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
// Note that key can be null
if (PreferencesUtils.getRecordingTrackIdKey(TrackDetailActivity.this).equals(key)) {
updateMenu();
}
}
};
private final OnSharedPreferenceChangeListener
sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
// Note that key can be null
if (PreferencesUtils.getKey(TrackDetailActivity.this, R.string.recording_track_id_key)
.equals(key)) {
updateMenu();
}
}
};
/**
* We are not displaying driving directions. Just an arbitrary track that is
@@ -133,31 +126,28 @@ public class TrackDetailActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
ApiAdapterFactory.getApiAdapter().hideTitle(this);
ApiAdapterFactory.getApiAdapter().configureActionBarHomeAsUp(this);
setContentView(R.layout.track_detail);
sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE)
.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
trackDataHub = ((MyTracksApplication) getApplication()).getTrackDataHub();
trackRecordingServiceConnection = new TrackRecordingServiceConnection(this, null);
mapViewContainer = getLayoutInflater().inflate(R.layout.mytracks_layout, null);
mapViewContainer = getLayoutInflater().inflate(R.layout.map, null);
tabHost = (TabHost) findViewById(android.R.id.tabhost);
tabHost.setup();
tabManager = new TabManager(this, tabHost, R.id.realtabcontent);
TabSpec mapTabSpec = tabHost.newTabSpec(MAP_TAB_TAG).setIndicator(
getString(R.string.track_detail_map_tab),
getResources().getDrawable(android.R.drawable.ic_menu_mapmode));
TabSpec mapTabSpec = tabHost.newTabSpec(MapFragment.MAP_FRAGMENT_TAG).setIndicator(
getString(R.string.track_detail_map_tab), getResources().getDrawable(R.drawable.tab_map));
tabManager.addTab(mapTabSpec, MapFragment.class, null);
TabSpec chartTabSpec = tabHost.newTabSpec(CHART_TAB_TAG).setIndicator(
TabSpec chartTabSpec = tabHost.newTabSpec(ChartFragment.CHART_FRAGMENT_TAG).setIndicator(
getString(R.string.track_detail_chart_tab),
getResources().getDrawable(R.drawable.menu_elevation));
getResources().getDrawable(R.drawable.tab_chart));
tabManager.addTab(chartTabSpec, ChartFragment.class, null);
TabSpec statsTabSpec = tabHost.newTabSpec(STATS_TAB_TAG).setIndicator(
TabSpec statsTabSpec = tabHost.newTabSpec(StatsFragment.STATS_FRAGMENT_TAG).setIndicator(
getString(R.string.track_detail_stats_tab),
getResources().getDrawable(R.drawable.ic_menu_statistics));
getResources().getDrawable(R.drawable.tab_stats));
tabManager.addTab(statsTabSpec, StatsFragment.class, null);
if (savedInstanceState != null) {
tabHost.setCurrentTabByTag(savedInstanceState.getString(CURRENT_TAG_KEY));
@@ -165,13 +155,13 @@ public class TrackDetailActivity extends FragmentActivity {
handleIntent(getIntent());
}
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
handleIntent(intent);
}
}
@Override
protected void onStart() {
super.onStart();
@@ -238,41 +228,27 @@ public class TrackDetailActivity extends FragmentActivity {
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
String currentTabTag = tabHost.getCurrentTabTag();
menu.findItem(R.id.track_detail_chart_settings).setVisible(CHART_TAB_TAG.equals(currentTabTag));
menu.findItem(R.id.track_detail_my_location).setVisible(MAP_TAB_TAG.equals(currentTabTag));
// Set map or satellite mode
MapFragment mapFragment = (MapFragment) getSupportFragmentManager()
.findFragmentByTag(MAP_TAB_TAG);
boolean isSatelliteMode = mapFragment != null ? mapFragment.isSatelliteView() : false;
menu.findItem(R.id.track_detail_satellite_mode).setVisible(MAP_TAB_TAG.equals(currentTabTag))
.setTitle(isSatelliteMode ? R.string.menu_map_mode : R.string.menu_satellite_mode);
return super.onPrepareOptionsMenu(menu);
protected void onHomeSelected() {
Intent intent = IntentUtils.newIntent(this, TrackListActivity.class);
startActivity(intent);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
MapFragment mapFragment;
Intent intent;
switch (item.getItemId()) {
case android.R.id.home:
startTrackListActivity();
return true;
case R.id.track_detail_stop_recording:
updateMenuItems(false);
TrackRecordingServiceConnectionUtils.stop(this, trackRecordingServiceConnection);
return true;
case R.id.track_detail_insert_marker:
startActivity(new Intent(this, MarkerEditActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
MarkerAddDialogFragment.newInstance(trackId)
.show(getSupportFragmentManager(), MarkerAddDialogFragment.MARKER_ADD_DIALOG_TAG);
return true;
case R.id.track_detail_play:
if (isEarthInstalled()) {
AnalyticsUtils.sendPageViews(this, "/action/play");
intent = new Intent(this, SaveActivity.class)
intent = IntentUtils.newIntent(this, SaveActivity.class)
.putExtra(SaveActivity.EXTRA_TRACK_ID, trackId)
.putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.KML)
.putExtra(SaveActivity.EXTRA_PLAY_TRACK, true);
@@ -282,13 +258,13 @@ public class TrackDetailActivity extends FragmentActivity {
getSupportFragmentManager(), InstallEarthDialogFragment.INSTALL_EARTH_DIALOG_TAG);
}
return true;
case R.id.track_detail_share_map:
intent = new Intent(this, UploadServiceChooserActivity.class)
case R.id.track_detail_share_map_url:
intent = IntentUtils.newIntent(this, UploadServiceChooserActivity.class)
.putExtra(SendRequest.SEND_REQUEST_KEY, new SendRequest(trackId, true, false, false));
startActivity(intent);
return true;
case R.id.track_detail_share_fusion_table:
intent = new Intent(this, UploadServiceChooserActivity.class)
case R.id.track_detail_share_fusion_table_url:
intent = IntentUtils.newIntent(this, UploadServiceChooserActivity.class)
.putExtra(SendRequest.SEND_REQUEST_KEY, new SendRequest(trackId, false, true, false));
startActivity(intent);
return true;
@@ -305,13 +281,12 @@ public class TrackDetailActivity extends FragmentActivity {
startSaveActivity(TrackFileFormat.TCX, true);
return true;
case R.id.track_detail_markers:
intent = new Intent(this, MarkerListActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
intent = IntentUtils.newIntent(this, MarkerListActivity.class)
.putExtra(MarkerListActivity.EXTRA_TRACK_ID, trackId);
startActivity(intent);
return true;
case R.id.track_detail_send_google:
intent = new Intent(this, UploadServiceChooserActivity.class)
intent = IntentUtils.newIntent(this, UploadServiceChooserActivity.class)
.putExtra(SendRequest.SEND_REQUEST_KEY, new SendRequest(trackId, true, true, true));
startActivity(intent);
return true;
@@ -328,40 +303,28 @@ public class TrackDetailActivity extends FragmentActivity {
startSaveActivity(TrackFileFormat.TCX, false);
return true;
case R.id.track_detail_edit:
startActivity(new Intent(this, TrackEditActivity.class)
.putExtra(TrackEditActivity.EXTRA_TRACK_ID, trackId));
intent = IntentUtils.newIntent(this, TrackEditActivity.class)
.putExtra(TrackEditActivity.EXTRA_TRACK_ID, trackId);
startActivity(intent);
return true;
case R.id.track_detail_delete:
DeleteOneTrackDialogFragment.newInstance(trackId).show(
getSupportFragmentManager(), DeleteOneTrackDialogFragment.DELETE_ONE_TRACK_DIALOG_TAG);
return true;
case R.id.track_detail_my_location:
mapFragment = (MapFragment) getSupportFragmentManager().findFragmentByTag(MAP_TAB_TAG);
if (mapFragment != null) {
mapFragment.showMyLocation();
}
return true;
case R.id.track_detail_satellite_mode:
mapFragment = (MapFragment) getSupportFragmentManager().findFragmentByTag(MAP_TAB_TAG);
if (mapFragment != null) {
mapFragment.setSatelliteView(!mapFragment.isSatelliteView());
}
return true;
case R.id.track_detail_chart_settings:
new ChartSettingsDialogFragment().show(
getSupportFragmentManager(), ChartSettingsDialogFragment.CHART_SETTINGS_DIALOG_TAG);
return true;
case R.id.track_detail_sensor_state:
startActivity(new Intent(this, SensorStateActivity.class));
intent = IntentUtils.newIntent(this, SensorStateActivity.class);
startActivity(intent);
return true;
case R.id.track_detail_settings:
startActivity(new Intent(this, SettingsActivity.class));
intent = IntentUtils.newIntent(this, SettingsActivity.class);
startActivity(intent);
return true;
case R.id.track_detail_help:
startActivity(new Intent(this, HelpActivity.class));
intent = IntentUtils.newIntent(this, HelpActivity.class);
startActivity(intent);
return true;
default:
return false;
return super.onOptionsItemSelected(item);
}
}
@@ -369,25 +332,8 @@ public class TrackDetailActivity extends FragmentActivity {
public boolean onTrackballEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (TrackRecordingServiceConnectionUtils.isRecording(this, trackRecordingServiceConnection)) {
ITrackRecordingService trackRecordingService = trackRecordingServiceConnection
.getServiceIfBound();
if (trackRecordingService == null) {
Log.e(TAG, "The track recording service is null");
return true;
}
boolean success = false;
try {
long waypointId = trackRecordingService.insertWaypoint(
WaypointCreationRequest.DEFAULT_STATISTICS);
if (waypointId != -1L) {
success = true;
}
} catch (RemoteException e) {
Log.e(TAG, "Unable to insert waypoint", e);
}
Toast.makeText(this,
success ? R.string.marker_edit_add_success : R.string.marker_edit_add_error,
success ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG).show();
TrackRecordingServiceConnectionUtils.addMarker(
this, trackRecordingServiceConnection, WaypointCreationRequest.DEFAULT_STATISTICS);
return true;
}
}
@@ -410,14 +356,16 @@ public class TrackDetailActivity extends FragmentActivity {
if (markerId != -1L) {
Waypoint waypoint = MyTracksProviderUtils.Factory.get(this).getWaypoint(markerId);
if (waypoint == null) {
startTrackListActivity();
Intent newIntent = IntentUtils.newIntent(this, TrackListActivity.class);
startActivity(newIntent);
finish();
return;
}
trackId = waypoint.getTrackId();
}
if (trackId == -1L) {
startTrackListActivity();
Intent newIntent = IntentUtils.newIntent(this, TrackListActivity.class);
startActivity(newIntent);
finish();
return;
}
@@ -425,9 +373,9 @@ public class TrackDetailActivity extends FragmentActivity {
if (markerId != -1L) {
MapFragment mapFragmet = (MapFragment) getSupportFragmentManager()
.findFragmentByTag(MAP_TAB_TAG);
.findFragmentByTag(MapFragment.MAP_FRAGMENT_TAG);
if (mapFragmet != null) {
tabHost.setCurrentTabByTag(MAP_TAB_TAG);
tabHost.setCurrentTabByTag(MapFragment.MAP_FRAGMENT_TAG);
mapFragmet.showMarker(trackId, markerId);
} else {
Log.e(TAG, "MapFragment is null");
@@ -439,7 +387,7 @@ public class TrackDetailActivity extends FragmentActivity {
* Updates the menu.
*/
private void updateMenu() {
updateMenuItems(trackId == PreferencesUtils.getRecordingTrackId(this));
updateMenuItems(trackId == PreferencesUtils.getLong(this, R.string.recording_track_id_key));
}
/**
@@ -474,14 +422,6 @@ public class TrackDetailActivity extends FragmentActivity {
}
}
/**
* Starts the {@link TrackListActivity}.
*/
private void startTrackListActivity() {
startActivity(new Intent(this, TrackListActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
}
/**
* Starts the {@link SaveActivity} to save a track.
*
@@ -489,7 +429,7 @@ public class TrackDetailActivity extends FragmentActivity {
* @param shareTrack true to share the track after saving
*/
private void startSaveActivity(TrackFileFormat trackFileFormat, boolean shareTrack) {
Intent intent = new Intent(this, SaveActivity.class)
Intent intent = IntentUtils.newIntent(this, SaveActivity.class)
.putExtra(SaveActivity.EXTRA_TRACK_ID, trackId)
.putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) trackFileFormat)
.putExtra(SaveActivity.EXTRA_SHARE_TRACK, shareTrack);
@@ -18,16 +18,11 @@ 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.util.ApiAdapterFactory;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
@@ -39,10 +34,10 @@ import android.widget.EditText;
*
* @author Leif Hendrik Wilden
*/
public class TrackEditActivity extends Activity implements OnClickListener {
public class TrackEditActivity extends AbstractMyTracksActivity {
public static final String EXTRA_TRACK_ID = "track_id";
public static final String EXTRA_SHOW_CANCEL = "show_cancel";
public static final String EXTRA_NEW_TRACK = "new_track";
private static final String TAG = TrackEditActivity.class.getSimpleName();
@@ -57,8 +52,6 @@ public class TrackEditActivity extends Activity implements OnClickListener {
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
ApiAdapterFactory.getApiAdapter().configureActionBarHomeAsUp(this);
setContentView(R.layout.track_edit);
trackId = getIntent().getLongExtra(EXTRA_TRACK_ID, -1L);
@@ -89,36 +82,30 @@ public class TrackEditActivity extends Activity implements OnClickListener {
description.setText(track.getDescription());
Button save = (Button) findViewById(R.id.track_edit_save);
save.setOnClickListener(this);
save.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
track.setName(name.getText().toString());
track.setCategory(activityType.getText().toString());
track.setDescription(description.getText().toString());
myTracksProviderUtils.updateTrack(track);
finish();
}
});
Button cancel = (Button) findViewById(R.id.track_edit_cancel);
if (getIntent().getBooleanExtra(EXTRA_SHOW_CANCEL, true)) {
setTitle(R.string.menu_edit);
cancel.setOnClickListener(this);
cancel.setVisibility(View.VISIBLE);
} else {
if (getIntent().getBooleanExtra(EXTRA_NEW_TRACK, false)) {
setTitle(R.string.track_edit_new_track_title);
cancel.setVisibility(View.GONE);
} else {
setTitle(R.string.menu_edit);
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
cancel.setVisibility(View.VISIBLE);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() != android.R.id.home) {
return false;
}
finish();
return true;
}
@Override
public void onClick(View view) {
if (view.getId() == R.id.track_edit_save) {
track.setName(name.getText().toString());
track.setCategory(activityType.getText().toString());
track.setDescription(description.getText().toString());
myTracksProviderUtils.updateTrack(track);
}
finish();
}
}
@@ -17,14 +17,19 @@
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.fragments.CheckUnitsDialogFragment;
import com.google.android.apps.mytracks.fragments.DeleteAllTrackDialogFragment;
import com.google.android.apps.mytracks.fragments.DeleteOneTrackDialogFragment;
import com.google.android.apps.mytracks.fragments.EulaDialogFragment;
import com.google.android.apps.mytracks.fragments.WelcomeDialogFragment;
import com.google.android.apps.mytracks.io.file.TrackWriterFactory.TrackFileFormat;
import com.google.android.apps.mytracks.services.ITrackRecordingService;
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
import com.google.android.apps.mytracks.settings.SettingsActivity;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.EulaUtils;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.ListItemUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
@@ -56,7 +61,6 @@ import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
/**
@@ -93,10 +97,11 @@ public class TrackListActivity extends FragmentActivity {
try {
recordingTrackId = service.startNewTrack();
startNewRecording = false;
startTrackDetailActivity(recordingTrackId);
Intent intent = IntentUtils.newIntent(TrackListActivity.this, TrackDetailActivity.class)
.putExtra(TrackDetailActivity.EXTRA_TRACK_ID, recordingTrackId);
startActivity(intent);
Toast.makeText(
TrackListActivity.this, R.string.track_list_record_success, Toast.LENGTH_SHORT).show();
Log.d(TAG, "Started a new recording");
} catch (Exception e) {
Toast.makeText(TrackListActivity.this, R.string.track_list_record_error, Toast.LENGTH_LONG)
.show();
@@ -113,19 +118,28 @@ public class TrackListActivity extends FragmentActivity {
sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
boolean updateList = false;
// Note that key can be null
if (getString(R.string.metric_units_key).equals(key)) {
metricUnits = preferences.getBoolean(getString(R.string.metric_units_key), true);
if (PreferencesUtils.getKey(TrackListActivity.this, R.string.metric_units_key)
.equals(key)) {
metricUnits = PreferencesUtils.getBoolean(TrackListActivity.this,
R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
updateList = true;
}
if (PreferencesUtils.getRecordingTrackIdKey(TrackListActivity.this).equals(key)) {
recordingTrackId = PreferencesUtils.getRecordingTrackId(TrackListActivity.this);
if (PreferencesUtils.getKey(TrackListActivity.this, R.string.recording_track_id_key)
.equals(key)) {
recordingTrackId = PreferencesUtils.getLong(
TrackListActivity.this, R.string.recording_track_id_key);
if (TrackRecordingServiceConnectionUtils.isRecording(
TrackListActivity.this, trackRecordingServiceConnection)) {
trackRecordingServiceConnection.startAndBind();
}
updateMenu();
updateList = true;
}
if (updateList) {
resourceCursorAdapter.notifyDataSetChanged();
}
resourceCursorAdapter.notifyDataSetChanged();
}
};
@@ -133,7 +147,7 @@ public class TrackListActivity extends FragmentActivity {
private ContextualActionModeCallback contextualActionModeCallback =
new ContextualActionModeCallback() {
@Override
public boolean onClick(int itemId, long id) {
public boolean onClick(int itemId, int position, long id) {
return handleContextItem(itemId, id);
}
};
@@ -150,8 +164,8 @@ public class TrackListActivity extends FragmentActivity {
private MenuItem recordTrackMenuItem;
private MenuItem stopRecordingMenuItem;
private MenuItem searchMenuItem;
private MenuItem importAllMenuItem;
private MenuItem exportAllMenuItem;
private MenuItem importMenuItem;
private MenuItem saveAllMenuItem;
private MenuItem deleteAllMenuItem;
@Override
@@ -164,11 +178,11 @@ public class TrackListActivity extends FragmentActivity {
trackRecordingServiceConnection = new TrackRecordingServiceConnection(
this, bindChangedCallback);
SharedPreferences sharedPreferences = getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
metricUnits = sharedPreferences.getBoolean(getString(R.string.metric_units_key), true);
recordingTrackId = PreferencesUtils.getRecordingTrackId(this);
getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE)
.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
metricUnits = PreferencesUtils.getBoolean(
this, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
recordingTrackId = PreferencesUtils.getLong(this, R.string.recording_track_id_key);
ImageButton recordImageButton = (ImageButton) findViewById(R.id.track_list_record_button);
recordImageButton.setOnClickListener(new View.OnClickListener() {
@@ -184,11 +198,13 @@ public class TrackListActivity extends FragmentActivity {
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
startTrackDetailActivity(id);
Intent intent = IntentUtils.newIntent(TrackListActivity.this, TrackDetailActivity.class)
.putExtra(TrackDetailActivity.EXTRA_TRACK_ID, id);
startActivity(intent);
}
});
resourceCursorAdapter = new ResourceCursorAdapter(this, R.layout.track_list_item, null, 0) {
@Override
resourceCursorAdapter = new ResourceCursorAdapter(this, R.layout.list_item, null, 0) {
@Override
public void bindView(View view, Context context, Cursor cursor) {
int idIndex = cursor.getColumnIndex(TracksColumns._ID);
int nameIndex = cursor.getColumnIndex(TracksColumns.NAME);
@@ -199,37 +215,32 @@ public class TrackListActivity extends FragmentActivity {
int descriptionIndex = cursor.getColumnIndex(TracksColumns.DESCRIPTION);
boolean isRecording = cursor.getLong(idIndex) == recordingTrackId;
TextView name = (TextView) view.findViewById(R.id.track_list_item_name);
name.setText(cursor.getString(nameIndex));
name.setCompoundDrawablesWithIntrinsicBounds(
isRecording ? R.drawable.menu_record_track : R.drawable.track, 0, 0, 0);
TextView category = (TextView) view.findViewById(R.id.track_list_item_category);
category.setText(cursor.getString(categoryIndex));
TextView time = (TextView) view.findViewById(R.id.track_list_item_time);
time.setText(StringUtils.formatElapsedTime(cursor.getLong(timeIndex)));
time.setVisibility(isRecording ? View.GONE : View.VISIBLE);
TextView distance = (TextView) view.findViewById(R.id.track_list_item_distance);
distance.setText(StringUtils.formatDistance(
TrackListActivity.this, cursor.getDouble(distanceIndex), metricUnits));
distance.setVisibility(isRecording ? View.GONE : View.VISIBLE);
TextView start = (TextView) view.findViewById(R.id.track_list_item_start);
start.setText(
StringUtils.formatDateTime(TrackListActivity.this, cursor.getLong(startIndex)));
start.setVisibility(start.getText().equals(name.getText()) ? View.GONE : View.VISIBLE);
TextView description = (TextView) view.findViewById(R.id.track_list_item_description);
description.setText(cursor.getString(descriptionIndex));
description.setVisibility(description.getText().length() == 0 ? View.GONE : View.VISIBLE);
String name = cursor.getString(nameIndex);
int iconId = isRecording ? R.drawable.menu_record_track : R.drawable.track;
String category = cursor.getString(categoryIndex);
String totalTime = isRecording
? null : StringUtils.formatElapsedTime(cursor.getLong(timeIndex));
String totalDistance = isRecording ? null : StringUtils.formatDistance(
TrackListActivity.this, cursor.getDouble(distanceIndex), metricUnits);
String startTime =
StringUtils.formatDateTime(TrackListActivity.this, cursor.getLong(startIndex));
if (startTime.equals(name)) {
startTime = null;
}
String description = cursor.getString(descriptionIndex);
ListItemUtils.setListItem(view,
name,
iconId,
category,
totalTime,
totalDistance,
startTime,
description);
}
};
listView.setAdapter(resourceCursorAdapter);
ApiAdapterFactory.getApiAdapter().configureListViewContextualMenu(
this, listView, R.menu.track_list_context_menu, R.id.track_list_item_name,
this, listView, R.menu.list_context_menu, R.id.list_item_name,
contextualActionModeCallback);
getSupportLoaderManager().initLoader(0, null, new LoaderCallbacks<Cursor>() {
@@ -254,15 +265,50 @@ public class TrackListActivity extends FragmentActivity {
}
});
showStartupDialogs();
}
/**
* Shows start up dialogs.
*/
public void showStartupDialogs() {
if (!EulaUtils.getEulaValue(this)) {
Fragment fragment = getSupportFragmentManager()
.findFragmentByTag(EulaDialogFragment.EULA_DIALOG_TAG);
if (fragment == null) {
EulaDialogFragment.newInstance(false).show(
getSupportFragmentManager(), EulaDialogFragment.EULA_DIALOG_TAG);
EulaDialogFragment.newInstance(false)
.show(getSupportFragmentManager(), EulaDialogFragment.EULA_DIALOG_TAG);
}
} else if (PreferencesUtils.getBoolean(
this, R.string.show_welcome_dialog_key, PreferencesUtils.SHOW_WELCOME_DIALOG_DEFAULT)) {
Fragment fragment = getSupportFragmentManager()
.findFragmentByTag(WelcomeDialogFragment.WELCOME_DIALOG_TAG);
if (fragment == null) {
new WelcomeDialogFragment().show(
getSupportFragmentManager(), WelcomeDialogFragment.WELCOME_DIALOG_TAG);
}
} else if (PreferencesUtils.getBoolean(this, R.string.show_check_units_dialog_key,
PreferencesUtils.SHOW_CHECK_UNITS_DIALOG_DEFAULT)) {
Fragment fragment = getSupportFragmentManager()
.findFragmentByTag(CheckUnitsDialogFragment.CHECK_UNITS_DIALOG_TAG);
if (fragment == null) {
new CheckUnitsDialogFragment().show(
getSupportFragmentManager(), CheckUnitsDialogFragment.CHECK_UNITS_DIALOG_TAG);
}
} else {
enableEmptyView();
}
}
/**
* Enables the content of the empty view.
*/
private void enableEmptyView() {
View emptyMessage = findViewById(R.id.track_list_empty_message);
emptyMessage.setVisibility(View.VISIBLE);
View recordButton = findViewById(R.id.track_list_record_button);
recordButton.setVisibility(View.VISIBLE);
}
@Override
protected void onResume() {
@@ -280,20 +326,20 @@ public class TrackListActivity extends FragmentActivity {
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.track_list, menu);
String fileTypes[] = getResources().getStringArray(R.array.file_types);
menu.findItem(R.id.track_list_export_gpx)
.setTitle(getString(R.string.menu_export_all_format, fileTypes[0]));
menu.findItem(R.id.track_list_export_kml)
.setTitle(getString(R.string.menu_export_all_format, fileTypes[1]));
menu.findItem(R.id.track_list_export_csv)
.setTitle(getString(R.string.menu_export_all_format, fileTypes[2]));
menu.findItem(R.id.track_list_export_tcx)
.setTitle(getString(R.string.menu_export_all_format, fileTypes[3]));
menu.findItem(R.id.track_list_save_all_gpx)
.setTitle(getString(R.string.menu_save_format, fileTypes[0]));
menu.findItem(R.id.track_list_save_all_kml)
.setTitle(getString(R.string.menu_save_format, fileTypes[1]));
menu.findItem(R.id.track_list_save_all_csv)
.setTitle(getString(R.string.menu_save_format, fileTypes[2]));
menu.findItem(R.id.track_list_save_all_tcx)
.setTitle(getString(R.string.menu_save_format, fileTypes[3]));
recordTrackMenuItem = menu.findItem(R.id.track_list_record_track);
stopRecordingMenuItem = menu.findItem(R.id.track_list_stop_recording);
searchMenuItem = menu.findItem(R.id.track_list_search);
importAllMenuItem = menu.findItem(R.id.track_list_import_all);
exportAllMenuItem = menu.findItem(R.id.track_list_export_all);
importMenuItem = menu.findItem(R.id.track_list_import);
saveAllMenuItem = menu.findItem(R.id.track_list_save_all);
deleteAllMenuItem = menu.findItem(R.id.track_list_delete_all);
ApiAdapterFactory.getApiAdapter().configureSearchWidget(this, searchMenuItem);
@@ -321,11 +367,11 @@ public class TrackListActivity extends FragmentActivity {
if (stopRecordingMenuItem != null) {
stopRecordingMenuItem.setVisible(isRecording);
}
if (importAllMenuItem != null) {
importAllMenuItem.setVisible(!isRecording);
if (importMenuItem != null) {
importMenuItem.setVisible(!isRecording);
}
if (exportAllMenuItem != null) {
exportAllMenuItem.setVisible(!isRecording);
if (saveAllMenuItem != null) {
saveAllMenuItem.setVisible(!isRecording);
}
if (deleteAllMenuItem != null) {
deleteAllMenuItem.setVisible(!isRecording);
@@ -334,6 +380,7 @@ public class TrackListActivity extends FragmentActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent intent;
switch (item.getItemId()) {
case R.id.track_list_record_track:
updateMenuItems(true);
@@ -345,38 +392,46 @@ public class TrackListActivity extends FragmentActivity {
return true;
case R.id.track_list_search:
return ApiAdapterFactory.getApiAdapter().handleSearchMenuSelection(this);
case R.id.track_list_import_all:
startActivity(
new Intent(this, ImportActivity.class).putExtra(ImportActivity.EXTRA_IMPORT_ALL, true));
case R.id.track_list_import:
intent = IntentUtils.newIntent(this, ImportActivity.class)
.putExtra(ImportActivity.EXTRA_IMPORT_ALL, true);
startActivity(intent);
return true;
case R.id.track_list_export_gpx:
startActivity(new Intent(this, ExportActivity.class).putExtra(
ExportActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.GPX));
case R.id.track_list_save_all_gpx:
intent = IntentUtils.newIntent(this, SaveAllActivity.class)
.putExtra(SaveAllActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.GPX);
startActivity(intent);
return true;
case R.id.track_list_export_kml:
startActivity(new Intent(this, ExportActivity.class).putExtra(
ExportActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.KML));
case R.id.track_list_save_all_kml:
intent = IntentUtils.newIntent(this, SaveAllActivity.class)
.putExtra(SaveAllActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.KML);
startActivity(intent);
return true;
case R.id.track_list_export_csv:
startActivity(new Intent(this, ExportActivity.class).putExtra(
ExportActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.CSV));
case R.id.track_list_save_all_csv:
intent = IntentUtils.newIntent(this, SaveAllActivity.class)
.putExtra(SaveAllActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.CSV);
startActivity(intent);
return true;
case R.id.track_list_export_tcx:
startActivity(new Intent(this, ExportActivity.class).putExtra(
ExportActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.TCX));
case R.id.track_list_save_all_tcx:
intent = IntentUtils.newIntent(this, SaveAllActivity.class)
.putExtra(SaveAllActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) TrackFileFormat.TCX);
startActivity(intent);
return true;
case R.id.track_list_delete_all:
new DeleteAllTrackDialogFragment().show(
getSupportFragmentManager(), DeleteAllTrackDialogFragment.DELETE_ALL_TRACK_DIALOG_TAG);
return true;
case R.id.track_list_aggregated_statistics:
startActivity(new Intent(this, AggregatedStatsActivity.class));
intent = IntentUtils.newIntent(this, AggregatedStatsActivity.class);
startActivity(intent);
return true;
case R.id.track_list_settings:
startActivity(new Intent(this, SettingsActivity.class));
intent = IntentUtils.newIntent(this, SettingsActivity.class);
startActivity(intent);
return true;
case R.id.track_list_help:
startActivity(new Intent(this, HelpActivity.class));
intent = IntentUtils.newIntent(this, HelpActivity.class);
startActivity(intent);
return true;
default:
return super.onOptionsItemSelected(item);
@@ -386,7 +441,7 @@ public class TrackListActivity extends FragmentActivity {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
getMenuInflater().inflate(R.menu.track_list_context_menu, menu);
getMenuInflater().inflate(R.menu.list_context_menu, menu);
}
@Override
@@ -396,21 +451,28 @@ public class TrackListActivity extends FragmentActivity {
}
return super.onContextItemSelected(item);
}
/**
* Handles a context item selection.
*
*
* @param itemId the menu item id
* @param trackId the track id
* @return true if handled.
*/
private boolean handleContextItem(int itemId, long trackId) {
Intent intent;
switch (itemId) {
case R.id.track_list_context_menu_edit:
startActivity(new Intent(this, TrackEditActivity.class).putExtra(
TrackEditActivity.EXTRA_TRACK_ID, trackId));
case R.id.list_context_menu_show_on_map:
intent = IntentUtils.newIntent(this, TrackDetailActivity.class)
.putExtra(TrackDetailActivity.EXTRA_TRACK_ID, trackId);
startActivity(intent);
return true;
case R.id.track_list_context_menu_delete:
case R.id.list_context_menu_edit:
intent = IntentUtils.newIntent(this, TrackEditActivity.class)
.putExtra(TrackEditActivity.EXTRA_TRACK_ID, trackId);
startActivity(intent);
return true;
case R.id.list_context_menu_delete:
DeleteOneTrackDialogFragment.newInstance(trackId).show(
getSupportFragmentManager(), DeleteOneTrackDialogFragment.DELETE_ONE_TRACK_DIALOG_TAG);
return true;
@@ -418,18 +480,6 @@ public class TrackListActivity extends FragmentActivity {
return false;
}
}
/**
* Starts {@link TrackDetailActivity}.
*
* @param trackId the track id.
*/
private void startTrackDetailActivity(long trackId) {
Intent intent = new Intent(TrackListActivity.this, TrackDetailActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(TrackDetailActivity.EXTRA_TRACK_ID, trackId);
startActivity(intent);
}
/**
* Starts a new recording.
@@ -16,13 +16,13 @@
package com.google.android.apps.mytracks.content;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
@@ -190,13 +190,11 @@ public class MyTracksProvider extends ContentProvider {
if (Binder.getCallingPid() == Process.myPid()) {
return true;
} else {
Context context = getContext();
SharedPreferences sharedPreferences = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
return sharedPreferences.getBoolean(context.getString(R.string.allow_access_key), false);
return PreferencesUtils.getBoolean(
getContext(), R.string.allow_access_key, PreferencesUtils.ALLOW_ACCESS_DEFAULT);
}
}
@Override
public boolean onCreate() {
if (!canAccess()) {
@@ -15,7 +15,6 @@
*/
package com.google.android.apps.mytracks.content;
import static com.google.android.apps.mytracks.Constants.DEFAULT_MIN_REQUIRED_ACCURACY;
import static com.google.android.apps.mytracks.Constants.MAX_DISPLAYED_WAYPOINTS_POINTS;
import static com.google.android.apps.mytracks.Constants.MAX_LOCATION_AGE_MS;
import static com.google.android.apps.mytracks.Constants.MAX_NETWORK_AGE_MS;
@@ -58,11 +57,6 @@ import java.util.Set;
*/
public class TrackDataHub {
// Preference keys
private final String MIN_REQUIRED_ACCURACY_KEY;
private final String METRIC_UNITS_KEY;
private final String SPEED_REPORTING_KEY;
// Overridable constants
private final int targetNumPoints;
@@ -171,7 +165,7 @@ public class TrackDataHub {
// Cached preference values
private int minRequiredAccuracy;
private boolean useMetricUnits;
private boolean metricUnits;
private boolean reportSpeed;
// Cached sensor readings
@@ -221,10 +215,6 @@ public class TrackDataHub {
this.targetNumPoints = targetNumPoints;
this.locationFactory = new DoubleBufferedLocationFactory();
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);
resetState();
}
@@ -298,11 +288,13 @@ public class TrackDataHub {
}
private void loadSharedPreferences() {
selectedTrackId = PreferencesUtils.getSelectedTrackId(context);
useMetricUnits = preferences.getBoolean(METRIC_UNITS_KEY, true);
reportSpeed = preferences.getBoolean(SPEED_REPORTING_KEY, true);
minRequiredAccuracy = preferences.getInt(MIN_REQUIRED_ACCURACY_KEY,
DEFAULT_MIN_REQUIRED_ACCURACY);
selectedTrackId = PreferencesUtils.getLong(context, R.string.selected_track_id_key);
metricUnits = PreferencesUtils.getBoolean(
context, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
reportSpeed = PreferencesUtils.getBoolean(
context, R.string.report_speed_key, PreferencesUtils.REPORT_SPEED_DEFAULT);
minRequiredAccuracy = PreferencesUtils.getInt(context, R.string.min_required_accuracy_key,
PreferencesUtils.MIN_REQUIRED_ACCURACY_DEFAULT);
}
/** Updates known magnetic declination if needed. */
@@ -376,8 +368,9 @@ public class TrackDataHub {
if (!isStarted()) {
loadSharedPreferences();
}
long recordingTrackId = PreferencesUtils.getRecordingTrackId(context);
return recordingTrackId != -1L && recordingTrackId == selectedTrackId;
long recordingTrackId = PreferencesUtils.getLong(context, R.string.recording_track_id_key);
return recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT
&& recordingTrackId == selectedTrackId;
}
/**
@@ -395,7 +388,7 @@ public class TrackDataHub {
// Save the selection to memory and flush.
selectedTrackId = trackId;
PreferencesUtils.setSelectedTrackId(context, selectedTrackId);
PreferencesUtils.setLong(context, R.string.selected_track_id_key, selectedTrackId);
// Force it to reload data from the beginning.
Log.d(TAG, "Loading track");
@@ -495,7 +488,7 @@ public class TrackDataHub {
Set<TrackDataListener> listenerSet = Collections.singleton(listener);
if (registration.isInterestedIn(ListenerDataType.DISPLAY_PREFERENCES)) {
reloadAll |= listener.onUnitsChanged(useMetricUnits);
reloadAll |= listener.onUnitsChanged(metricUnits);
reloadAll |= listener.onReportSpeedChanged(reportSpeed);
}
@@ -577,7 +570,7 @@ public class TrackDataHub {
// Ignore the return values here, we're already sending the full data set anyway
for (TrackDataListener listener :
getListenersFor(ListenerDataType.DISPLAY_PREFERENCES)) {
listener.onUnitsChanged(useMetricUnits);
listener.onUnitsChanged(metricUnits);
listener.onReportSpeedChanged(reportSpeed);
}
@@ -609,21 +602,23 @@ public class TrackDataHub {
/**
* Called when a preference changes.
*
*
* @param key the key to the preference that changed
*/
private void notifyPreferenceChanged(String key) {
if (MIN_REQUIRED_ACCURACY_KEY.equals(key)) {
minRequiredAccuracy = preferences.getInt(MIN_REQUIRED_ACCURACY_KEY,
DEFAULT_MIN_REQUIRED_ACCURACY);
} else if (METRIC_UNITS_KEY.equals(key)) {
useMetricUnits = preferences.getBoolean(METRIC_UNITS_KEY, true);
if (PreferencesUtils.getKey(context, R.string.min_required_accuracy_key).equals(key)) {
minRequiredAccuracy = PreferencesUtils.getInt(context, R.string.min_required_accuracy_key,
PreferencesUtils.MIN_REQUIRED_ACCURACY_DEFAULT);
} else if (PreferencesUtils.getKey(context, R.string.metric_units_key).equals(key)) {
metricUnits = PreferencesUtils.getBoolean(
context, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
notifyUnitsChanged();
} else if (SPEED_REPORTING_KEY.equals(key)) {
reportSpeed = preferences.getBoolean(SPEED_REPORTING_KEY, true);
} else if (PreferencesUtils.getKey(context, R.string.report_speed_key).equals(key)) {
reportSpeed = PreferencesUtils.getBoolean(
context, R.string.report_speed_key, PreferencesUtils.REPORT_SPEED_DEFAULT);
notifySpeedReportingChanged();
} else if (PreferencesUtils.getSelectedTrackIdKey(context).equals(key)) {
loadTrack(PreferencesUtils.getSelectedTrackId(context));
} else if (PreferencesUtils.getKey(context, R.string.selected_track_id_key).equals(key)) {
loadTrack(PreferencesUtils.getLong(context, R.string.selected_track_id_key));
}
}
@@ -659,7 +654,7 @@ public class TrackDataHub {
Set<TrackDataListener> displayListeners = getListenersFor(ListenerDataType.DISPLAY_PREFERENCES);
for (TrackDataListener listener : displayListeners) {
if (listener.onUnitsChanged(useMetricUnits)) {
if (listener.onUnitsChanged(metricUnits)) {
synchronized (dataListeners) {
reloadDataForListener(listener);
}
@@ -42,7 +42,6 @@ public class AboutDialogFragment extends DialogFragment {
TextView aboutVersion = (TextView) view.findViewById(R.id.about_version);
aboutVersion.setText(SystemUtils.getMyTracksVersion(getActivity()));
return new AlertDialog.Builder(getActivity())
.setCancelable(true)
.setNegativeButton(R.string.about_license, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
@@ -17,7 +17,6 @@
package com.google.android.apps.mytracks.fragments;
import com.google.android.apps.mytracks.ChartView;
import com.google.android.apps.mytracks.ChartView.Mode;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.MyTracksApplication;
import com.google.android.apps.mytracks.content.MyTracksLocation;
@@ -31,6 +30,7 @@ import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.stats.DoubleBuffer;
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
import com.google.common.annotations.VisibleForTesting;
@@ -42,7 +42,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
import android.widget.ZoomControls;
import java.util.ArrayList;
@@ -56,6 +55,8 @@ import java.util.EnumSet;
*/
public class ChartFragment extends Fragment implements TrackDataListener {
public static final String CHART_FRAGMENT_TAG = "chartFragment";
// Android reports 128 when the speed is invalid
private static final int INVALID_SPEED = 128;
private final DoubleBuffer elevationBuffer = new DoubleBuffer(
@@ -75,9 +76,11 @@ public class ChartFragment extends Fragment implements TrackDataListener {
private boolean metricUnits = true;
private boolean reportSpeed = true;
private boolean chartByDistance = true;
private boolean[] chartShow = new boolean[] {true, true, true, true, true};
// UI elements
private ChartView chartView;
private LinearLayout busyPane;
private ZoomControls zoomControls;
/**
@@ -91,7 +94,6 @@ public class ChartFragment extends Fragment implements TrackDataListener {
return;
}
busyPane.setVisibility(View.GONE);
zoomControls.setIsZoomInEnabled(chartView.canZoomIn());
zoomControls.setIsZoomOutEnabled(chartView.canZoomOut());
chartView.setShowPointer(isRecording());
@@ -113,9 +115,8 @@ public class ChartFragment extends Fragment implements TrackDataListener {
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.mytracks_charts, container, false);
busyPane = (LinearLayout) view.findViewById(R.id.elevation_busypane);
zoomControls = (ZoomControls) view.findViewById(R.id.elevation_zoom);
View view = inflater.inflate(R.layout.chart, container, false);
zoomControls = (ZoomControls) view.findViewById(R.id.chart_zoom_controls);
zoomControls.setOnZoomInClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -134,9 +135,10 @@ public class ChartFragment extends Fragment implements TrackDataListener {
@Override
public void onStart() {
super.onStart();
ViewGroup layout = (ViewGroup) getActivity().findViewById(R.id.elevation_chart);
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
ViewGroup layout = (ViewGroup) getActivity().findViewById(R.id.chart_view_layout);
@SuppressWarnings("deprecation")
LayoutParams layoutParams = new LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
layout.addView(chartView, layoutParams);
}
@@ -144,6 +146,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
public void onResume() {
super.onResume();
resumeTrackDataHub();
checkChartSettings();
getActivity().runOnUiThread(updateChart);
}
@@ -156,61 +159,9 @@ public class ChartFragment extends Fragment implements TrackDataListener {
@Override
public void onStop() {
super.onStop();
ViewGroup layout = (ViewGroup) getActivity().findViewById(R.id.elevation_chart);
ViewGroup layout = (ViewGroup) getActivity().findViewById(R.id.chart_view_layout);
layout.removeView(chartView);
}
/**
* Sets the chart view mode.
*
* @param mode the chart view mode
*/
public void setMode(Mode mode) {
if (chartView.getMode() != mode) {
chartView.setMode(mode);
reloadTrackDataHub();
}
}
/**
* Gets the chart view mode.
*/
public Mode getMode() {
return chartView.getMode();
}
/**
* Enables or disables the chart value series.
*
* @param index the index of the series
* @param enabled true to enable, false to disable
*/
public void setChartValueSeriesEnabled(int index, boolean enabled) {
chartView.setChartValueSeriesEnabled(index, enabled);
}
/**
* Returns true if the chart value series is enabled.
*
* @param index the index of the series
*/
public boolean isChartValueSeriesEnabled(int index) {
return chartView.isChartValueSeriesEnabled(index);
}
/**
* Returns true to report speed instead of pace.
*/
public boolean isReportSpeed() {
return reportSpeed;
}
/**
* Updates the chart.
*/
public void update() {
chartView.postInvalidate();
}
@Override
public void onProviderStateChange(ProviderState state) {
@@ -229,12 +180,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
@Override
public void onSelectedTrackChanged(Track track, boolean isRecording) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
busyPane.setVisibility(View.VISIBLE);
}
});
// We don't care.
}
@Override
@@ -344,6 +290,60 @@ public class ChartFragment extends Fragment implements TrackDataListener {
return true;
}
/**
* Checks the chart settings.
*/
private void checkChartSettings() {
boolean needUpdate = false;
if (chartByDistance != PreferencesUtils.getBoolean(getActivity(),
R.string.chart_by_distance_key, PreferencesUtils.CHART_BY_DISTANCE_DEFAULT)) {
chartByDistance = !chartByDistance;
chartView.setChartByDistance(chartByDistance);
reloadTrackDataHub();
needUpdate = true;
}
if (setSeriesEnabled(ChartView.ELEVATION_SERIES, PreferencesUtils.getBoolean(getActivity(),
R.string.chart_show_elevation_key, PreferencesUtils.CHART_SHOW_ELEVATION_DEFAULT))) {
needUpdate = true;
}
if (setSeriesEnabled(ChartView.SPEED_SERIES, PreferencesUtils.getBoolean(
getActivity(), R.string.chart_show_speed_key, PreferencesUtils.CHART_SHOW_SPEED_DEFAULT))) {
needUpdate = true;
}
if (setSeriesEnabled(ChartView.POWER_SERIES, PreferencesUtils.getBoolean(
getActivity(), R.string.chart_show_power_key, PreferencesUtils.CHART_SHOW_POWER_DEFAULT))) {
needUpdate = true;
}
if (setSeriesEnabled(ChartView.CADENCE_SERIES, PreferencesUtils.getBoolean(getActivity(),
R.string.chart_show_cadence_key, PreferencesUtils.CHART_SHOW_CADENCE_DEFAULT))) {
needUpdate = true;
}
if (setSeriesEnabled(ChartView.HEART_RATE_SERIES, PreferencesUtils.getBoolean(getActivity(),
R.string.chart_show_heart_rate_key, PreferencesUtils.CHART_SHOW_HEART_RATE_DEFAULT))) {
needUpdate = true;
}
if (needUpdate) {
chartView.postInvalidate();
}
}
/**
* Sets the series enabled value.
*
* @param index the series index
* @param value the value
* @return true if changed
*/
private boolean setSeriesEnabled(int index, boolean value) {
if (chartShow[index] != value) {
chartShow[index] = value;
chartView.setChartValueSeriesEnabled(index, value);
return true;
} else {
return false;
}
}
/**
* Resumes the trackDataHub. Needs to be synchronized because trackDataHub can be
* accessed by multiple threads.
@@ -358,16 +358,16 @@ public class ChartFragment extends Fragment implements TrackDataListener {
ListenerDataType.SAMPLED_OUT_POINT_UPDATES,
ListenerDataType.DISPLAY_PREFERENCES));
}
/**
* Pauses the trackDataHub. Needs to be synchronized because trackDataHub can be
* accessed by multiple threads.
* Pauses the trackDataHub. Needs to be synchronized because trackDataHub can
* be accessed by multiple threads.
*/
private synchronized void pauseTrackDataHub() {
trackDataHub.unregisterTrackDataListener(this);
trackDataHub = null;
}
/**
* Returns true if recording. Needs to be synchronized because trackDataHub
* can be accessed by multiple threads.
@@ -375,7 +375,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
private synchronized boolean isRecording() {
return trackDataHub != null && trackDataHub.isRecordingSelected();
}
/**
* Reloads the trackDataHub. Needs to be synchronized because trackDataHub can be
* accessed by multiple threads.
@@ -426,7 +426,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
double heartRate = Double.NaN;
// TODO: Use TripStatisticsBuilder
if (chartView.getMode() == Mode.BY_DISTANCE) {
if (chartByDistance) {
if (lastLocation != null) {
double distance = lastLocation.distanceTo(location) * UnitConversions.M_TO_KM;
if (metricUnits) {
@@ -518,4 +518,8 @@ public class ChartFragment extends Fragment implements TrackDataListener {
void setReportSpeed(boolean value) {
reportSpeed = value;
}
@VisibleForTesting
void setChartByDistance(boolean value) {
chartByDistance = value;
}
}
@@ -1,87 +0,0 @@
/*
* Copyright 2012 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.fragments;
import static com.google.android.apps.mytracks.Constants.CHART_TAB_TAG;
import com.google.android.apps.mytracks.ChartView;
import com.google.android.maps.mytracks.R;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.View;
import android.widget.CheckBox;
import android.widget.RadioGroup;
/**
* A DialogFragment to show chart settings.
*
* @author Jimmy Shih
*/
public class ChartSettingsDialogFragment extends DialogFragment {
public static final String CHART_SETTINGS_DIALOG_TAG = "chartSettingsDialog";
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final ChartFragment chartFragment = (ChartFragment) getActivity()
.getSupportFragmentManager().findFragmentByTag(CHART_TAB_TAG);
View view = getActivity().getLayoutInflater().inflate(R.layout.chart_settings, null);
final RadioGroup radioGroup = (RadioGroup) view.findViewById(R.id.chart_settings_x);
radioGroup.check(chartFragment.getMode() == ChartView.Mode.BY_DISTANCE
? R.id.chart_settings_by_distance : R.id.chart_settings_by_time);
final CheckBox[] checkBoxes = new CheckBox[ChartView.NUM_SERIES];
checkBoxes[ChartView.ELEVATION_SERIES] = (CheckBox) view.findViewById(
R.id.chart_settings_elevation);
checkBoxes[ChartView.SPEED_SERIES] = (CheckBox) view.findViewById(R.id.chart_settings_speed);
checkBoxes[ChartView.POWER_SERIES] = (CheckBox) view.findViewById(R.id.chart_settings_power);
checkBoxes[ChartView.CADENCE_SERIES] = (CheckBox) view.findViewById(
R.id.chart_settings_cadence);
checkBoxes[ChartView.HEART_RATE_SERIES] = (CheckBox) view.findViewById(
R.id.chart_settings_heart_rate);
// set checkboxes values
for (int i = 0; i < ChartView.NUM_SERIES; i++) {
checkBoxes[i].setChecked(chartFragment.isChartValueSeriesEnabled(i));
}
checkBoxes[ChartView.SPEED_SERIES].setText(chartFragment.isReportSpeed()
? R.string.stat_speed : R.string.stat_pace);
return new AlertDialog.Builder(getActivity())
.setCancelable(true)
.setNegativeButton(R.string.generic_cancel, null)
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
chartFragment.setMode(
radioGroup.getCheckedRadioButtonId() == R.id.chart_settings_by_distance
? ChartView.Mode.BY_DISTANCE : ChartView.Mode.BY_TIME);
for (int i = 0; i < ChartView.NUM_SERIES; i++) {
chartFragment.setChartValueSeriesEnabled(i, checkBoxes[i].isChecked());
}
chartFragment.update();
}
})
.setTitle(R.string.menu_chart_settings)
.setView(view)
.create();
}
}
@@ -16,22 +16,21 @@
package com.google.android.apps.mytracks.fragments;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.CheckUnitsUtils;
import com.google.android.apps.mytracks.TrackListActivity;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import java.util.Locale;
/**
* A DialogFragment to check preferred units.
*
*
* @author Jimmy Shih
*/
public class CheckUnitsDialogFragment extends DialogFragment {
@@ -39,31 +38,39 @@ public class CheckUnitsDialogFragment extends DialogFragment {
public static final String CHECK_UNITS_DIALOG_TAG = "checkUnitsDialog";
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
public void onCancel(DialogInterface arg0) {
onDone();
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Locale defaultLocale = Locale.getDefault();
boolean defaultMetric = !defaultLocale.equals(Locale.US) && !defaultLocale.equals(Locale.UK);
PreferencesUtils.setBoolean(getActivity(), R.string.metric_units_key, defaultMetric);
final String metric = getString(R.string.settings_stats_units_metric);
final String imperial = getString(R.string.settings_stats_units_imperial);
final CharSequence[] items = defaultMetric ? new CharSequence[] { metric, imperial }
: new CharSequence[] { imperial, metric };
return new AlertDialog.Builder(getActivity())
.setCancelable(true)
.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
CheckUnitsUtils.setCheckUnitsValue(getActivity());
}
})
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
CheckUnitsUtils.setCheckUnitsValue(getActivity());
int position = ((AlertDialog) dialog).getListView().getSelectedItemPosition();
SharedPreferences sharedPreferences = getActivity()
.getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(sharedPreferences.edit()
.putBoolean(getString(R.string.metric_units_key), position == 0));
int position = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
PreferencesUtils.setBoolean(
getActivity(), R.string.metric_units_key, items[position].equals(metric));
onDone();
}
})
.setSingleChoiceItems(new CharSequence[] { getString(R.string.preferred_units_metric),
getString(R.string.preferred_units_imperial) }, 0, null)
.setTitle(R.string.preferred_units_title)
.create();
.setSingleChoiceItems(items, 0, null)
.setTitle(R.string.settings_stats_units_title).create();
}
/**
* Tasks to perform when done.
*/
private void onDone() {
PreferencesUtils.setBoolean(getActivity(), R.string.show_check_units_dialog_key, false);
TrackListActivity trackListActivity = (TrackListActivity) getActivity();
trackListActivity.showStartupDialogs();
}
}
@@ -20,6 +20,7 @@ import com.google.android.apps.mytracks.MarkerListActivity;
import com.google.android.apps.mytracks.content.DescriptionGeneratorImpl;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.maps.mytracks.R;
import android.app.Dialog;
@@ -37,10 +38,12 @@ public class DeleteOneMarkerDialogFragment extends DialogFragment {
public static final String DELETE_ONE_MARKER_DIALOG_TAG = "deleteOneMarkerDialog";
private static final String KEY_MARKER_ID = "markerId";
private static final String KEY_TRACK_ID = "trackId";
public static DeleteOneMarkerDialogFragment newInstance(long markerId) {
public static DeleteOneMarkerDialogFragment newInstance(long markerId, long trackId) {
Bundle bundle = new Bundle();
bundle.putLong(KEY_MARKER_ID, markerId);
bundle.putLong(KEY_TRACK_ID, trackId);
DeleteOneMarkerDialogFragment deleteOneMarkerDialogFragment = new DeleteOneMarkerDialogFragment();
deleteOneMarkerDialogFragment.setArguments(bundle);
@@ -55,8 +58,11 @@ public class DeleteOneMarkerDialogFragment extends DialogFragment {
public void onClick(DialogInterface dialog, int which) {
MyTracksProviderUtils.Factory.get(getActivity()).deleteWaypoint(
getArguments().getLong(KEY_MARKER_ID), new DescriptionGeneratorImpl(getActivity()));
startActivity(new Intent(getActivity(), MarkerListActivity.class).addFlags(
Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
Intent intent = IntentUtils.newIntent(getActivity(), MarkerListActivity.class)
.putExtra(MarkerListActivity.EXTRA_TRACK_ID, getArguments().getLong(KEY_TRACK_ID));
startActivity(intent);
// Close the activity since its content can change after delete.
getActivity().finish();
}
});
}
@@ -19,6 +19,7 @@ package com.google.android.apps.mytracks.fragments;
import com.google.android.apps.mytracks.TrackListActivity;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.maps.mytracks.R;
import android.app.Dialog;
@@ -54,8 +55,10 @@ public class DeleteOneTrackDialogFragment extends DialogFragment {
public void onClick(DialogInterface dialog, int which) {
MyTracksProviderUtils.Factory.get(getActivity())
.deleteTrack(getArguments().getLong(KEY_TRACK_ID));
startActivity(new Intent(getActivity(), TrackListActivity.class).addFlags(
Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
Intent intent = IntentUtils.newIntent(getActivity(), TrackListActivity.class);
startActivity(intent);
// Close the activity since its content can change after delete.
getActivity().finish();
}
});
}
@@ -16,6 +16,7 @@
package com.google.android.apps.mytracks.fragments;
import com.google.android.apps.mytracks.TrackListActivity;
import com.google.android.apps.mytracks.util.EulaUtils;
import com.google.android.maps.mytracks.R;
@@ -49,11 +50,17 @@ public class EulaDialogFragment extends DialogFragment {
return eulaDialogFragment;
}
@Override
public void onCancel(DialogInterface arg0) {
if (!getArguments().getBoolean(KEY_HAS_ACCEPTED)) {
exitApp();
}
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
boolean hasAccepted = getArguments().getBoolean(KEY_HAS_ACCEPTED);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
.setCancelable(true)
.setMessage(EulaUtils.getEulaMessage(getActivity()))
.setTitle(R.string.eula_title);
@@ -63,24 +70,25 @@ public class EulaDialogFragment extends DialogFragment {
builder.setNegativeButton(R.string.eula_decline, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
getActivity().finish();
}
})
.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
getActivity().finish();
exitApp();
}
})
.setPositiveButton(R.string.eula_accept, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
EulaUtils.setEulaValue(getActivity());
new WelcomeDialogFragment().show(
getActivity().getSupportFragmentManager(), WelcomeDialogFragment.WELCOME_DIALOG_TAG);
TrackListActivity trackListActivity = (TrackListActivity) getActivity();
trackListActivity.showStartupDialogs();
}
});
}
return builder.create();
}
/**
* Exits the application.
*/
private void exitApp() {
getActivity().finish();
}
}
@@ -39,13 +39,13 @@ public class InstallEarthDialogFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setCancelable(true)
.setMessage(R.string.track_detail_install_earth_message)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startActivity(new Intent().setData(Uri.parse(SaveActivity.GOOGLE_EARTH_MARKET_URL)));
Intent intent = new Intent().setData(Uri.parse(SaveActivity.GOOGLE_EARTH_MARKET_URL));
startActivity(intent);
}
})
.create();
@@ -40,11 +40,13 @@ import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
@@ -59,6 +61,8 @@ import java.util.EnumSet;
public class MapFragment extends Fragment
implements View.OnTouchListener, View.OnClickListener, TrackDataListener {
public static final String MAP_FRAGMENT_TAG = "mapFragment";
private static final String KEY_CURRENT_LOCATION = "currentLocation";
private static final String KEY_KEEP_MY_LOCATION_VISIBLE = "keepMyLocationVisible";
@@ -85,11 +89,15 @@ public class MapFragment extends Fragment
// UI elements
private View mapViewContainer;
private MapOverlay mapOverlay;
private RelativeLayout screen;
private MapView mapView;
private LinearLayout messagePane;
private TextView messageText;
private LinearLayout busyPane;
private ImageButton myLocationImageButton;
private TextView messageTextView;
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(
@@ -98,15 +106,19 @@ public class MapFragment extends Fragment
mapOverlay = new MapOverlay(getActivity());
screen = (RelativeLayout) mapViewContainer.findViewById(R.id.screen);
mapView = (MapView) mapViewContainer.findViewById(R.id.map);
mapView = (MapView) mapViewContainer.findViewById(R.id.map_view);
mapView.requestFocus();
mapView.setOnTouchListener(this);
mapView.setBuiltInZoomControls(true);
mapView.getOverlays().add(mapOverlay);
messagePane = (LinearLayout) mapViewContainer.findViewById(R.id.messagepane);
messageText = (TextView) mapViewContainer.findViewById(R.id.messagetext);
busyPane = (LinearLayout) mapViewContainer.findViewById(R.id.busypane);
myLocationImageButton = (ImageButton) mapViewContainer.findViewById(R.id.map_my_location);
myLocationImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showMyLocation();
}
});
messageTextView = (TextView) mapViewContainer.findViewById(R.id.map_message);
return mapViewContainer;
}
@@ -153,10 +165,34 @@ public class MapFragment extends Fragment
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflator) {
menuInflator.inflate(R.menu.map, menu);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
int titleId = R.string.menu_satellite_mode;
if (mapView != null) {
titleId = mapView.isSatellite() ? R.string.menu_map_mode : R.string.menu_satellite_mode;
}
menu.findItem(R.id.map_satellite_mode).setTitle(titleId);
super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
if (mapView != null && menuItem.getItemId() == R.id.map_satellite_mode) {
mapView.setSatellite(!mapView.isSatellite());
return true;
}
return super.onOptionsItemSelected(menuItem);
}
/**
* Shows my location.
*/
public void showMyLocation() {
private void showMyLocation() {
updateTrackDataHub();
keepMyLocationVisible = true;
zoomToMyLocation = true;
@@ -206,22 +242,6 @@ public class MapFragment extends Fragment
}
}
/**
* Returns true if in satellite mode.
*/
public boolean isSatelliteView() {
return mapView.isSatellite();
}
/**
* Sets the satellite mode
*
* @param enabled true for satellite mode, false for map mode
*/
public void setSatelliteView(boolean enabled) {
mapView.setSatellite(enabled);
}
@Override
public boolean onTouch(View view, MotionEvent event) {
if (keepMyLocationVisible && event.getAction() == MotionEvent.ACTION_MOVE) {
@@ -238,8 +258,9 @@ public class MapFragment extends Fragment
@Override
public void onClick(View v) {
if (v == messagePane) {
startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
if (v == messageTextView) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
}
@@ -269,21 +290,20 @@ public class MapFragment extends Fragment
@Override
public void run() {
if (messageId != -1) {
messageText.setText(messageId);
messagePane.setVisibility(View.VISIBLE);
messageTextView.setText(messageId);
messageTextView.setVisibility(View.VISIBLE);
if (isGpsDisabled) {
Toast.makeText(getActivity(), R.string.gps_not_found, Toast.LENGTH_LONG).show();
// Click to show the location source settings
messagePane.setOnClickListener(MapFragment.this);
messageTextView.setOnClickListener(MapFragment.this);
} else {
messagePane.setOnClickListener(null);
messageTextView.setOnClickListener(null);
}
} else {
messagePane.setVisibility(View.GONE);
messageTextView.setVisibility(View.GONE);
}
screen.requestLayout();
}
});
}
@@ -309,9 +329,7 @@ public class MapFragment extends Fragment
boolean hasTrack = track != null;
mapOverlay.setTrackDrawingEnabled(hasTrack);
if (hasTrack) {
busyPane.setVisibility(View.VISIBLE);
if (hasTrack) {
synchronized (this) {
/*
* Synchronize to prevent race condition in changing markerTrackId
@@ -321,7 +339,6 @@ public class MapFragment extends Fragment
updateMap(track);
}
mapOverlay.setShowEndMarker(!isRecording);
busyPane.setVisibility(View.GONE);
}
mapView.invalidate();
}
@@ -0,0 +1,122 @@
/*
* Copyright 2012 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.fragments;
import com.google.android.apps.mytracks.MarkerEditActivity;
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.TrackRecordingServiceConnectionUtils;
import com.google.android.maps.mytracks.R;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.View;
import android.widget.Button;
import android.widget.RadioGroup;
/**
* A DialogFragment to add a marker.
*
* @author Jimmy Shih
*/
public class MarkerAddDialogFragment extends DialogFragment {
public static final String MARKER_ADD_DIALOG_TAG = "markerAddDialog";
private static final String KEY_TRACK_ID = "trackId";
private TrackRecordingServiceConnection trackRecordingServiceConnection;
private RadioGroup radioGroup;
private Button moreOptions;
/**
* Creates a new instance of {@link MarkerAddDialogFragment}.
*
* @param trackId the track id
*/
public static MarkerAddDialogFragment newInstance(long trackId) {
Bundle bundle = new Bundle();
bundle.putLong(KEY_TRACK_ID, trackId);
MarkerAddDialogFragment markerAddDialogFragment = new MarkerAddDialogFragment();
markerAddDialogFragment.setArguments(bundle);
return markerAddDialogFragment;
}
@Override
public void onCreate(Bundle arg0) {
super.onCreate(arg0);
trackRecordingServiceConnection = new TrackRecordingServiceConnection(getActivity(), null);
}
@Override
public void onResume() {
super.onResume();
TrackRecordingServiceConnectionUtils.resume(getActivity(), trackRecordingServiceConnection);
}
@Override
public void onDestroy() {
super.onDestroy();
trackRecordingServiceConnection.unbind();
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View view = getActivity().getLayoutInflater().inflate(R.layout.marker_add, null);
radioGroup = (RadioGroup) view.findViewById(R.id.marker_add_type);
moreOptions = (Button) view.findViewById(R.id.marker_add_more_options);
moreOptions.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean statisticsMarker = radioGroup.getCheckedRadioButtonId()
== R.id.marker_add_statistics;
Intent intent = IntentUtils.newIntent(getActivity(), MarkerEditActivity.class);
intent.putExtra(MarkerEditActivity.EXTRA_TRACK_ID, getArguments().getLong(KEY_TRACK_ID));
intent.putExtra(MarkerEditActivity.EXTRA_STATISTICS_MARKER, statisticsMarker);
startActivity(intent);
dismiss();
}
});
boolean pickStatisticsMarker = PreferencesUtils.getBoolean(getActivity(),
R.string.pick_statistics_marker_key, PreferencesUtils.PICK_STATISTICS_MARKER_DEFAULT);
radioGroup.check(pickStatisticsMarker ? R.id.marker_add_statistics : R.id.marker_add_waypoint);
return new AlertDialog.Builder(getActivity())
.setNegativeButton(R.string.generic_cancel, null)
.setPositiveButton(R.string.generic_add, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
boolean statisticsMarker = radioGroup.getCheckedRadioButtonId()
== R.id.marker_add_statistics;
PreferencesUtils.setBoolean(
getActivity(), R.string.pick_statistics_marker_key, statisticsMarker);
TrackRecordingServiceConnectionUtils.addMarker(getActivity(),
trackRecordingServiceConnection,
statisticsMarker ? WaypointCreationRequest.DEFAULT_STATISTICS
: WaypointCreationRequest.DEFAULT_WAYPOINT);
}
})
.setTitle(R.string.menu_insert_marker)
.setView(view)
.create();
}
}
@@ -17,14 +17,14 @@
package com.google.android.apps.mytracks.fragments;
import com.google.android.apps.mytracks.MyTracksApplication;
import com.google.android.apps.mytracks.StatsUtilities;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TrackDataHub;
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
import com.google.android.apps.mytracks.content.TrackDataListener;
import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.apps.mytracks.util.StatsUtils;
import com.google.android.maps.mytracks.R;
import android.location.Location;
@@ -34,7 +34,6 @@ import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ScrollView;
import java.util.EnumSet;
@@ -46,20 +45,24 @@ import java.util.EnumSet;
*/
public class StatsFragment extends Fragment implements TrackDataListener {
public static final String STATS_FRAGMENT_TAG = "statsFragment";
private static final String TAG = StatsFragment.class.getSimpleName();
private StatsUtilities statsUtilities;
private TrackDataHub trackDataHub;
private UiUpdateThread uiUpdateThread;
// The start time of the current track.
private long startTime = -1L;
private Location lastLocation = null;
private TripStatistics lastTripStatistics = null;
// A runnable to update the total time field.
private final Runnable updateTotalTime = new Runnable() {
public void run() {
if (isRecording()) {
statsUtilities.setTime(R.id.total_time_register, System.currentTimeMillis() - startTime);
StatsUtils.setTotalTimeValue(getActivity(), System.currentTimeMillis() - startTime);
}
}
};
@@ -68,11 +71,11 @@ public class StatsFragment extends Fragment implements TrackDataListener {
* A thread that updates the total time field every second.
*/
private class UiUpdateThread extends Thread {
@Override
public void run() {
Log.d(TAG, "UI update thread started");
while (PreferencesUtils.getRecordingTrackId(getActivity()) != -1L) {
while (PreferencesUtils.getLong(getActivity(), R.string.recording_track_id_key)
!= PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) {
getActivity().runOnUiThread(updateTotalTime);
try {
Thread.sleep(1000L);
@@ -85,12 +88,6 @@ public class StatsFragment extends Fragment implements TrackDataListener {
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
statsUtilities = new StatsUtilities(getActivity());
}
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -100,10 +97,7 @@ public class StatsFragment extends Fragment implements TrackDataListener {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
ScrollView scrollView = (ScrollView) getActivity().findViewById(R.id.scrolly);
scrollView.setScrollBarStyle(ScrollView.SCROLLBARS_OUTSIDE_INSET);
updateLabels();
setLocationUnknown();
updateUi();
}
@Override
@@ -128,7 +122,8 @@ public class StatsFragment extends Fragment implements TrackDataListener {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
setLocationUnknown();
lastLocation = null;
StatsUtils.setLocationValues(getActivity(), lastLocation, true);
}
});
}
@@ -140,11 +135,8 @@ public class StatsFragment extends Fragment implements TrackDataListener {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if (location != null) {
setLocation(location);
} else {
setLocationUnknown();
}
lastLocation = location;
StatsUtils.setLocationValues(getActivity(), lastLocation, true);
}
});
}
@@ -172,16 +164,18 @@ public class StatsFragment extends Fragment implements TrackDataListener {
@Override
public void run() {
if (track == null || track.getStatistics() == null) {
statsUtilities.setAllToUnknown();
lastLocation = null;
lastTripStatistics = null;
updateUi();
return;
}
lastTripStatistics = track.getStatistics();
startTime = track.getStatistics().getStartTime();
if (!isRecording()) {
statsUtilities.setTime(R.id.total_time_register, track.getStatistics().getTotalTime());
setLocationUnknown();
lastLocation = null;
}
statsUtilities.setAllStats(track.getStatistics());
updateUi();
}
});
}
@@ -227,30 +221,22 @@ public class StatsFragment extends Fragment implements TrackDataListener {
}
@Override
public boolean onUnitsChanged(boolean metric) {
if (statsUtilities.isMetricUnits() == metric) {
return false;
}
statsUtilities.setMetricUnits(metric);
public boolean onUnitsChanged(final boolean metric) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
updateLabels();
updateUi();
}
});
return true;
}
@Override
public boolean onReportSpeedChanged(boolean speed) {
if (statsUtilities.isReportSpeed() == speed) {
return false;
}
statsUtilities.setReportSpeed(speed);
public boolean onReportSpeedChanged(final boolean speed) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
updateLabels();
updateUi();
}
});
return true;
@@ -287,33 +273,10 @@ public class StatsFragment extends Fragment implements TrackDataListener {
}
/**
* Updates the labels.
* Updates the UI.
*/
private void updateLabels() {
statsUtilities.updateUnits();
statsUtilities.setSpeedLabel(R.id.speed_label, R.string.stat_speed, R.string.stat_pace);
statsUtilities.setSpeedLabels();
}
/**
* Sets the current location.
*
* @param location the current location
*/
private void setLocation(Location location) {
statsUtilities.setAltitude(R.id.elevation_register, location.getAltitude());
statsUtilities.setLatLong(R.id.latitude_register, location.getLatitude());
statsUtilities.setLatLong(R.id.longitude_register, location.getLongitude());
statsUtilities.setSpeed(R.id.speed_register, location.getSpeed() * UnitConversions.MS_TO_KMH);
}
/**
* Sets the current location to unknown.
*/
private void setLocationUnknown() {
statsUtilities.setUnknown(R.id.elevation_register);
statsUtilities.setUnknown(R.id.latitude_register);
statsUtilities.setUnknown(R.id.longitude_register);
statsUtilities.setUnknown(R.id.speed_register);
private void updateUi() {
StatsUtils.setTripStatisticsValues(getActivity(), lastTripStatistics);
StatsUtils.setLocationValues(getActivity(), lastLocation, true);
}
}
@@ -16,6 +16,8 @@
package com.google.android.apps.mytracks.fragments;
import com.google.android.apps.mytracks.TrackListActivity;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.app.AlertDialog;
@@ -23,7 +25,6 @@ import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.View;
/**
* A DialogFrament to show the welcome info.
@@ -34,30 +35,28 @@ public class WelcomeDialogFragment extends DialogFragment {
public static final String WELCOME_DIALOG_TAG = "welcomeDialog";
@Override
public void onCancel(DialogInterface arg0) {
onDone();
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View view = getActivity().getLayoutInflater().inflate(R.layout.welcome, null);
return new AlertDialog.Builder(getActivity())
.setCancelable(true)
.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
checkUnits();
}
})
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
checkUnits();
onDone();
}
})
.setTitle(R.string.welcome_title)
.setView(view)
.setMessage(R.string.welcome_message)
.create();
}
private void checkUnits() {
new CheckUnitsDialogFragment().show(
getActivity().getSupportFragmentManager(), CheckUnitsDialogFragment.CHECK_UNITS_DIALOG_TAG);
private void onDone() {
PreferencesUtils.setBoolean(getActivity(), R.string.show_welcome_dialog_key, false);
TrackListActivity trackListActivity = (TrackListActivity) getActivity();
trackListActivity.showStartupDialogs();
}
}
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.TrackListActivity;
import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
@@ -93,8 +94,8 @@ public class RestoreActivity extends Activity {
public void onAsyncTaskCompleted(boolean success, int messageId) {
removeDialog(DIALOG_PROGRESS_ID);
Toast.makeText(this, messageId, success ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG).show();
startActivity(new Intent(this, TrackListActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
Intent intent = IntentUtils.newIntent(this, TrackListActivity.class);
startActivity(intent);
}
/**
@@ -17,6 +17,7 @@
package com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.util.FileUtils;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
@@ -76,8 +77,9 @@ public class RestoreChooserActivity extends Activity {
}
if (backupDates.length == 1) {
startActivity(new Intent(this, RestoreActivity.class)
.putExtra(RestoreActivity.EXTRA_DATE, backupDates[0].getTime()));
Intent intent = IntentUtils.newIntent(this, RestoreActivity.class)
.putExtra(RestoreActivity.EXTRA_DATE, backupDates[0].getTime());
startActivity(intent);
finish();
return;
}
@@ -100,8 +102,10 @@ public class RestoreChooserActivity extends Activity {
.setItems(items, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startActivity(new Intent(RestoreChooserActivity.this, RestoreActivity.class).putExtra(
RestoreActivity.EXTRA_DATE, backupDates[which].getTime()));
Intent intent = IntentUtils.newIntent(
RestoreChooserActivity.this, RestoreActivity.class)
.putExtra(RestoreActivity.EXTRA_DATE, backupDates[which].getTime());
startActivity(intent);
finish();
}
})
@@ -19,6 +19,7 @@ import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendActivity;
import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendAsyncTask;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.maps.mytracks.R;
import android.content.Intent;
@@ -43,7 +44,7 @@ public class SendDocsActivity extends AbstractSendActivity {
@Override
protected void startNextActivity(boolean success, boolean isCancel) {
sendRequest.setDocsSuccess(success);
Intent intent = new Intent(this, UploadResultActivity.class)
Intent intent = IntentUtils.newIntent(this, UploadResultActivity.class)
.putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
startActivity(intent);
finish();
@@ -21,6 +21,7 @@ import com.google.android.apps.mytracks.io.gdata.docs.DocumentsClient;
import com.google.android.apps.mytracks.io.gdata.docs.SpreadsheetsClient;
import com.google.android.apps.mytracks.io.gdata.docs.SpreadsheetsClient.WorksheetEntry;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.ResourceUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
@@ -33,7 +34,6 @@ import com.google.wireless.gdata.parser.ParseException;
import com.google.wireless.gdata2.client.AuthenticationException;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import java.io.BufferedReader;
@@ -270,10 +270,8 @@ public class SendDocsUtils {
Track track, String spreadsheetId, String worksheetId, String authToken, Context context)
throws IOException {
String worksheetUri = String.format(GET_WORKSHEET_URI, spreadsheetId, worksheetId);
SharedPreferences prefs = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
boolean metricUnits = prefs.getBoolean(context.getString(R.string.metric_units_key), true);
boolean metricUnits = PreferencesUtils.getBoolean(
context, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
addRow(worksheetUri, getRowContent(track, metricUnits, context), authToken);
}
@@ -102,7 +102,7 @@ public class CsvTrackWriter implements TrackFormatWriter {
@Override
public void writeBeginWaypoints() {
writeCommaSeparatedLine(context.getString(R.string.generic_name),
context.getString(R.string.marker_edit_marker_type_hint),
context.getString(R.string.marker_edit_waypoint_marker_type_hint),
context.getString(R.string.generic_description),
context.getString(R.string.description_location_latitude),
context.getString(R.string.description_location_longitude),
@@ -20,6 +20,7 @@ import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendActivity;
import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendAsyncTask;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.maps.mytracks.R;
import com.google.common.annotations.VisibleForTesting;
@@ -45,10 +46,9 @@ public class SendFusionTablesActivity extends AbstractSendActivity {
@Override
protected void startNextActivity(boolean success, boolean isCancel) {
sendRequest.setFusionTablesSuccess(success);
Class<?> next = getNextClass(sendRequest, isCancel);
Intent intent = new Intent(this, next).putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
Intent intent = IntentUtils.newIntent(this, next)
.putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
startActivity(intent);
finish();
}
@@ -14,6 +14,7 @@ import com.google.android.apps.mytracks.stats.DoubleBuffer;
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.SystemUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
@@ -32,7 +33,6 @@ import android.accounts.AccountManager;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.location.Location;
import android.util.Log;
@@ -205,9 +205,8 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
private boolean uploadAllTrackPoints(Track track) {
Cursor locationsCursor = null;
try {
SharedPreferences prefs = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
boolean metricUnits = prefs.getBoolean(context.getString(R.string.metric_units_key), true);
boolean metricUnits = PreferencesUtils.getBoolean(
context, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
locationsCursor = myTracksProviderUtils.getLocationsCursor(trackId, 0, -1, false);
if (locationsCursor == null) {
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks.io.maps;
import com.google.android.apps.mytracks.io.gdata.maps.MapsMapMetadata;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.maps.mytracks.R;
import com.google.common.annotations.VisibleForTesting;
@@ -67,11 +68,11 @@ public class ChooseMapActivity extends Activity {
}
MapsMapMetadata mapData = getItem(position).getMapData();
TextView title = (TextView) convertView.findViewById(R.id.choose_map_list_item_title);
TextView title = (TextView) convertView.findViewById(R.id.choose_map_item_title);
title.setText(mapData.getTitle());
TextView description = (TextView) convertView.findViewById(
R.id.choose_map_list_item_description);
R.id.choose_map_item_description);
String descriptionText = mapData.getDescription();
if (descriptionText == null || descriptionText.equals("")) {
description.setVisibility(View.GONE);
@@ -81,7 +82,7 @@ public class ChooseMapActivity extends Activity {
}
TextView searchStatus = (TextView) convertView.findViewById(
R.id.choose_map_list_item_search_status);
R.id.choose_map_item_search_status);
searchStatus.setTextColor(mapData.getSearchable() ? Color.RED : Color.GREEN);
searchStatus.setText(mapData.getSearchable() ? R.string.maps_list_public_label
: R.string.maps_list_unlisted_label);
@@ -209,7 +210,7 @@ public class ChooseMapActivity extends Activity {
*/
private void startNextActivity(String mapId) {
sendRequest.setMapId(mapId);
Intent intent = new Intent(this, SendMapsActivity.class)
Intent intent = IntentUtils.newIntent(this, SendMapsActivity.class)
.putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
startActivity(intent);
finish();
@@ -21,6 +21,7 @@ import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendActivity;
import com.google.android.apps.mytracks.io.sendtogoogle.AbstractSendAsyncTask;
import com.google.android.apps.mytracks.io.sendtogoogle.SendRequest;
import com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.maps.mytracks.R;
import com.google.common.annotations.VisibleForTesting;
@@ -47,10 +48,9 @@ public class SendMapsActivity extends AbstractSendActivity {
@Override
protected void startNextActivity(boolean success, boolean isCancel) {
sendRequest.setMapsSuccess(success);
Class<?> next = getNextClass(sendRequest, isCancel);
Intent intent = new Intent(this, next).putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
Intent intent = IntentUtils.newIntent(this, next)
.putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
startActivity(intent);
finish();
}
@@ -31,6 +31,7 @@ import com.google.android.apps.mytracks.io.sendtogoogle.SendToGoogleUtils;
import com.google.android.apps.mytracks.stats.DoubleBuffer;
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.common.gdata.AndroidXmlParserFactory;
import com.google.android.maps.mytracks.R;
@@ -44,7 +45,6 @@ import android.accounts.AccountManager;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.location.Location;
import android.util.Log;
@@ -224,15 +224,13 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask {
mapId = chooseMapId;
return true;
} else {
SharedPreferences sharedPreferences = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
boolean mapPublic = sharedPreferences.getBoolean(
context.getString(R.string.default_map_public_key), true);
boolean defaultMapPublic = PreferencesUtils.getBoolean(
context, R.string.default_map_public_key, PreferencesUtils.DEFAULT_MAP_PUBLIC_DEFAULT);
try {
String description = track.getCategory() + "\n" + track.getDescription() + "\n"
+ context.getString(R.string.send_google_by_my_tracks, "", "");
mapId = SendMapsUtils.createNewMap(
track.getName(), description, mapPublic, mapsClient, authToken);
track.getName(), description, defaultMapPublic, mapsClient, authToken);
} catch (ParseException e) {
Log.d(TAG, "Unable to create a new map", e);
return false;
@@ -257,9 +255,8 @@ public class SendMapsAsyncTask extends AbstractSendAsyncTask {
boolean uploadAllTrackPoints(Track track) {
Cursor locationsCursor = null;
try {
SharedPreferences prefs = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
boolean metricUnits = prefs.getBoolean(context.getString(R.string.metric_units_key), true);
boolean metricUnits = PreferencesUtils.getBoolean(
context, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
locationsCursor = myTracksProviderUtils.getLocationsCursor(trackId, 0, -1, false);
if (locationsCursor == null) {
@@ -24,7 +24,8 @@ import com.google.android.apps.mytracks.io.gdata.docs.SpreadsheetsClient;
import com.google.android.apps.mytracks.io.gdata.maps.MapsConstants;
import com.google.android.apps.mytracks.io.maps.ChooseMapActivity;
import com.google.android.apps.mytracks.io.maps.SendMapsActivity;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.accounts.Account;
@@ -36,11 +37,8 @@ import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.util.Log;
@@ -92,8 +90,8 @@ public class AccountChooserActivity extends Activity {
return;
}
SharedPreferences prefs = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
String preferredAccount = prefs.getString(getString(R.string.preferred_account_key), "");
String preferredAccount = PreferencesUtils.getString(this, R.string.preferred_account_key,
PreferencesUtils.PREFERRED_ACCOUNT_DEFAULT);
selectedAccountIndex = 0;
for (int i = 0; i < accounts.length; i++) {
@@ -165,12 +163,8 @@ public class AccountChooserActivity extends Activity {
.setPositiveButton(R.string.generic_ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Account account = accounts[selectedAccountIndex];
SharedPreferences sharedPreferences = getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
Editor editor = sharedPreferences.edit();
editor.putString(getString(R.string.preferred_account_key), account.name);
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
PreferencesUtils.setString(
AccountChooserActivity.this, R.string.preferred_account_key, account.name);
sendRequest.setAccount(account);
getPermission(MapsConstants.SERVICE_NAME, sendRequest.isSendMaps(), mapsCallback);
}
@@ -294,7 +288,7 @@ public class AccountChooserActivity extends Activity {
} else {
next = UploadResultActivity.class;
}
Intent intent = new Intent(this, next)
Intent intent = IntentUtils.newIntent(this, next)
.putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
startActivity(intent);
finish();
@@ -15,21 +15,19 @@
*/
package com.google.android.apps.mytracks.io.sendtogoogle;
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.fusiontables.SendFusionTablesUtils;
import com.google.android.apps.mytracks.io.maps.SendMapsUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import com.google.common.annotations.VisibleForTesting;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
@@ -49,7 +47,7 @@ public class UploadResultActivity extends Activity {
private SendRequest sendRequest;
private Track track;
private String shareUrl;
private Dialog dialog;
private Dialog resultDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -169,29 +167,28 @@ public class UploadResultActivity extends Activity {
}
});
}
dialog = builder.create();
return dialog;
resultDialog = builder.create();
return resultDialog;
}
/**
* Starts an activity to share the url.
*
*
* @param url the url
*/
private void startShareUrlActivity(String url) {
SharedPreferences prefs = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
boolean shareUrlOnly = prefs.getBoolean(getString(R.string.share_url_only_key), false);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType(TEXT_PLAIN_TYPE);
intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_track_subject));
intent.putExtra(Intent.EXTRA_TEXT,
shareUrlOnly ? url : getString(R.string.share_track_url_body_format, url));
boolean shareUrlOnly = PreferencesUtils.getBoolean(
this, R.string.share_url_only_key, PreferencesUtils.SHARE_URL_ONLY_DEFAULT);
Intent intent = new Intent(Intent.ACTION_SEND)
.setType(TEXT_PLAIN_TYPE)
.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_track_subject))
.putExtra(Intent.EXTRA_TEXT,
shareUrlOnly ? url : getString(R.string.share_track_url_body_format, url));
startActivity(Intent.createChooser(intent, getString(R.string.share_track_picker_title)));
}
@VisibleForTesting
Dialog getDialog() {
return dialog;
return resultDialog;
}
}
@@ -15,20 +15,17 @@
*/
package com.google.android.apps.mytracks.io.sendtogoogle;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.util.AnalyticsUtils;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import com.google.common.annotations.VisibleForTesting;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
@@ -152,16 +149,18 @@ public class UploadServiceChooserActivity extends Activity {
*/
@VisibleForTesting
void initState() {
SharedPreferences prefs = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
boolean pickExistingMap = prefs.getBoolean(getString(R.string.pick_existing_map_key), false);
boolean pickExistingMap = PreferencesUtils.getBoolean(
this, R.string.pick_existing_map_key, PreferencesUtils.PICK_EXISTING_MAP_DEFAULT);
newMapRadioButton.setChecked(!pickExistingMap);
existingMapRadioButton.setChecked(pickExistingMap);
mapsCheckBox.setChecked(prefs.getBoolean(getString(R.string.send_to_maps_key), true));
fusionTablesCheckBox.setChecked(
prefs.getBoolean(getString(R.string.send_to_fusion_tables_key), true));
docsCheckBox.setChecked(prefs.getBoolean(getString(R.string.send_to_docs_key), true));
mapsCheckBox.setChecked(PreferencesUtils.getBoolean(
this, R.string.send_to_maps_key, PreferencesUtils.SEND_TO_MAPS_DEFAULT));
fusionTablesCheckBox.setChecked(PreferencesUtils.getBoolean(
this, R.string.send_to_fusion_tables_key, PreferencesUtils.SEND_TO_FUSION_TABLES_DEFAULT));
docsCheckBox.setChecked(PreferencesUtils.getBoolean(
this, R.string.send_to_docs_key, PreferencesUtils.SEND_TO_DOCS_DEFAULT));
}
/**
@@ -194,16 +193,13 @@ public class UploadServiceChooserActivity extends Activity {
*/
@VisibleForTesting
void saveState() {
SharedPreferences prefs = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putBoolean(
getString(R.string.pick_existing_map_key), existingMapRadioButton.isChecked());
PreferencesUtils.setBoolean(
this, R.string.pick_existing_map_key, existingMapRadioButton.isChecked());
if (sendRequest.isShowAll()) {
editor.putBoolean(getString(R.string.send_to_maps_key), sendMaps());
editor.putBoolean(getString(R.string.send_to_fusion_tables_key), sendFusionTables());
editor.putBoolean(getString(R.string.send_to_docs_key), sendDocs());
PreferencesUtils.setBoolean(this, R.string.send_to_maps_key, sendMaps());
PreferencesUtils.setBoolean(this, R.string.send_to_fusion_tables_key, sendFusionTables());
PreferencesUtils.setBoolean(this, R.string.send_to_docs_key, sendDocs());
}
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
}
/**
@@ -237,7 +233,7 @@ public class UploadServiceChooserActivity extends Activity {
sendRequest.setSendFusionTables(sendFusionTables());
sendRequest.setSendDocs(sendDocs());
sendRequest.setNewMap(!existingMapRadioButton.isChecked());
Intent intent = new Intent(this, AccountChooserActivity.class)
Intent intent = IntentUtils.newIntent(this, AccountChooserActivity.class)
.putExtra(SendRequest.SEND_REQUEST_KEY, sendRequest);
startActivity(intent);
finish();
@@ -42,7 +42,6 @@ public class DynamicSpeedTrackPathDescriptor implements TrackPathDescriptor,
private int slowSpeed;
private int normalSpeed;
private int speedMargin;
private final int speedMarginDefault;
private double averageMovingSpeed;
private final Context context;
@VisibleForTesting
@@ -50,29 +49,11 @@ public class DynamicSpeedTrackPathDescriptor implements TrackPathDescriptor,
public DynamicSpeedTrackPathDescriptor(Context context) {
this.context = context;
speedMarginDefault = Integer.parseInt(context
.getString(R.string.color_mode_dynamic_percentage_default));
SharedPreferences prefs = context.getSharedPreferences(Constants.SETTINGS_NAME,
Context.MODE_PRIVATE);
context.getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE)
.registerOnSharedPreferenceChangeListener(this);
if (prefs == null) {
speedMargin = speedMarginDefault;
return;
}
prefs.registerOnSharedPreferenceChangeListener(this);
speedMargin = getSpeedMargin(prefs);
}
@VisibleForTesting
int getSpeedMargin(SharedPreferences sharedPreferences) {
try {
return Integer.parseInt(sharedPreferences.getString(
context.getString(R.string.track_color_mode_dynamic_speed_variation_key),
Integer.toString(speedMarginDefault)));
} catch (NumberFormatException e) {
return speedMarginDefault;
}
speedMargin = PreferencesUtils.getInt(context, R.string.track_color_mode_percentage_key,
PreferencesUtils.TRACK_COLOR_MODE_PERCENTAGE_DEFAULT);
}
/**
@@ -98,23 +79,16 @@ public class DynamicSpeedTrackPathDescriptor implements TrackPathDescriptor,
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Log.d(TAG, "DynamicSpeedTrackPathDescriptor: onSharedPreferences changed " + key);
if (key == null
|| !key.equals(context.getString(R.string.track_color_mode_dynamic_speed_variation_key))) { return; }
SharedPreferences prefs = context.getSharedPreferences(Constants.SETTINGS_NAME,
Context.MODE_PRIVATE);
if (prefs == null) {
speedMargin = speedMarginDefault;
return;
if (PreferencesUtils.getKey(context, R.string.track_color_mode_percentage_key).equals(key)) {
speedMargin = PreferencesUtils.getInt(context, R.string.track_color_mode_percentage_key,
PreferencesUtils.TRACK_COLOR_MODE_PERCENTAGE_DEFAULT);
}
speedMargin = getSpeedMargin(prefs);
}
@Override
public boolean needsRedraw() {
long selectedTrackId = PreferencesUtils.getSelectedTrackId(context);
if (selectedTrackId == -1L) {
long selectedTrackId = PreferencesUtils.getLong(context, R.string.selected_track_id_key);
if (selectedTrackId == PreferencesUtils.SELECTED_TRACK_ID_DEFAULT) {
// Could not find track.
return false;
}
@@ -13,104 +13,66 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.maps;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.util.Log;
/**
* A fixed speed path descriptor.
*
*
* @author Vangelis S.
*/
public class FixedSpeedTrackPathDescriptor implements TrackPathDescriptor, OnSharedPreferenceChangeListener {
public class FixedSpeedTrackPathDescriptor
implements TrackPathDescriptor, OnSharedPreferenceChangeListener {
private int slowSpeed;
private int normalSpeed;
private final int slowDefault;
private final int normalDefault;
private final Context context;
public FixedSpeedTrackPathDescriptor(Context context) {
this.context = context;
slowDefault = Integer.parseInt(context.getString(R.string.color_mode_fixed_slow_default));
normalDefault = Integer.parseInt(context.getString(R.string.color_mode_fixed_medium_default));
SharedPreferences prefs = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
if (prefs == null) {
slowSpeed = slowDefault;
normalSpeed = normalDefault;
return;
}
prefs.registerOnSharedPreferenceChangeListener(this);
try {
slowSpeed = Integer.parseInt(prefs.getString(context.getString(
R.string.track_color_mode_fixed_speed_slow_key), Integer.toString(slowDefault)));
} catch (NumberFormatException e) {
slowSpeed = slowDefault;
}
try {
normalSpeed = Integer.parseInt(prefs.getString(context.getString(
R.string.track_color_mode_fixed_speed_medium_key), Integer.toString(normalDefault)));
} catch (NumberFormatException e) {
normalSpeed = normalDefault;
}
context.getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE)
.registerOnSharedPreferenceChangeListener(this);
slowSpeed = PreferencesUtils.getInt(context, R.string.track_color_mode_slow_key,
PreferencesUtils.TRACK_COLOR_MODE_SLOW_DEFAULT);
normalSpeed = PreferencesUtils.getInt(context, R.string.track_color_mode_medium_key,
PreferencesUtils.TRACK_COLOR_MODE_MEDIUM_DEFAULT);
}
/**
* Gets the slow speed for reference.
*
* @return The speed limit considered as slow.
*/
public int getSlowSpeed() {
return slowSpeed;
}
/**
* Gets the normal speed for reference.
*
* @return The speed limit considered as normal.
*/
public int getNormalSpeed() {
return normalSpeed;
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Log.d(TAG, "FixedSpeedTrackPathDescriptor: onSharedPreferences changed " + key);
if (key == null
|| (!key.equals(context.getString(R.string.track_color_mode_fixed_speed_slow_key))
&& !key.equals(context.getString(R.string.track_color_mode_fixed_speed_medium_key)))) {
return;
}
SharedPreferences prefs = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
if (prefs == null) {
slowSpeed = slowDefault;
normalSpeed = normalDefault;
return;
}
try {
slowSpeed = Integer.parseInt(prefs.getString(context.getString(
R.string.track_color_mode_fixed_speed_slow_key), Integer.toString(slowDefault)));
} catch (NumberFormatException e) {
slowSpeed = slowDefault;
}
try {
normalSpeed = Integer.parseInt(prefs.getString(context.getString(
R.string.track_color_mode_fixed_speed_medium_key), Integer.toString(normalDefault)));
} catch (NumberFormatException e) {
normalSpeed = normalDefault;
if (PreferencesUtils.getKey(context, R.string.track_color_mode_slow_key).equals(key)) {
slowSpeed = PreferencesUtils.getInt(context, R.string.track_color_mode_slow_key,
PreferencesUtils.TRACK_COLOR_MODE_SLOW_DEFAULT);
} else if (PreferencesUtils.getKey(context, R.string.track_color_mode_medium_key).equals(key)) {
normalSpeed = PreferencesUtils.getInt(context, R.string.track_color_mode_medium_key,
PreferencesUtils.TRACK_COLOR_MODE_MEDIUM_DEFAULT);
}
}
@@ -17,11 +17,10 @@ package com.google.android.apps.mytracks.maps;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
/**
@@ -40,26 +39,18 @@ public class TrackPathPainterFactory {
* @return The TrackPathPainter that corresponds to the track color mode setting.
*/
public static TrackPathPainter getTrackPathPainter(Context context) {
SharedPreferences prefs = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
if (prefs == null) {
return new SingleColorTrackPathPainter(context);
}
String colorMode = prefs.getString(context.getString(R.string.track_color_mode_key), null);
Log.i(TAG, "Creating track path painter of type: " + colorMode);
String trackColorMode = PreferencesUtils.getString(context, R.string.track_color_mode_key,
context.getString(R.string.settings_map_track_color_mode_single_value));
Log.i(TAG, "Creating track path painter of type: " + trackColorMode);
if (colorMode == null
|| colorMode.equals(context.getString(R.string.display_track_color_value_none))) {
return new SingleColorTrackPathPainter(context);
} else if (colorMode.equals(context.getString(R.string.display_track_color_value_fixed))) {
return new DynamicSpeedTrackPathPainter(context,
new FixedSpeedTrackPathDescriptor(context));
} else if (colorMode.equals(context.getString(R.string.display_track_color_value_dynamic))) {
return new DynamicSpeedTrackPathPainter(context,
new DynamicSpeedTrackPathDescriptor(context));
if (context.getString(R.string.settings_map_track_color_mode_fixed_value)
.equals(trackColorMode)) {
return new DynamicSpeedTrackPathPainter(context, new FixedSpeedTrackPathDescriptor(context));
} else if (context.getString(R.string.settings_map_track_color_mode_dynamic_value)
.equals(trackColorMode)) {
return new DynamicSpeedTrackPathPainter(context, new DynamicSpeedTrackPathDescriptor(
context));
} else {
Log.w(TAG, "Using default track path painter. Unrecognized painter: " + colorMode);
return new SingleColorTrackPathPainter(context);
}
}
@@ -15,13 +15,12 @@
*/
package com.google.android.apps.mytracks.services;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
import com.google.common.annotations.VisibleForTesting;
import android.content.Context;
import android.content.SharedPreferences;
import java.text.SimpleDateFormat;
@@ -59,7 +58,7 @@ public class DefaultTrackNameFactory {
} else {
// trackNameSetting equals
// R.string.settings_recording_track_name_number_value
return String.format(context.getString(R.string.track_name_format), trackId);
return context.getString(R.string.track_name_format, trackId);
}
}
@@ -68,10 +67,7 @@ public class DefaultTrackNameFactory {
*/
@VisibleForTesting
String getTrackNameSetting() {
SharedPreferences sharedPreferences = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
return sharedPreferences.getString(
context.getString(R.string.track_name_key),
return PreferencesUtils.getString(context, R.string.track_name_key,
context.getString(R.string.settings_recording_track_name_date_local_value));
}
}
@@ -16,160 +16,120 @@
package com.google.android.apps.mytracks.services;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.util.Log;
/**
* A class that manages reading the shared preferences for the service.
*
*
* @author Sandor Dornbush
*/
public class PreferenceManager implements OnSharedPreferenceChangeListener {
private TrackRecordingService service;
private SharedPreferences sharedPreferences;
private final String announcementFrequencyKey;
private final String autoResumeTrackCurrentRetryKey;
private final String autoResumeTrackTimeoutKey;
private final String maxRecordingDistanceKey;
private final String metricUnitsKey;
private final String minRecordingDistanceKey;
private final String minRecordingIntervalKey;
private final String minRequiredAccuracyKey;
private final String splitFrequencyKey;
public PreferenceManager(TrackRecordingService service) {
this.service = service;
this.sharedPreferences = service.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
if (sharedPreferences == null) {
Log.w(Constants.TAG,
"TrackRecordingService: Couldn't get shared preferences.");
throw new IllegalStateException("Couldn't get shared preferences");
}
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
announcementFrequencyKey =
service.getString(R.string.announcement_frequency_key);
autoResumeTrackCurrentRetryKey =
service.getString(R.string.auto_resume_track_current_retry_key);
autoResumeTrackTimeoutKey =
service.getString(R.string.auto_resume_track_timeout_key);
maxRecordingDistanceKey =
service.getString(R.string.max_recording_distance_key);
metricUnitsKey =
service.getString(R.string.metric_units_key);
minRecordingDistanceKey =
service.getString(R.string.min_recording_distance_key);
minRecordingIntervalKey =
service.getString(R.string.min_recording_interval_key);
minRequiredAccuracyKey =
service.getString(R.string.min_required_accuracy_key);
splitFrequencyKey =
service.getString(R.string.split_frequency_key);
// Refresh all properties.
onSharedPreferenceChanged(sharedPreferences, null);
}
/**
* Notifies that preferences have changed.
* Call this with key == null to update all preferences in one call.
*
* Notifies that preferences have changed. Call this with key == null to
* update all preferences in one call.
*
* @param key the key that changed (may be null to update all preferences)
*/
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences,
String key) {
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (service == null) {
Log.w(Constants.TAG,
"onSharedPreferenceChanged: a preference change (key = " + key
Log.w(Constants.TAG, "onSharedPreferenceChanged: a preference change (key = " + key
+ ") after a call to shutdown()");
return;
}
if (key == null || key.equals(minRecordingDistanceKey)) {
int minRecordingDistance = sharedPreferences.getInt(
minRecordingDistanceKey,
Constants.DEFAULT_MIN_RECORDING_DISTANCE);
service.setMinRecordingDistance(minRecordingDistance);
Log.d(Constants.TAG,
"TrackRecordingService: minRecordingDistance = "
+ minRecordingDistance);
if (key == null
|| PreferencesUtils.getKey(service, R.string.recording_track_id_key).equals(key)) {
long recordingTrackId = PreferencesUtils.getLong(service, R.string.recording_track_id_key);
/*
* Only set the id if it is valid. Setting it to -1L should only happen
* in TrackRecordingService.endCurrentTrack()
*/
if (recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) {
service.setRecordingTrackId(recordingTrackId);
}
}
if (key == null || key.equals(maxRecordingDistanceKey)) {
service.setMaxRecordingDistance(sharedPreferences.getInt(
maxRecordingDistanceKey,
Constants.DEFAULT_MAX_RECORDING_DISTANCE));
if (key == null || PreferencesUtils.getKey(service, R.string.metric_units_key).equals(key)) {
service.setMetricUnits(PreferencesUtils.getBoolean(
service, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT));
}
if (key == null || key.equals(minRecordingIntervalKey)) {
int minRecordingInterval = sharedPreferences.getInt(
minRecordingIntervalKey,
Constants.DEFAULT_MIN_RECORDING_INTERVAL);
if (key == null
|| PreferencesUtils.getKey(service, R.string.announcement_frequency_key).equals(key)) {
service.setAnnouncementFrequency(PreferencesUtils.getInt(
service, R.string.announcement_frequency_key,
PreferencesUtils.ANNOUNCEMENT_FREQUENCY_DEFAULT));
}
if (key == null || PreferencesUtils.getKey(service, R.string.split_frequency_key).equals(key)) {
service.setSplitFrequency(PreferencesUtils.getInt(
service, R.string.split_frequency_key, PreferencesUtils.SPLIT_FREQUENCY_DEFAULT));
}
if (key == null
|| PreferencesUtils.getKey(service, R.string.min_recording_interval_key).equals(key)) {
int minRecordingInterval = PreferencesUtils.getInt(service,
R.string.min_recording_interval_key, PreferencesUtils.MIN_RECORDING_INTERVAL_DEFAULT);
switch (minRecordingInterval) {
case -2:
// Battery Miser
// min: 30 seconds
// max: 5 minutes
// minDist: 5 meters Choose battery life over moving time accuracy.
service.setLocationListenerPolicy(
new AdaptiveLocationListenerPolicy(30000, 300000, 5));
case PreferencesUtils.MIN_RECORDING_INTERVAL_ADAPT_BATTERY_LIFE:
/*
* Choose battery life over moving time accuracy. min: 30 seconds,
* max: 5 minutes, inDist: 5 meters.
*/
service.setLocationListenerPolicy(new AdaptiveLocationListenerPolicy(30000, 300000, 5));
break;
case -1:
// High Accuracy
// min: 1 second
// max: 30 seconds
// minDist: 0 meters get all updates to properly measure moving time.
service.setLocationListenerPolicy(
new AdaptiveLocationListenerPolicy(1000, 30000, 0));
case PreferencesUtils.MIN_RECORDING_INTERVAL_ADAPT_ACCURACY:
/*
* Get all the updates. min: 1 second, max: 30 seconds, minDist: 0
* meter.
*/
service.setLocationListenerPolicy(new AdaptiveLocationListenerPolicy(1000, 30000, 0));
break;
default:
service.setLocationListenerPolicy(
new AbsoluteLocationListenerPolicy(minRecordingInterval * 1000));
}
}
if (key == null || key.equals(minRequiredAccuracyKey)) {
service.setMinRequiredAccuracy(sharedPreferences.getInt(
minRequiredAccuracyKey,
Constants.DEFAULT_MIN_REQUIRED_ACCURACY));
if (key == null
|| PreferencesUtils.getKey(service, R.string.min_recording_distance_key).equals(key)) {
service.setMinRecordingDistance(PreferencesUtils.getInt(
service, R.string.min_recording_distance_key,
PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT));
}
if (key == null || key.equals(announcementFrequencyKey)) {
service.setAnnouncementFrequency(
sharedPreferences.getInt(announcementFrequencyKey, -1));
if (key == null
|| PreferencesUtils.getKey(service, R.string.max_recording_distance_key).equals(key)) {
service.setMaxRecordingDistance(PreferencesUtils.getInt(
service, R.string.max_recording_distance_key,
PreferencesUtils.MAX_RECORDING_DISTANCE_DEFAULT));
}
if (key == null || key.equals(autoResumeTrackTimeoutKey)) {
service.setAutoResumeTrackTimeout(sharedPreferences.getInt(
autoResumeTrackTimeoutKey,
Constants.DEFAULT_AUTO_RESUME_TRACK_TIMEOUT));
}
if (key == null || key.equals(PreferencesUtils.getRecordingTrackIdKey(service))) {
long recordingTrackId = PreferencesUtils.getRecordingTrackId(service);
// Only read the id if it is valid.
// Setting it to -1 should only happen in
// TrackRecordingService.endCurrentTrack()
if (recordingTrackId != -1L) {
service.setRecordingTrackId(recordingTrackId);
}
}
if (key == null || key.equals(splitFrequencyKey)) {
service.setSplitFrequency(
sharedPreferences.getInt(splitFrequencyKey, 0));
}
if (key == null || key.equals(metricUnitsKey)) {
service.setMetricUnits(
sharedPreferences.getBoolean(metricUnitsKey, true));
}
}
public void setAutoResumeTrackCurrentRetry(int retryAttempts) {
Editor editor = sharedPreferences.edit();
editor.putInt(autoResumeTrackCurrentRetryKey, retryAttempts);
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
if (key == null
|| PreferencesUtils.getKey(service, R.string.min_required_accuracy_key).equals(key)) {
service.setMinRequiredAccuracy(PreferencesUtils.getInt(
service, R.string.min_required_accuracy_key,
PreferencesUtils.MIN_REQUIRED_ACCURACY_DEFAULT));
}
if (key == null
|| PreferencesUtils.getKey(service, R.string.auto_resume_track_timeout_key).equals(key)) {
service.setAutoResumeTrackTimeout(PreferencesUtils.getInt(
service, R.string.auto_resume_track_timeout_key,
PreferencesUtils.AUTO_RESUME_TRACK_TIMEOUT_DEFAULT));
}
}
public void shutdown() {
@@ -38,6 +38,7 @@ import com.google.android.apps.mytracks.services.tasks.SplitTask;
import com.google.android.apps.mytracks.services.tasks.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.stats.TripStatisticsBuilder;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.LocationUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
@@ -49,7 +50,6 @@ import android.app.Service;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.location.Location;
@@ -83,14 +83,10 @@ public class TrackRecordingService extends Service {
private LocationManager locationManager;
private WakeLock wakeLock;
private int minRecordingDistance =
Constants.DEFAULT_MIN_RECORDING_DISTANCE;
private int maxRecordingDistance =
Constants.DEFAULT_MAX_RECORDING_DISTANCE;
private int minRequiredAccuracy =
Constants.DEFAULT_MIN_REQUIRED_ACCURACY;
private int autoResumeTrackTimeout =
Constants.DEFAULT_AUTO_RESUME_TRACK_TIMEOUT;
private int minRecordingDistance = PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT;
private int maxRecordingDistance = PreferencesUtils.MAX_RECORDING_DISTANCE_DEFAULT;
private int minRequiredAccuracy = PreferencesUtils.MIN_REQUIRED_ACCURACY_DEFAULT;
private int autoResumeTrackTimeout = PreferencesUtils.AUTO_RESUME_TRACK_TIMEOUT_DEFAULT;
private long recordingTrackId = -1;
@@ -122,7 +118,7 @@ public class TrackRecordingService extends Service {
private SensorManager sensorManager;
private PreferenceManager prefManager;
private PreferenceManager prefereceManager;
/**
* The interval in milliseconds that we have requested to be notified of gps
@@ -247,7 +243,7 @@ public class TrackRecordingService extends Service {
setUpTaskExecutors();
executorService = Executors.newSingleThreadExecutor();
prefManager = new PreferenceManager(this);
prefereceManager = new PreferenceManager(this);
registerLocationListener();
@@ -270,7 +266,7 @@ public class TrackRecordingService extends Service {
+ "Resetting an orphaned recording track = " + recordingTrackId);
}
recordingTrackId = -1L;
PreferencesUtils.setRecordingTrackId(this, recordingTrackId);
PreferencesUtils.setLong(this, R.string.recording_track_id_key, recordingTrackId);
}
showNotification();
}
@@ -327,7 +323,7 @@ public class TrackRecordingService extends Service {
+ recordingTrack + ") doesn't exist or is too old");
isRecording = false;
recordingTrackId = -1L;
PreferencesUtils.setRecordingTrackId(this, recordingTrackId);
PreferencesUtils.setLong(this, R.string.recording_track_id_key, recordingTrackId);
stopSelfResult(startId);
return;
}
@@ -353,8 +349,7 @@ public class TrackRecordingService extends Service {
isRecording = false;
showNotification();
prefManager.shutdown();
prefManager = null;
prefereceManager.shutdown();
checkLocationListener.cancel();
checkLocationListener = null;
timer.cancel();
@@ -382,7 +377,7 @@ public class TrackRecordingService extends Service {
private void setAutoResumeTrackRetries(int retryAttempts) {
Log.d(TAG, "Updating auto-resume retry attempts to: " + retryAttempts);
prefManager.setAutoResumeTrackCurrentRetry(retryAttempts);
PreferencesUtils.setInt(this, R.string.auto_resume_track_current_retry_key, retryAttempts);
}
private boolean shouldResumeTrack(Track track) {
@@ -390,10 +385,8 @@ public class TrackRecordingService extends Service {
+ autoResumeTrackTimeout);
// Check if we haven't exceeded the maximum number of retry attempts.
SharedPreferences sharedPreferences = getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
int retries = sharedPreferences.getInt(
getString(R.string.auto_resume_track_current_retry_key), 0);
int retries = PreferencesUtils.getInt(this, R.string.auto_resume_track_current_retry_key,
PreferencesUtils.AUTO_RESUME_TRACK_CURRENT_RETRY_DEFAULT);
Log.d(TAG,
"shouldResumeTrack: Attempting to auto-resume the track ("
+ (retries + 1) + "/" + MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS + ")");
@@ -408,12 +401,12 @@ public class TrackRecordingService extends Service {
setAutoResumeTrackRetries(retries + 1);
// Check for special cases.
if (autoResumeTrackTimeout == 0) {
if (autoResumeTrackTimeout == PreferencesUtils.AUTO_RESUME_TRACK_TIMEOUT_NEVER) {
// Never resume.
Log.d(TAG,
"shouldResumeTrack: Auto-resume disabled (never resume)");
return false;
} else if (autoResumeTrackTimeout == -1) {
} else if (autoResumeTrackTimeout == PreferencesUtils.AUTO_RESUME_TRACK_TIMEOUT_ALWAYS) {
// Always resume.
Log.d(TAG,
"shouldResumeTrack: Auto-resume forced (always resume)");
@@ -485,13 +478,11 @@ public class TrackRecordingService extends Service {
private void showNotification() {
if (isRecording) {
Notification notification = new Notification(
R.drawable.arrow_320, null /* tickerText */,
System.currentTimeMillis());
Intent intent = new Intent(this, TrackDetailActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
R.drawable.my_tracks_notification_icon, null, System.currentTimeMillis());
Intent intent = IntentUtils.newIntent(this, TrackDetailActivity.class)
.putExtra(TrackDetailActivity.EXTRA_TRACK_ID, recordingTrackId);
PendingIntent contentIntent = PendingIntent.getActivity(
this, 0 /* requestCode */, intent, 0 /* flags */);
this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
notification.setLatestEventInfo(this, getString(R.string.my_tracks_app_name),
getString(R.string.track_record_notification), contentIntent);
notification.flags += Notification.FLAG_NO_CLEAR;
@@ -566,12 +557,6 @@ public class TrackRecordingService extends Service {
"Location listener now unregistered w/ TrackRecordingService.");
}
private String getDefaultActivityType(Context context) {
SharedPreferences prefs = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
return prefs.getString(context.getString(R.string.default_activity_key), "");
}
/*
* Recording lifecycle.
*/
@@ -594,7 +579,8 @@ public class TrackRecordingService extends Service {
track.setId(recordingTrackId);
track.setName(new DefaultTrackNameFactory(this).getDefaultTrackName(
recordingTrackId, startTime));
track.setCategory(getDefaultActivityType(this));
track.setCategory(PreferencesUtils.getString(
this, R.string.default_activity_key, PreferencesUtils.DEFAULT_ACTIVITY_DEFAULT));
isRecording = true;
isMoving = true;
@@ -612,7 +598,7 @@ public class TrackRecordingService extends Service {
// Reset the number of auto-resume retries.
setAutoResumeTrackRetries(0);
// Persist the current recording track.
PreferencesUtils.setRecordingTrackId(this, recordingTrackId);
PreferencesUtils.setLong(this, R.string.recording_track_id_key, recordingTrackId);
// Notify the world that we're now recording.
sendTrackBroadcast(
@@ -934,15 +920,15 @@ public class TrackRecordingService extends Service {
"Unable to insert waypoint marker while not recording!");
}
if (request == null) {
request = WaypointCreationRequest.DEFAULT_MARKER;
request = WaypointCreationRequest.DEFAULT_WAYPOINT;
}
Waypoint wpt = new Waypoint();
switch (request.getType()) {
case MARKER:
buildMarker(wpt, request);
case WAYPOINT:
buildWaypointMarker(wpt, request);
break;
case STATISTICS:
buildStatisticsMarker(wpt);
buildStatisticsMarker(wpt, request);
break;
}
wpt.setTrackId(recordingTrackId);
@@ -964,18 +950,22 @@ public class TrackRecordingService extends Service {
return Long.parseLong(uri.getLastPathSegment());
}
private void buildMarker(Waypoint wpt, WaypointCreationRequest request) {
private void buildWaypointMarker(Waypoint wpt, WaypointCreationRequest request) {
wpt.setType(Waypoint.TYPE_WAYPOINT);
if (request.getIconUrl() == null) {
wpt.setIcon(getString(R.string.marker_waypoint_icon_url));
} else {
wpt.setIcon(request.getIconUrl());
}
if (request.getName() == null) {
wpt.setName(getString(R.string.marker_edit_type_waypoint));
String name;
if (request.getName() != null) {
name = request.getName();
} else {
wpt.setName(request.getName());
int nextMarkerNumber = providerUtils.getNextMarkerNumber(recordingTrackId, false);
name = nextMarkerNumber == -1 ? getString(R.string.marker_type_waypoint)
: getString(R.string.marker_waypoint_name_format, nextMarkerNumber);
}
wpt.setName(name);
if (request.getCategory() != null) {
wpt.setCategory(request.getCategory());
}
@@ -988,9 +978,10 @@ public class TrackRecordingService extends Service {
* Build a statistics marker.
* A statistics marker holds the stats for the* last segment up to this marker.
*
* @param waypoint The waypoint which will be populated with stats data.
* @param waypoint The waypoint which will be populated with stats data
* @param request The waypoint creation request
*/
private void buildStatisticsMarker(Waypoint waypoint) {
private void buildStatisticsMarker(Waypoint waypoint, WaypointCreationRequest request) {
DescriptionGenerator descriptionGenerator = new DescriptionGeneratorImpl(this);
// Set stop and total time in the stats data
@@ -1003,7 +994,15 @@ public class TrackRecordingService extends Service {
// Set the rest of the waypoint data
waypoint.setType(Waypoint.TYPE_STATISTICS);
waypoint.setName(getString(R.string.marker_edit_type_statistics));
String name;
if (request.getName() != null) {
name = request.getName();
} else {
int nextMarkerNumber = providerUtils.getNextMarkerNumber(recordingTrackId, true);
name = nextMarkerNumber == -1 ? getString(R.string.marker_type_statistics)
: getString(R.string.marker_statistics_name_format, nextMarkerNumber);
}
waypoint.setName(name);
waypoint.setStatistics(waypointStatsBuilder.getStatistics());
waypoint.setDescription(descriptionGenerator.generateWaypointDescription(waypoint));
waypoint.setIcon(getString(R.string.marker_statistics_icon_url));
@@ -1042,7 +1041,7 @@ public class TrackRecordingService extends Service {
showNotification();
long recordedTrackId = recordingTrackId;
recordingTrackId = -1L;
PreferencesUtils.setRecordingTrackId(this, recordingTrackId);
PreferencesUtils.setLong(this, R.string.recording_track_id_key, recordingTrackId);
if (sensorManager != null) {
SensorManagerFactory.getInstance().releaseSensorManager(sensorManager);
@@ -1063,10 +1062,8 @@ public class TrackRecordingService extends Service {
.setAction(getString(actionResId))
.putExtra(getString(R.string.track_id_broadcast_extra), trackId);
sendBroadcast(broadcastIntent, getString(R.string.permission_notification_value));
SharedPreferences sharedPreferences = getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
if (sharedPreferences.getBoolean(getString(R.string.allow_access_key), false)) {
if (PreferencesUtils.getBoolean(
this, R.string.allow_access_key, PreferencesUtils.ALLOW_ACCESS_DEFAULT)) {
sendBroadcast(broadcastIntent, getString(R.string.broadcast_notifications_permission));
}
}
@@ -1212,20 +1209,17 @@ public class TrackRecordingService extends Service {
/**
* Returns true if the RPC caller is from the same application or if the
* "Allow access" setting indicates that another app can invoke this service's
* RPCs.
* "Allow access" setting indicates that another app can invoke this
* service's RPCs.
*/
private boolean canAccess() {
// As a precondition for access, must check if the service is available.
checkService();
if (Process.myPid() == Binder.getCallingPid()) {
return true;
} else {
SharedPreferences sharedPreferences = service.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
return sharedPreferences.getBoolean(service.getString(R.string.allow_access_key), false);
return PreferencesUtils.getBoolean(
service, R.string.allow_access_key, PreferencesUtils.ALLOW_ACCESS_DEFAULT);
}
}
@@ -19,12 +19,12 @@ import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -127,16 +127,20 @@ public class BluetoothSensorManager extends SensorManager {
Log.w(Constants.TAG, "Disabled manager onStartTrack");
return;
}
SharedPreferences prefs = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
String address =
prefs.getString(context.getString(R.string.bluetooth_sensor_key), "");
if (address == null || address.equals("")) {
String address = PreferencesUtils.getString(
context, R.string.bluetooth_sensor_key, PreferencesUtils.BLUETOOTH_SENSOR_DEFAULT);
if (PreferencesUtils.BLUETOOTH_SENSOR_DEFAULT.equals(address)) {
return;
}
Log.w(Constants.TAG, "Connecting to bluetooth sensor: " + address);
// Get the BluetoothDevice object
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
BluetoothDevice device;
try {
device = bluetoothAdapter.getRemoteDevice(address);
} catch (IllegalArgumentException e) {
Log.d(Constants.TAG, "Invalid address " + address, e);
return;
}
// Attempt to connect to the device
connectionManager.connect(device);
@@ -18,10 +18,10 @@ package com.google.android.apps.mytracks.services.sensors;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.services.sensors.ant.AntDirectSensorManager;
import com.google.android.apps.mytracks.services.sensors.ant.AntSrmBridgeSensorManager;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
/**
@@ -53,41 +53,36 @@ public class SensorManagerFactory {
* @return The sensor manager that corresponds to the sensor type setting.
*/
public SensorManager getSensorManager(Context context) {
SharedPreferences prefs = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
if (prefs == null) {
return null;
}
context = context.getApplicationContext();
String sensorTypeValueNone = context.getString(R.string.sensor_type_value_none);
String sensorType = PreferencesUtils.getString(
context, R.string.sensor_type_key, sensorTypeValueNone);
Log.i(Constants.TAG, "Creating sensor of type: " + sensorType);
String sensor = prefs.getString(context.getString(R.string.sensor_type_key), null);
Log.i(Constants.TAG, "Creating sensor of type: " + sensor);
if (sensor == null) {
if (sensorTypeValueNone.equals(sensorType)) {
reset();
return null;
}
if (sensor.equals(activeSensorType)) {
if (sensorType.equals(activeSensorType)) {
Log.i(Constants.TAG, "Returning existing sensor manager.");
refCount++;
return activeSensorManager;
}
reset();
if (sensor.equals(context.getString(R.string.sensor_type_value_ant))) {
if (sensorType.equals(context.getString(R.string.sensor_type_value_ant))) {
activeSensorManager = new AntDirectSensorManager(context);
} else if (sensor.equals(context.getString(R.string.sensor_type_value_srm_ant_bridge))) {
} else if (sensorType.equals(context.getString(R.string.sensor_type_value_srm_ant_bridge))) {
activeSensorManager = new AntSrmBridgeSensorManager(context);
} else if (sensor.equals(context.getString(R.string.sensor_type_value_zephyr))) {
} else if (sensorType.equals(context.getString(R.string.sensor_type_value_zephyr))) {
activeSensorManager = new ZephyrSensorManager(context);
} else if (sensor.equals(context.getString(R.string.sensor_type_value_polar))) {
} else if (sensorType.equals(context.getString(R.string.sensor_type_value_polar))) {
activeSensorManager = new PolarSensorManager(context);
} else {
Log.w(Constants.TAG, "Unable to find sensor type: " + sensor);
Log.w(Constants.TAG, "Unable to find sensor type: " + sensorType);
return null;
}
activeSensorType = sensor;
activeSensorType = sensorType;
refCount = 1;
activeSensorManager.onStartTrack();
return activeSensorManager;
@@ -20,13 +20,11 @@ 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.Constants;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
/**
@@ -107,11 +105,7 @@ public class AntDirectSensorManager extends AntSensorManager
}
Log.i(TAG, "Found ANT device id: " + deviceNumber + " on channel: " + channel);
SharedPreferences prefs = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putInt(context.getString(sensorIdKeys[channel]), deviceNumber);
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
PreferencesUtils.setInt(context, sensorIdKeys[channel], deviceNumber);
return deviceNumber;
}
@@ -171,12 +165,8 @@ public class AntDirectSensorManager extends AntSensorManager
protected void setupAntSensorChannels() {
short devIds[] = new short[sensorIdKeys.length];
SharedPreferences prefs = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
if (prefs != null) {
for (int i = 0; i < sensorIdKeys.length; ++i) {
devIds[i] = (short) prefs.getInt(context.getString(sensorIdKeys[i]), WILDCARD);
}
for (int i = 0; i < sensorIdKeys.length; ++i) {
devIds[i] = (short) PreferencesUtils.getInt(context, sensorIdKeys[i], WILDCARD);
}
sensors = new AntSensorBase[] {
@@ -20,14 +20,12 @@ 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.Constants;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.BuildConfig;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
/**
@@ -68,13 +66,8 @@ public class AntSrmBridgeSensorManager extends AntSensorManager {
deviceNumber = WILDCARD;
// First read the the device id that we will be pairing with.
SharedPreferences prefs = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
if (prefs != null) {
deviceNumber =
(short) prefs.getInt(context.getString(
R.string.ant_srm_bridge_sensor_id_key), 0);
}
deviceNumber = (short) PreferencesUtils.getInt(
context, R.string.ant_srm_bridge_sensor_id_key, WILDCARD);
Log.i(TAG, "Will pair with device: " + deviceNumber);
}
@@ -194,12 +187,7 @@ public class AntSrmBridgeSensorManager extends AntSensorManager {
AntChannelIdMessage message = new AntChannelIdMessage(rawMessage);
deviceNumber = message.getDeviceNumber();
Log.d(TAG, "Found device id: " + deviceNumber);
SharedPreferences prefs = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putInt(context.getString(R.string.ant_srm_bridge_sensor_id_key), deviceNumber);
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
PreferencesUtils.setInt(context, R.string.ant_srm_bridge_sensor_id_key, deviceNumber);
}
private void handleMessageResponse(byte[] rawMessage) {
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks.services.tasks;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.services.TrackRecordingService;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import android.util.Log;
@@ -34,7 +35,7 @@ public class PeriodicTaskExecutor {
* A value greater than zero is a frequency in time.
* A value less than zero is considered a frequency in distance.
*/
private int taskFrequency = 0;
private int taskFrequency = PreferencesUtils.PERIODIC_TASK_OFF;
/**
* The next distance when the task should execute.
@@ -74,7 +75,7 @@ public class PeriodicTaskExecutor {
timerExecutor = null;
}
}
if (taskFrequency == 0) {
if (taskFrequency == PreferencesUtils.PERIODIC_TASK_OFF) {
return;
}
@@ -21,13 +21,13 @@ import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.services.TrackRecordingService;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
import com.google.common.annotations.VisibleForTesting;
import android.content.Context;
import android.content.SharedPreferences;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.telephony.PhoneStateListener;
@@ -150,16 +150,11 @@ public class StatusAnnouncerTask implements PeriodicTask {
*/
// @VisibleForTesting
protected String getAnnouncement(TripStatistics stats) {
boolean metricUnits = true;
boolean reportSpeed = true;
SharedPreferences preferences = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
if (preferences != null) {
metricUnits = preferences.getBoolean(context.getString(R.string.metric_units_key), true);
reportSpeed = preferences.getBoolean(context.getString(R.string.report_speed_key), true);
}
double d = stats.getTotalDistance() * UnitConversions.M_TO_KM;
boolean metricUnits = PreferencesUtils.getBoolean(
context, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
boolean reportSpeed = PreferencesUtils.getBoolean(
context, R.string.report_speed_key, PreferencesUtils.REPORT_SPEED_DEFAULT);
double d = stats.getTotalDistance() * UnitConversions.M_TO_KM;
double s = stats.getAverageMovingSpeed() * UnitConversions.MS_TO_KMH;
if (d == 0) {
@@ -0,0 +1,74 @@
/*
* Copyright 2012 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.settings;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.io.backup.BackupPreferencesListener;
import com.google.android.apps.mytracks.util.ApiAdapterFactory;
import android.content.Context;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.speech.tts.TextToSpeech;
import android.view.MenuItem;
/**
* An abstract activity for all the settings activities.
*
* @author Jimmy Shih
*/
public class AbstractSettingsActivity extends PreferenceActivity {
private BackupPreferencesListener backupPreferencesListener;
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
ApiAdapterFactory.getApiAdapter().configureActionBarHomeAsUp(this);
@SuppressWarnings("deprecation")
PreferenceManager preferenceManager = getPreferenceManager();
preferenceManager.setSharedPreferencesName(Constants.SETTINGS_NAME);
preferenceManager.setSharedPreferencesMode(Context.MODE_PRIVATE);
// Set up automatic preferences backup
backupPreferencesListener = ApiAdapterFactory.getApiAdapter()
.getBackupPreferencesListener(this);
preferenceManager.getSharedPreferences()
.registerOnSharedPreferenceChangeListener(backupPreferencesListener);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() != android.R.id.home) {
return super.onOptionsItemSelected(item);
}
finish();
return true;
}
@Override
protected void onDestroy() {
super.onDestroy();
@SuppressWarnings("deprecation")
PreferenceManager preferenceManager = getPreferenceManager();
preferenceManager.getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(backupPreferencesListener);
}
}
@@ -0,0 +1,127 @@
/*
* Copyright 2012 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.settings;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.io.backup.BackupActivity;
import com.google.android.apps.mytracks.io.backup.RestoreChooserActivity;
import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
/**
* An activity for accessing the backup settings.
*
* @author Jimmy Shih
*/
public class BackupSettingsActivity extends AbstractSettingsActivity {
private static final int DIALOG_CONFIRM_RESTORE_ID = 0;
Preference backupPreference;
Preference restorePreference;
/*
* Note that sharedPreferenceChangeListenr cannot be an anonymous inner class.
* Anonymous inner class will get garbage collected.
*/
private final OnSharedPreferenceChangeListener
sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
// Note that key can be null
if (PreferencesUtils.getKey(BackupSettingsActivity.this, R.string.recording_track_id_key)
.equals(key)) {
updateUi();
}
}
};
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE)
.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
addPreferencesFromResource(R.xml.backup_settings);
backupPreference = findPreference(getString(R.string.settings_backup_now_key));
backupPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent intent = IntentUtils.newIntent(BackupSettingsActivity.this, BackupActivity.class);
startActivity(intent);
return true;
}
});
restorePreference = findPreference(getString(R.string.settings_backup_restore_key));
restorePreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
showDialog(DIALOG_CONFIRM_RESTORE_ID);
return true;
}
});
}
@Override
protected Dialog onCreateDialog(int id) {
if (id != DIALOG_CONFIRM_RESTORE_ID) {
return null;
}
return DialogUtils.createConfirmationDialog(this,
R.string.settings_backup_restore_confirm_message, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = IntentUtils.newIntent(
BackupSettingsActivity.this, RestoreChooserActivity.class);
startActivity(intent);
}
});
}
@Override
protected void onResume() {
super.onResume();
updateUi();
}
/**
* Updates the UI based on the recording state.
*/
private void updateUi() {
boolean isRecording = PreferencesUtils.getLong(this, R.string.recording_track_id_key)
!= PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
backupPreference.setEnabled(!isRecording);
restorePreference.setEnabled(!isRecording);
backupPreference.setSummary(isRecording ? R.string.settings_not_while_recording
: R.string.settings_backup_now_summary);
restorePreference.setSummary(isRecording ? R.string.settings_not_while_recording
: R.string.settings_backup_restore_summary);
}
}
@@ -0,0 +1,54 @@
/*
* Copyright 2012 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.settings;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
/**
* An activity for accessing chart settings.
*
* @author Jimmy Shih
*/
public class ChartSettingsActivity extends AbstractSettingsActivity {
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
addPreferencesFromResource(R.xml.chart_settings);
}
@Override
protected void onResume() {
super.onResume();
updateUi();
}
@SuppressWarnings("deprecation")
private void updateUi() {
CheckBoxPreference speedCheckBoxPreference = (CheckBoxPreference) findPreference(
getString(R.string.chart_show_speed_key));
boolean reportSpeed = PreferencesUtils.getBoolean(
this, R.string.report_speed_key, PreferencesUtils.REPORT_SPEED_DEFAULT);
speedCheckBoxPreference.setTitle(reportSpeed ? R.string.stats_speed
: R.string.stats_pace);
}
}
@@ -0,0 +1,273 @@
/*
* Copyright 2012 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.settings;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
import android.app.Dialog;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.util.Log;
import android.view.KeyEvent;
import android.view.inputmethod.EditorInfo;
import android.widget.TextView;
/**
* An activity for accessing map settings.
*
* @author Jimmy Shih
*/
public class MapSettingsActivity extends AbstractSettingsActivity {
private static final String TAG = MapSettingsActivity.class.getSimpleName();
private EditTextPreference slowEditTextPreference;
private EditTextPreference mediumEditTextPreference;
private EditTextPreference percentageEditTextPreference;
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
addPreferencesFromResource(R.xml.map_settings);
ListPreference trackColorModeListPreference = (ListPreference) findPreference(
getString(R.string.track_color_mode_key));
trackColorModeListPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
updateUiByTrackColorMode((String) newValue);
return true;
}
});
slowEditTextPreference = (EditTextPreference) findPreference(
getString(R.string.settings_map_slow_display_key));
configureSpeedEditTextPreference(R.string.track_color_mode_slow_key);
mediumEditTextPreference = (EditTextPreference) findPreference(
getString(R.string.settings_map_medium_display_key));
configureSpeedEditTextPreference(R.string.track_color_mode_medium_key);
percentageEditTextPreference = (EditTextPreference) findPreference(
getString(R.string.settings_map_percentage_display_key));
configurePercentageEditTextPreference();
updatePercentageSummary();
configureImeActionDone(slowEditTextPreference);
configureImeActionDone(mediumEditTextPreference);
configureImeActionDone(percentageEditTextPreference);
updateUiByTrackColorMode(trackColorModeListPreference.getValue());
}
/**
* Configures the speed edit text preference.
*
* @param keyId the key id
*/
private void configureSpeedEditTextPreference(final int keyId) {
final EditTextPreference editTextPreference = keyId == R.string.track_color_mode_slow_key ? slowEditTextPreference
: mediumEditTextPreference;
editTextPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
storeSpeedValue(keyId, (String) newValue);
updateSpeedSummary(keyId);
return true;
}
});
editTextPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
int value = getSpeedDisplayValue(keyId);
((EditTextPreference) preference).getEditText().setText(String.valueOf(value));
return true;
}
});
}
/**
* Configures the percentage edit text preference.
*/
private void configurePercentageEditTextPreference() {
percentageEditTextPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String displayValue = (String) newValue;
int value;
try {
value = Integer.parseInt(displayValue);
} catch (NumberFormatException e) {
Log.e(TAG, "invalid value " + displayValue);
value = PreferencesUtils.TRACK_COLOR_MODE_PERCENTAGE_DEFAULT;
}
if (value < 0) {
value = PreferencesUtils.TRACK_COLOR_MODE_PERCENTAGE_DEFAULT;
}
PreferencesUtils.setInt(
MapSettingsActivity.this, R.string.track_color_mode_percentage_key, value);
updatePercentageSummary();
return true;
}
});
percentageEditTextPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
int value = PreferencesUtils.getInt(
MapSettingsActivity.this, R.string.track_color_mode_percentage_key,
PreferencesUtils.TRACK_COLOR_MODE_PERCENTAGE_DEFAULT);
((EditTextPreference) preference).getEditText().setText(String.valueOf(value));
return true;
}
});
}
/**
* Configures the IME action done.
*
* @param editTextPreference the edit text preference
*/
private void configureImeActionDone(final EditTextPreference editTextPreference) {
editTextPreference.getEditText()
.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
Dialog dialog = editTextPreference.getDialog();
editTextPreference.onClick(dialog, Dialog.BUTTON_POSITIVE);
dialog.dismiss();
return true;
}
return false;
}
});
}
@Override
protected void onResume() {
super.onResume();
updateSpeedSummary(R.string.track_color_mode_slow_key);
updateSpeedSummary(R.string.track_color_mode_medium_key);
}
/**
* Updates the UI by the track color mode.
*
* @param trackColorMode the track color mode
*/
private void updateUiByTrackColorMode(String trackColorMode) {
boolean isFixedValue = trackColorMode.equals(
getString(R.string.settings_map_track_color_mode_fixed_value));
boolean isDynamicValue = trackColorMode.equals(
getString(R.string.settings_map_track_color_mode_dynamic_value));
slowEditTextPreference.setEnabled(isFixedValue);
mediumEditTextPreference.setEnabled(isFixedValue);
percentageEditTextPreference.setEnabled(isDynamicValue);
}
/**
* Stores the speed value, always in metric units.
*
* @param keyId the key id
* @param displayValue the display value
*/
private void storeSpeedValue(int keyId, String displayValue) {
int maxValue;
int minValue;
int defaultValue;
if (keyId == R.string.track_color_mode_slow_key) {
minValue = 0;
maxValue = PreferencesUtils.getInt(this, R.string.track_color_mode_medium_key,
PreferencesUtils.TRACK_COLOR_MODE_MEDIUM_DEFAULT);
defaultValue = PreferencesUtils.TRACK_COLOR_MODE_SLOW_DEFAULT;
} else {
minValue = PreferencesUtils.getInt(
this, R.string.track_color_mode_slow_key, PreferencesUtils.TRACK_COLOR_MODE_SLOW_DEFAULT);
maxValue = Integer.MAX_VALUE;
defaultValue = PreferencesUtils.TRACK_COLOR_MODE_MEDIUM_DEFAULT;
}
int value;
try {
value = Integer.parseInt(displayValue);
if (!PreferencesUtils.getBoolean(
this, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT)) {
value = (int) (value * UnitConversions.MI_TO_KM);
}
} catch (NumberFormatException e) {
Log.e(TAG, "invalid value " + displayValue);
value = defaultValue;
}
if (value > maxValue) {
value = maxValue;
}
if (value < minValue) {
value = minValue;
}
PreferencesUtils.setInt(this, keyId, value);
}
/**
* Gets the speed display value, in metric or imperial depending on the preferred
* units.
*
* @param keyId the key id
*/
private int getSpeedDisplayValue(int keyId) {
int defaultValue = keyId == R.string.track_color_mode_slow_key ? PreferencesUtils.TRACK_COLOR_MODE_SLOW_DEFAULT
: PreferencesUtils.TRACK_COLOR_MODE_MEDIUM_DEFAULT;
int value = PreferencesUtils.getInt(this, keyId, defaultValue);
if (!PreferencesUtils.getBoolean(
this, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT)) {
value = (int) (value * UnitConversions.KM_TO_MI);
}
return value;
}
/**
* Updates the speed summary.
*
* @param keyId the key id
*/
private void updateSpeedSummary(int keyId) {
EditTextPreference editTextPreference = keyId == R.string.track_color_mode_slow_key ? slowEditTextPreference
: mediumEditTextPreference;
boolean metric = PreferencesUtils.getBoolean(
this, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
int displayValue = getSpeedDisplayValue(keyId);
editTextPreference.setSummary(getString(metric ? R.string.value_integer_kilometer_hour
: R.string.value_integer_mile_hour, displayValue));
}
/**
* Updates the percentage summary.
*/
private void updatePercentageSummary() {
int value = PreferencesUtils.getInt(
MapSettingsActivity.this, R.string.track_color_mode_percentage_key,
PreferencesUtils.TRACK_COLOR_MODE_PERCENTAGE_DEFAULT);
percentageEditTextPreference.setSummary(getString(R.string.settings_map_percentage_summary) + "\n"
+ getString(R.string.value_integer_percent, value));
}
}
@@ -0,0 +1,243 @@
/*
* Copyright 2012 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.settings;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R;
import android.os.Bundle;
import android.preference.ListPreference;
/**
* An activity for accessing recording settings.
*
* @author Jimmy Shih
*/
public class RecordingSettingsActivity extends AbstractSettingsActivity {
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
addPreferencesFromResource(R.xml.recording_settings);
boolean metricUnits = PreferencesUtils.getBoolean(
this, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
ListPreference announcementFrequencyListPreference = (ListPreference) findPreference(
getString(R.string.announcement_frequency_key));
announcementFrequencyListPreference.setEntries(getPeriodicTaskDisplayOptions(metricUnits));
ListPreference splitFrequencyListPreference = (ListPreference) findPreference(
getString(R.string.split_frequency_key));
splitFrequencyListPreference.setEntries(getPeriodicTaskDisplayOptions(metricUnits));
ListPreference minRecordingIntervalListPreference = (ListPreference) findPreference(
getString(R.string.min_recording_interval_key));
minRecordingIntervalListPreference.setEntries(getMinRecordingIntervalDisplayOptions());
ListPreference minRecordingDistanceListPreference = (ListPreference) findPreference(
getString(R.string.min_recording_distance_key));
minRecordingDistanceListPreference.setEntries(
getMinRecordingDistanceDisplayOptions(metricUnits));
ListPreference maxRecordingDistanceListPreference = (ListPreference) findPreference(
getString(R.string.max_recording_distance_key));
maxRecordingDistanceListPreference.setEntries(
getMaxRecordingDistanceDisplayOptions(metricUnits));
ListPreference minRequiredAccuracyListPreference = (ListPreference) findPreference(
getString(R.string.min_required_accuracy_key));
minRequiredAccuracyListPreference.setEntries(getMinRequiredAccuracyDisplayOptions(metricUnits));
ListPreference autoResumeTrackTimeoutListPreference = (ListPreference) findPreference(
getString(R.string.auto_resume_track_timeout_key));
autoResumeTrackTimeoutListPreference.setEntries(getAutoResumeTrackTimeoutDisplayOptions());
}
/**
* Gets the periodic task display options.
*
* @param metricUnits true to display metric units
*/
private String[] getPeriodicTaskDisplayOptions(boolean metricUnits) {
String[] values = getResources().getStringArray(R.array.periodic_task_values);
String[] options = new String[values.length];
for (int i = 0; i < values.length; i++) {
int value = Integer.parseInt(values[i]);
if (value == PreferencesUtils.PERIODIC_TASK_OFF) {
options[i] = getString(R.string.value_off);
} else if (value < 0) {
options[i] = getString(metricUnits ? R.string.value_integer_kilometer
: R.string.value_integer_mile, Math.abs(value));
} else {
options[i] = getString(R.string.value_integer_minute, value);
}
}
return options;
}
/**
* Gets the min recording interval display options.
*/
private String[] getMinRecordingIntervalDisplayOptions() {
String[] values = getResources().getStringArray(R.array.min_recording_interval_values);
String[] options = new String[values.length];
for (int i = 0; i < values.length; i++) {
int value = Integer.parseInt(values[i]);
switch (value) {
case PreferencesUtils.MIN_RECORDING_INTERVAL_ADAPT_BATTERY_LIFE:
options[i] = getString(R.string.value_adapt_battery_life);
break;
case PreferencesUtils.MIN_RECORDING_INTERVAL_ADAPT_ACCURACY:
options[i] = getString(R.string.value_adapt_accuracy);
break;
case PreferencesUtils.MIN_RECORDING_INTERVAL_DEFAULT:
options[i] = getString(R.string.value_smallest_recommended);
break;
default:
options[i] = value < 60 ? getString(R.string.value_integer_second, value)
: getString(R.string.value_integer_minute, value / 60);
}
}
return options;
}
/**
* Gets the min recording distance display options.
*
* @param metricUnits true to display metric units
*/
private String[] getMinRecordingDistanceDisplayOptions(boolean metricUnits) {
String[] values = getResources().getStringArray(R.array.min_recording_distance_values);
String[] options = new String[values.length];
for (int i = 0; i < values.length; i++) {
int value = Integer.parseInt(values[i]);
if (metricUnits) {
options[i] = getString(value == PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT
? R.string.value_integer_meter_recommended
: R.string.value_integer_meter, value);
} else {
int feet = (int) (value * UnitConversions.M_TO_FT);
options[i] = getString(value == PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT
? R.string.value_integer_feet_recommended
: R.string.value_integer_feet, feet);
}
}
return options;
}
/**
* Gets the max recording distance display options.
*
* @param metricUnits true to display metric units
*/
private String[] getMaxRecordingDistanceDisplayOptions(boolean metricUnits) {
String[] values = getResources().getStringArray(R.array.max_recording_distance_values);
String[] options = new String[values.length];
for (int i = 0; i < values.length; i++) {
int value = Integer.parseInt(values[i]);
if (metricUnits) {
options[i] = getString(value == PreferencesUtils.MAX_RECORDING_DISTANCE_DEFAULT
? R.string.value_integer_meter_recommended
: R.string.value_integer_meter, value);
} else {
int feet = (int) (value * UnitConversions.M_TO_FT);
if (feet < 2000) {
options[i] = getString(value == PreferencesUtils.MAX_RECORDING_DISTANCE_DEFAULT
? R.string.value_integer_feet_recommended
: R.string.value_integer_feet, feet);
} else {
double mile = feet * UnitConversions.FT_TO_MI;
options[i] = getString(R.string.value_float_mile, mile);
}
}
}
return options;
}
/**
* Gets the min required accuracy display options.
*
* @param metricUnits true to display metric units
*/
private String[] getMinRequiredAccuracyDisplayOptions(boolean metricUnits) {
String[] values = getResources().getStringArray(R.array.min_required_accuracy_values);
String[] options = new String[values.length];
for (int i = 0; i < values.length; i++) {
int value = Integer.parseInt(values[i]);
if (metricUnits) {
switch (value) {
case PreferencesUtils.MIN_REQUIRED_ACCURACY_DEFAULT:
options[i] = getString(R.string.value_integer_meter_recommended, value);
break;
case PreferencesUtils.MIN_REQUIRED_ACCURACY_EXCELLENT:
options[i] = getString(R.string.value_integer_meter_excellent_gps, value);
break;
case PreferencesUtils.MIN_REQUIRED_ACCURACY_POOR:
options[i] = getString(R.string.value_integer_meter_poor_gps, value);
break;
default:
options[i] = getString(R.string.value_integer_meter, value);
}
} else {
int feet = (int) (value * UnitConversions.M_TO_FT);
if (feet < 2000) {
switch (value) {
case PreferencesUtils.MIN_REQUIRED_ACCURACY_DEFAULT:
options[i] = getString(R.string.value_integer_feet_recommended, feet);
break;
case PreferencesUtils.MIN_REQUIRED_ACCURACY_EXCELLENT:
options[i] = getString(R.string.value_integer_feet_excellent_gps, feet);
break;
default:
options[i] = getString(R.string.value_integer_feet, feet);
}
} else {
double mile = feet * UnitConversions.FT_TO_MI;
options[i] = getString(value == PreferencesUtils.MIN_REQUIRED_ACCURACY_POOR
? R.string.value_float_mile_poor_gps
: R.string.value_float_mile, mile);
}
}
}
return options;
}
/**
* Gets the auto resume track timeout display options.
*/
private String[] getAutoResumeTrackTimeoutDisplayOptions() {
String[] values = getResources().getStringArray(R.array.auto_resume_track_timeout_values);
String[] options = new String[values.length];
for (int i = 0; i < values.length; i++) {
int value = Integer.parseInt(values[i]);
switch (value) {
case PreferencesUtils.AUTO_RESUME_TRACK_TIMEOUT_NEVER:
options[i] = getString(R.string.value_never);
break;
case PreferencesUtils.AUTO_RESUME_TRACK_TIMEOUT_ALWAYS:
options[i] = getString(R.string.value_always);
break;
default:
options[i] = getString(R.string.value_integer_minute, value);
}
}
return options;
}
}
@@ -0,0 +1,141 @@
/*
* Copyright 2012 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.settings;
import com.google.android.apps.mytracks.services.sensors.ant.AntUtils;
import com.google.android.apps.mytracks.util.BluetoothDeviceUtils;
import com.google.android.maps.mytracks.R;
import android.bluetooth.BluetoothAdapter;
import android.content.Intent;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceScreen;
import android.provider.Settings;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* An activity for accessing sensor settings.
*
* @author Jimmy Shih
*/
public class SensorSettingsActivity extends AbstractSettingsActivity {
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
addPreferencesFromResource(R.xml.sensor_settings);
ListPreference sensorTypeListPreference = (ListPreference) findPreference(
getString(R.string.sensor_type_key));
List<String> sensorTypeEntries = Arrays.asList(getResources().getStringArray(
AntUtils.hasAntSupport(this) ? R.array.sensor_type_all_options
: R.array.sensor_type_bluetooth_options));
List<String> sensorTypeEntryValues = Arrays.asList(getResources().getStringArray(
AntUtils.hasAntSupport(this) ? R.array.sensor_type_all_values
: R.array.sensor_type_bluetooth_values));
sensorTypeListPreference.setEntries(sensorTypeEntries.toArray(
new CharSequence[sensorTypeEntries.size()]));
sensorTypeListPreference.setEntryValues(
sensorTypeEntryValues.toArray(new CharSequence[sensorTypeEntryValues.size()]));
sensorTypeListPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
updateUiBySensorType((String) newValue);
return true;
}
});
updateUiBySensorType(sensorTypeListPreference.getValue());
findPreference(getString(R.string.settings_sensor_bluetooth_pairing_key))
.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
Intent settingsIntent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
startActivity(settingsIntent);
return true;
}
});
if (!AntUtils.hasAntSupport(this)) {
PreferenceScreen rootPreferenceScreen = (PreferenceScreen) findPreference(
getString(R.string.settings_sensor_root_key));
rootPreferenceScreen.removePreference(
findPreference(getString(R.string.settings_sensor_ant_key)));
}
}
/**
* Updates the UI based on the sensor type.
*
* @param sensorType the sensor type
*/
@SuppressWarnings("deprecation")
private void updateUiBySensorType(String sensorType) {
boolean isBluetooth = getString(R.string.sensor_type_value_polar).equals(sensorType)
|| getString(R.string.sensor_type_value_zephyr).equals(sensorType);
findPreference(getString(R.string.settings_sensor_bluetooth_key)).setEnabled(isBluetooth);
Preference antHeartRateSensorId = findPreference(
getString(R.string.ant_heart_rate_sensor_id_key));
if (antHeartRateSensorId != null) {
antHeartRateSensorId.setEnabled(getString(R.string.sensor_type_value_ant).equals(sensorType));
}
Preference antSrmBridgetSensorId = findPreference(
getString(R.string.ant_srm_bridge_sensor_id_key));
if (antSrmBridgetSensorId != null) {
antSrmBridgetSensorId.setEnabled(
getString(R.string.sensor_type_value_srm_ant_bridge).equals(sensorType));
}
}
@Override
protected void onResume() {
super.onResume();
updateBluetoothSensorListPreference();
}
/**
* Updates the bluetooth sensor list preference.
*/
private void updateBluetoothSensorListPreference() {
@SuppressWarnings("deprecation")
ListPreference bluetoothSensorListPreference = (ListPreference) findPreference(
getString(R.string.bluetooth_sensor_key));
List<String> entries = new ArrayList<String>();
List<String> entryValues = new ArrayList<String>();
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter != null) {
BluetoothDeviceUtils.populateDeviceLists(bluetoothAdapter, entries, entryValues);
}
bluetoothSensorListPreference.setEntries(entries.toArray(new CharSequence[entries.size()]));
bluetoothSensorListPreference.setEntryValues(entryValues.toArray(
new CharSequence[entryValues.size()]));
if (entries.size() == 1) {
bluetoothSensorListPreference.setValueIndex(0);
}
}
}
@@ -0,0 +1,189 @@
/*
* 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.settings;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.util.Log;
import android.widget.Toast;
/**
* An activity for accessing settings.
*
* @author Leif Hendrik Wilden
* @author Rodrigo Damazio
*/
public class SettingsActivity extends AbstractSettingsActivity {
private static final String TAG = SettingsActivity.class.getSimpleName();
private static final int DIALOG_CONFIRM_RESET_ID = 0;
private Preference resetPreference;
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
addPreferencesFromResource(R.xml.settings);
Preference mapPreference = findPreference(getString(R.string.settings_map_key));
mapPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent intent = IntentUtils.newIntent(SettingsActivity.this, MapSettingsActivity.class);
startActivity(intent);
return true;
}
});
Preference chartPreference = findPreference(getString(R.string.settings_chart_key));
chartPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent intent = IntentUtils.newIntent(SettingsActivity.this, ChartSettingsActivity.class);
startActivity(intent);
return true;
}
});
Preference statsPreference = findPreference(getString(R.string.settings_stats_key));
statsPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent intent = IntentUtils.newIntent(SettingsActivity.this, StatsSettingsActivity.class);
startActivity(intent);
return true;
}
});
Preference recordingPreference = findPreference(getString(R.string.settings_recording_key));
recordingPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent intent = IntentUtils.newIntent(
SettingsActivity.this, RecordingSettingsActivity.class);
startActivity(intent);
return true;
}
});
Preference sharingPreference = findPreference(getString(R.string.settings_sharing_key));
sharingPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent intent = IntentUtils.newIntent(SettingsActivity.this, SharingSettingsActivity.class);
startActivity(intent);
return true;
}
});
Preference sensorPreference = findPreference(getString(R.string.settings_sensor_key));
sensorPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent intent = IntentUtils.newIntent(SettingsActivity.this, SensorSettingsActivity.class);
startActivity(intent);
return true;
}
});
Preference backupPreference = findPreference(getString(R.string.settings_backup_key));
backupPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent intent = IntentUtils.newIntent(SettingsActivity.this, BackupSettingsActivity.class);
startActivity(intent);
return true;
}
});
resetPreference = findPreference(getString(R.string.settings_reset_key));
resetPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference arg0) {
showDialog(DIALOG_CONFIRM_RESET_ID);
return true;
}
});
}
@Override
protected void onResume() {
super.onResume();
boolean isRecording = PreferencesUtils.getLong(this, R.string.recording_track_id_key)
!= PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
resetPreference.setEnabled(!isRecording);
resetPreference.setSummary(isRecording ? R.string.settings_not_while_recording
: R.string.settings_reset_summary);
}
@Override
protected Dialog onCreateDialog(int id) {
if (id != DIALOG_CONFIRM_RESET_ID) {
return null;
}
return DialogUtils.createConfirmationDialog(
this, R.string.settings_reset_confirm_message, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int button) {
onResetPreferencesConfirmed();
}
});
}
/**
* Callback when the user confirms resetting all settings.
*/
private void onResetPreferencesConfirmed() {
// Change preferences in a separate thread
new Thread() {
@Override
public void run() {
Log.i(TAG, "Resetting all settings");
SharedPreferences sharedPreferences = getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
// Actually wipe preferences and save synchronously
sharedPreferences.edit().clear().commit();
// Give UI feedback in the UI thread
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(SettingsActivity.this, R.string.settings_reset_done, Toast.LENGTH_SHORT)
.show();
// Restart the settings activity so all changes are loaded
Intent intent = getIntent()
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
});
}
}.start();
}
}
@@ -0,0 +1,75 @@
/*
* Copyright 2012 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.settings;
import com.google.android.apps.mytracks.util.DialogUtils;
import com.google.android.maps.mytracks.R;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
/**
* An activity for accessing the sharing settings.
*
* @author Jimmy Shih
*/
public class SharingSettingsActivity extends AbstractSettingsActivity {
private static final int DIALOG_CONFIRM_ALLOW_ACCESS_ID = 0;
private CheckBoxPreference allowAccessCheckBoxPreference;
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
addPreferencesFromResource(R.xml.sharing_settings);
allowAccessCheckBoxPreference = (CheckBoxPreference) findPreference(
getString(R.string.allow_access_key));
allowAccessCheckBoxPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if ((Boolean) newValue) {
showDialog(DIALOG_CONFIRM_ALLOW_ACCESS_ID);
return false;
} else {
return true;
}
}
});
}
@Override
protected Dialog onCreateDialog(int id) {
if (id != DIALOG_CONFIRM_ALLOW_ACCESS_ID) {
return null;
}
return DialogUtils.createConfirmationDialog(this,
R.string.settings_sharing_allow_access_confirm_message,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int button) {
allowAccessCheckBoxPreference.setChecked(true);
}
});
}
}
@@ -0,0 +1,81 @@
/*
* Copyright 2012 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.settings;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
/**
* An activity for accessing stats settings.
*
* @author Jimmy Shih
*/
public class StatsSettingsActivity extends AbstractSettingsActivity {
/*
* Note that sharedPreferenceChangeListenr cannot be an anonymous inner class.
* Anonymous inner class will get garbage collected.
*/
private final OnSharedPreferenceChangeListener
sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
// Note that key can be null
if (PreferencesUtils.getKey(StatsSettingsActivity.this, R.string.metric_units_key)
.equals(key)) {
updateUi();
}
}
};
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
addPreferencesFromResource(R.xml.stats_settings);
getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE)
.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
}
@Override
protected void onResume() {
super.onResume();
updateUi();
}
@SuppressWarnings("deprecation")
private void updateUi() {
CheckBoxPreference reportSpeedCheckBoxPreference = (CheckBoxPreference) findPreference(
getString(R.string.report_speed_key));
boolean metric = PreferencesUtils.getBoolean(
this, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
reportSpeedCheckBoxPreference.setSummaryOn(
metric ? getString(R.string.settings_stats_rate_speed_metric)
: getString(R.string.settings_stats_rate_speed_imperial));
reportSpeedCheckBoxPreference.setSummaryOff(
metric ? getString(R.string.settings_stats_rate_pace_metric)
: getString(R.string.settings_stats_rate_pace_imperial));
}
}
@@ -19,6 +19,7 @@ package com.google.android.apps.mytracks.stats;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import android.location.Location;
import android.util.Log;
@@ -91,8 +92,7 @@ public class TripStatisticsBuilder {
*/
private long totalLocations = 0;
private int minRecordingDistance =
Constants.DEFAULT_MIN_RECORDING_DISTANCE;
private int minRecordingDistance = PreferencesUtils.MIN_RECORDING_DISTANCE_DEFAULT;
/**
* Creates a new trip starting at the given time.
@@ -28,13 +28,16 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.TextView;
import java.util.List;
/**
* API level 11 specific implementation of the {@link ApiAdapter}.
*
*
* @author Jimmy Shih
*/
@TargetApi(11)
@@ -51,15 +54,14 @@ public class Api11Adapter extends Api10Adapter {
}
@Override
public void configureListViewContextualMenu(final Activity activity, ListView listView, final int menuId,
final int actionModeTitleId,
public void configureListViewContextualMenu(final Activity activity, ListView listView,
final int menuId, final int actionModeTitleId,
final ContextualActionModeCallback contextualActionModeCallback) {
listView.setOnItemLongClickListener(new OnItemLongClickListener() {
ActionMode actionMode;
@Override
public boolean onItemLongClick(
AdapterView<?> parent, View view, int position, final long id) {
AdapterView<?> parent, View view, final int position, final long id) {
if (actionMode != null) {
return false;
}
@@ -69,21 +71,19 @@ public class Api11Adapter extends Api10Adapter {
mode.getMenuInflater().inflate(menuId, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
// Return false to indicate no change.
return false;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
actionMode = null;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return contextualActionModeCallback.onClick(item.getItemId(), id);
mode.finish();
return contextualActionModeCallback.onClick(item.getItemId(), position, id);
}
});
TextView textView = (TextView) view.findViewById(actionModeTitleId);
@@ -95,17 +95,23 @@ public class Api11Adapter extends Api10Adapter {
}
});
};
@Override
public void configureSearchWidget(Activity activity, MenuItem menuItem) {
public void configureSearchWidget(Activity activity, final MenuItem menuItem) {
SearchManager searchManager = (SearchManager) activity.getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) menuItem.getActionView();
searchView.setSearchableInfo(searchManager.getSearchableInfo(activity.getComponentName()));
searchView.setQueryRefinementEnabled(true);
}
@Override
public boolean handleSearchMenuSelection(Activity activity) {
// Returns false to allow the platform to expand the search widget.
return false;
}
}
@Override
public <T> void addAllToArrayAdapter(ArrayAdapter<T> arrayAdapter, List<T> items) {
arrayAdapter.addAll(items);
}
}
@@ -20,10 +20,11 @@ import android.annotation.TargetApi;
import android.app.ActionBar;
import android.app.Activity;
import android.view.MenuItem;
import android.widget.SearchView;
/**
* API level 14 specific implementation of the {@link ApiAdapter}.
*
*
* @author Jimmy Shih
*/
@TargetApi(14)
@@ -35,7 +36,35 @@ public class Api14Adapter extends Api11Adapter {
actionBar.setHomeButtonEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(true);
}
@Override
public void configureSearchWidget(Activity activity, final MenuItem menuItem) {
super.configureSearchWidget(activity, menuItem);
SearchView searchView = (SearchView) menuItem.getActionView();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
menuItem.collapseActionView();
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
return false;
}
});
searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() {
@Override
public boolean onSuggestionSelect(int position) {
return false;
}
@Override
public boolean onSuggestionClick(int position) {
menuItem.collapseActionView();
return false;
}
});
}
@Override
public boolean handleSearchKey(MenuItem menuItem) {
menuItem.expandActionView();
@@ -33,11 +33,13 @@ import android.content.SharedPreferences.Editor;
import android.util.Log;
import android.view.MenuItem;
import android.view.Window;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
/**
* API level 7 specific implementation of the {@link ApiAdapter}.
@@ -131,7 +133,14 @@ public class Api7Adapter implements ApiAdapter {
activity.onSearchRequested();
return true;
}
@Override
public <T> void addAllToArrayAdapter(ArrayAdapter<T> arrayAdapter, List<T> items) {
for (T item : items) {
arrayAdapter.add(item);
}
}
@Override
public boolean handleSearchKey(MenuItem menuItem) {
// Return false and allow the framework to handle the search key.
@@ -26,9 +26,11 @@ import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.SharedPreferences;
import android.view.MenuItem;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.io.IOException;
import java.util.List;
/**
* A set of methods that may be implemented differently depending on the Android
@@ -160,6 +162,16 @@ public interface ApiAdapter {
*/
public boolean handleSearchMenuSelection(Activity activity);
/**
* Adds all items to an array adapter.
*
* Due to changes in API level 11.
*s
* @param arrayAdapter the array adapter
* @param items list of items
*/
public <T> void addAllToArrayAdapter(ArrayAdapter<T> arrayAdapter, List<T> items);
/**
* Handles the search key press. Returns true if handled.
*
@@ -24,17 +24,17 @@ import java.util.Set;
/**
* Utilities for dealing with bluetooth devices.
*
*
* @author Rodrigo Damazio
*/
public class BluetoothDeviceUtils {
private BluetoothDeviceUtils() {}
/**
* Populates the device names and the device addresses with all the suitable
* bluetooth devices.
*
*
* @param bluetoothAdapter the bluetooth adapter
* @param deviceNames list of device names
* @param deviceAddresses list of device addresses
@@ -16,13 +16,11 @@
package com.google.android.apps.mytracks.util;
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;
import android.content.Context;
import android.content.SharedPreferences;
import java.util.Vector;
@@ -47,18 +45,12 @@ public class ChartURLGenerator {
* @param track The track for this chart
* @param context The current appplication context
*/
public static String getChartUrl(Vector<Double> distances,
Vector<Double> elevations, Track track, Context context) {
SharedPreferences preferences = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
boolean metricUnits = true;
if (preferences != null) {
metricUnits = preferences.getBoolean(
context.getString(R.string.metric_units_key), true);
}
return getChartUrl(distances, elevations, track,
context.getString(R.string.stat_elevation), metricUnits);
public static String getChartUrl(
Vector<Double> distances, Vector<Double> elevations, Track track, Context context) {
boolean metricUnits = PreferencesUtils.getBoolean(
context, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
return getChartUrl(
distances, elevations, track, context.getString(R.string.stats_elevation), metricUnits);
}
/**
@@ -1,47 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.util;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
/**
* Utilities for checking units.
*
* @author Jimmy Shih
*/
public class CheckUnitsUtils {
private static final String CHECK_UNITS_PREFERENCE_FILE = "checkunits";
private static final String CHECK_UNITS_PREFERENCE_KEY = "checkunits.checked";
private CheckUnitsUtils() {}
public static boolean getCheckUnitsValue(Context context) {
SharedPreferences sharedPreferences = context.getSharedPreferences(
CHECK_UNITS_PREFERENCE_FILE, Context.MODE_PRIVATE);
return sharedPreferences.getBoolean(CHECK_UNITS_PREFERENCE_KEY, false);
}
public static void setCheckUnitsValue(Context context) {
SharedPreferences sharedPreferences = context.getSharedPreferences(
CHECK_UNITS_PREFERENCE_FILE, Context.MODE_PRIVATE);
Editor editor = sharedPreferences.edit().putBoolean(CHECK_UNITS_PREFERENCE_KEY, true);
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
}
}
@@ -0,0 +1,42 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.util;
import android.content.Context;
import android.content.Intent;
/**
* Utilities for creating intents.
*
* @author Jimmy Shih
*/
public class IntentUtils {
private IntentUtils() {}
/**
* Creates an intent with {@link Intent#FLAG_ACTIVITY_CLEAR_TOP} and
* {@link Intent#FLAG_ACTIVITY_NEW_TASK}.
*
* @param context the context
* @param cls the class
*/
public static final Intent newIntent(Context context, Class<?> cls) {
return new Intent(context, cls).addFlags(
Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
}
}
@@ -0,0 +1,87 @@
/*
* Copyright 2012 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.maps.mytracks.R;
import android.view.View;
import android.widget.TextView;
/**
* Utilities to display a list item.
*
* @author Jimmy Shih
*/
public class ListItemUtils {
private ListItemUtils() {}
/**
* Sets a list item.
*
* @param view the list item view
* @param name the name value
* @param iconId the icon id
* @param category the category value
* @param totalTime the total time value
* @param totalDistance the total distance value
* @param startTime the start time value
* @param description the description value
*/
public static void setListItem(View view,
String name,
int iconId,
String category,
String totalTime,
String totalDistance,
String startTime,
String description) {
TextView nameTextView = (TextView) view.findViewById(R.id.list_item_name);
nameTextView.setText(name);
nameTextView.setCompoundDrawablesWithIntrinsicBounds(iconId, 0, 0, 0);
TextView categoryTextView = (TextView) view.findViewById(R.id.list_item_category);
setTextView(categoryTextView, category);
TextView totalTimeTextView = (TextView) view.findViewById(R.id.list_item_total_time);
setTextView(totalTimeTextView, totalTime);
TextView totalDistanceTextView = (TextView) view.findViewById(R.id.list_item_total_distance);
setTextView(totalDistanceTextView, totalDistance);
TextView startTimeTextView = (TextView) view.findViewById(R.id.list_item_start_time);
setTextView(startTimeTextView, startTime);
TextView descriptionTextView = (TextView) view.findViewById(R.id.list_item_description);
setTextView(descriptionTextView, description);
}
/**
* Sets a text view.
*
* @param textView the text view
* @param value the value for the text view
*/
private static void setTextView(TextView textView, String value) {
if (value == null || value.length() == 0) {
textView.setVisibility(View.GONE);
} else {
textView.setVisibility(View.VISIBLE);
textView.setText(value);
}
}
}
@@ -17,7 +17,6 @@
package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.Constants;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.content.SharedPreferences;
@@ -30,81 +29,140 @@ import android.content.SharedPreferences.Editor;
*/
public class PreferencesUtils {
/*
* Preferences values. The defaults need to match the defaults in the xml
* files.
*/
public static final boolean ALLOW_ACCESS_DEFAULT = false;
public static final int ANNOUNCEMENT_FREQUENCY_DEFAULT = 0;
public static final int AUTO_RESUME_TRACK_CURRENT_RETRY_DEFAULT = 0;
public static final int AUTO_RESUME_TRACK_TIMEOUT_ALWAYS = -1;
public static final int AUTO_RESUME_TRACK_TIMEOUT_DEFAULT = 10;
public static final int AUTO_RESUME_TRACK_TIMEOUT_NEVER = 0;
public static final String BLUETOOTH_SENSOR_DEFAULT = "";
public static final boolean CHART_BY_DISTANCE_DEFAULT = true;
public static final boolean CHART_SHOW_CADENCE_DEFAULT = true;
public static final boolean CHART_SHOW_ELEVATION_DEFAULT = true;
public static final boolean CHART_SHOW_HEART_RATE_DEFAULT = true;
public static final boolean CHART_SHOW_POWER_DEFAULT = true;
public static final boolean CHART_SHOW_SPEED_DEFAULT = true;
public static final String DEFAULT_ACTIVITY_DEFAULT = "";
public static final boolean DEFAULT_MAP_PUBLIC_DEFAULT = true;
public static final int MAX_RECORDING_DISTANCE_DEFAULT = 200;
public static final boolean METRIC_UNITS_DEFAULT = true;
public static final int MIN_RECORDING_DISTANCE_DEFAULT = 5;
public static final int MIN_RECORDING_INTERVAL_ADAPT_ACCURACY = -1;
public static final int MIN_RECORDING_INTERVAL_ADAPT_BATTERY_LIFE = -2;
public static final int MIN_RECORDING_INTERVAL_DEFAULT = 0;
public static final int MIN_REQUIRED_ACCURACY_DEFAULT = 200;
public static final int MIN_REQUIRED_ACCURACY_EXCELLENT = 10;
public static final int MIN_REQUIRED_ACCURACY_POOR = 5000;
public static final int PERIODIC_TASK_OFF = 0;
public static final boolean PICK_EXISTING_MAP_DEFAULT = false;
public static final boolean PICK_STATISTICS_MARKER_DEFAULT = true;
public static final String PREFERRED_ACCOUNT_DEFAULT = "";
public static final long RECORDING_TRACK_ID_DEFAULT = -1L;
public static final boolean REPORT_SPEED_DEFAULT = true;
public static final long SELECTED_TRACK_ID_DEFAULT = -1L;
public static final boolean SEND_TO_DOCS_DEFAULT = true;
public static final boolean SEND_TO_FUSION_TABLES_DEFAULT = true;
public static final boolean SEND_TO_MAPS_DEFAULT = true;
public static final boolean SHARE_URL_ONLY_DEFAULT = false;
public static final boolean SHOW_CHECK_UNITS_DIALOG_DEFAULT = true;
public static final boolean SHOW_WELCOME_DIALOG_DEFAULT = true;
public static final int SPLIT_FREQUENCY_DEFAULT = 0;
public static final boolean STATS_SHOW_COORDINATE_DEFAULT = false;
public static final boolean STATS_SHOW_ELEVATION_DEFAULT = false;
public static final boolean STATS_SHOW_GRADE_DEFAULT = false;
public static final boolean STATS_USE_TOTAL_TIME_DEFAULT = true;
public static final int TRACK_COLOR_MODE_MEDIUM_DEFAULT = 15;
public static final int TRACK_COLOR_MODE_PERCENTAGE_DEFAULT = 25;
public static final int TRACK_COLOR_MODE_SLOW_DEFAULT = 9;
private PreferencesUtils() {}
/**
* Gets the recording track id key.
*
* @param context the context
*/
public static String getRecordingTrackIdKey(Context context) {
return getKey(context, R.string.recording_track_id_key);
}
/**
* Gets the recording track id.
*
* @param context the context
*/
public static long getRecordingTrackId(Context context) {
return getLong(context, R.string.recording_track_id_key);
}
/**
* Sets the recording track id.
*
* @param context the context
* @param trackId the track id
*/
public static void setRecordingTrackId(Context context, long trackId) {
setLong(context, R.string.recording_track_id_key, trackId);
}
/**
* Gets the selected track id key.
*
* @param context the context
*/
public static String getSelectedTrackIdKey(Context context) {
return getKey(context, R.string.selected_track_id_key);
}
/**
* Gets the selected track id.
*
* @param context the context
*/
public static long getSelectedTrackId(Context context) {
return getLong(context, R.string.selected_track_id_key);
}
/**
* Sets the selected track id.
*
* @param context the context
* @param trackId the track id
*/
public static void setSelectedTrackId(Context context, long trackId) {
setLong(context, R.string.selected_track_id_key, trackId);
}
/**
* Gets a preference key
*
* @param context the context
* @param keyId the key id
*/
private static String getKey(Context context, int keyId) {
public static String getKey(Context context, int keyId) {
return context.getString(keyId);
}
/**
* Gets a boolean preference value.
*
* @param context the context
* @param keyId the key id
* @param defaultValue the default value
*/
public static boolean getBoolean(Context context, int keyId, boolean defaultValue) {
SharedPreferences sharedPreferences = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
return sharedPreferences.getBoolean(getKey(context, keyId), defaultValue);
}
/**
* Sets a boolean preference value.
*
* @param context the context
* @param keyId the key id
* @param value the value
*/
public static void setBoolean(Context context, int keyId, boolean value) {
SharedPreferences sharedPreferences = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
Editor editor = sharedPreferences.edit();
editor.putBoolean(getKey(context, keyId), value);
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
}
/**
* Gets an integer preference value.
*
* @param context the context
* @param keyId the key id
* @param defaultValue the default value
*/
public static int getInt(Context context, int keyId, int defaultValue) {
SharedPreferences sharedPreferences = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
return sharedPreferences.getInt(getKey(context, keyId), defaultValue);
}
/**
* Sets an integer preference value.
*
* @param context the context
* @param keyId the key id
* @param value the value
*/
public static void setInt(Context context, int keyId, int value) {
SharedPreferences sharedPreferences = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
Editor editor = sharedPreferences.edit();
editor.putInt(getKey(context, keyId), value);
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
}
/**
* Gets a long preference value.
*
* @param context the context
* @param keyId the key id
*/
private static long getLong(Context context, int keyId) {
public static long getLong(Context context, int keyId) {
SharedPreferences sharedPreferences = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
return sharedPreferences.getLong(getKey(context, keyId), -1L);
@@ -117,11 +175,39 @@ public class PreferencesUtils {
* @param keyId the key id
* @param value the value
*/
private static void setLong(Context context, int keyId, long value) {
public static void setLong(Context context, int keyId, long value) {
SharedPreferences sharedPreferences = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
Editor editor = sharedPreferences.edit();
editor.putLong(getKey(context, keyId), value);
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
}
/**
* Gets a string preference value.
*
* @param context the context
* @param keyId the key id
* @param defaultValue default value
*/
public static String getString(Context context, int keyId, String defaultValue) {
SharedPreferences sharedPreferences = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
return sharedPreferences.getString(getKey(context, keyId), defaultValue);
}
/**
* Sets a string preference value.
*
* @param context the context
* @param keyId the key id
* @param value the value
*/
public static void setString(Context context, int keyId, String value) {
SharedPreferences sharedPreferences = context.getSharedPreferences(
Constants.SETTINGS_NAME, Context.MODE_PRIVATE);
Editor editor = sharedPreferences.edit();
editor.putString(getKey(context, keyId), value);
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
}
}
@@ -16,9 +16,12 @@
package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.location.Location;
import android.view.View;
import android.widget.TextView;
/**
@@ -30,6 +33,166 @@ public class StatsUtils {
private StatsUtils() {}
/**
* Sets the location values.
*
* @param activity the activity
* @param location the location
* @param showAll true to show all the fields, false to show only the
* elevation field
*/
public static void setLocationValues(Activity activity, Location location, boolean showAll) {
boolean metricUnits = PreferencesUtils.getBoolean(
activity, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
boolean reportSpeed = PreferencesUtils.getBoolean(
activity, R.string.report_speed_key, PreferencesUtils.REPORT_SPEED_DEFAULT);
// Set elevation
boolean showElevation = PreferencesUtils.getBoolean(
activity, R.string.stats_show_elevation_key, PreferencesUtils.STATS_SHOW_ELEVATION_DEFAULT);
if (showElevation) {
double altitude = location == null ? Double.NaN : location.getAltitude();
setElevationValue(activity, R.id.stats_elevation_value, altitude, metricUnits);
}
if (!showAll) {
return;
}
// Set speed/pace
setSpeedLabel(
activity, R.id.stats_speed_label, R.string.stats_speed, R.string.stats_pace, reportSpeed);
double speed = location == null ? Double.NaN : location.getSpeed();
setSpeedValue(activity, R.id.stats_speed_value, speed, metricUnits, reportSpeed);
// Set coordinate
boolean showCoordinate = PreferencesUtils.getBoolean(activity,
R.string.stats_show_coordinate_key, PreferencesUtils.STATS_SHOW_COORDINATE_DEFAULT);
View coordinateLabelTableRow = activity.findViewById(R.id.stats_coordinate_label_table_row);
View coordinateValueTableRow = activity.findViewById(R.id.stats_coordinate_value_table_row);
coordinateLabelTableRow.setVisibility(showCoordinate ? View.VISIBLE : View.GONE);
coordinateValueTableRow.setVisibility(showCoordinate ? View.VISIBLE : View.GONE);
if (showCoordinate) {
double latitude = location == null ? Double.NaN : location.getLatitude();
double longitude = location == null ? Double.NaN : location.getLongitude();
setCoordinateValue(activity, R.id.stats_latitude_value, latitude);
setCoordinateValue(activity, R.id.stats_longitude_value, longitude);
}
}
/**
* Sets the total time value.
*
* @param activity the activity
* @param totalTime the total time
*/
public static void setTotalTimeValue(Activity activity, long totalTime) {
setTimeValue(activity, R.id.stats_total_time_value, totalTime);
}
/**
* Sets the trip statistics values.
*
* @param activity the activity
* @param tripStatistics the trip statistics
*/
public static void setTripStatisticsValues(Activity activity, TripStatistics tripStatistics) {
boolean metricUnits = PreferencesUtils.getBoolean(
activity, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
boolean reportSpeed = PreferencesUtils.getBoolean(
activity, R.string.report_speed_key, PreferencesUtils.REPORT_SPEED_DEFAULT);
boolean useTotalTime = PreferencesUtils.getBoolean(
activity, R.string.stats_use_total_time_key, PreferencesUtils.STATS_USE_TOTAL_TIME_DEFAULT);
// Set total distance
double totalDistance = tripStatistics == null ? Double.NaN : tripStatistics.getTotalDistance();
setDistanceValue(activity, R.id.stats_total_distance_value, totalDistance, metricUnits);
// Set total time/moving time
setTimeLabel(activity, R.id.stats_total_time_label, R.string.stats_total_time,
R.string.stats_moving_time, useTotalTime);
long totalTime;
if (tripStatistics == null) {
totalTime = -1L;
} else {
totalTime = useTotalTime ? tripStatistics.getTotalTime() : tripStatistics.getMovingTime();
}
setTimeValue(activity, R.id.stats_total_time_value, totalTime);
// Set average speed/moving average speed
if (useTotalTime) {
setSpeedLabel(activity, R.id.stats_average_speed_label, R.string.stats_average_speed,
R.string.stats_average_pace, reportSpeed);
} else {
setSpeedLabel(activity, R.id.stats_average_speed_label, R.string.stats_average_moving_speed,
R.string.stats_average_moving_pace, reportSpeed);
}
double averageSpeed;
if (tripStatistics == null) {
averageSpeed = Double.NaN;
} else {
averageSpeed = useTotalTime ? tripStatistics.getAverageSpeed()
: tripStatistics.getAverageMovingSpeed();
}
setSpeedValue(activity, R.id.stats_average_speed_value, averageSpeed, metricUnits, reportSpeed);
// Set max speed
setSpeedLabel(activity, R.id.stats_max_speed_label, R.string.stats_max_speed,
R.string.stats_fastest_pace, reportSpeed);
double maxSpeed = tripStatistics == null ? Double.NaN : tripStatistics.getMaxSpeed();
setSpeedValue(activity, R.id.stats_max_speed_value, maxSpeed, metricUnits, reportSpeed);
// Set elevation
boolean showElevation = PreferencesUtils.getBoolean(
activity, R.string.stats_show_elevation_key, PreferencesUtils.STATS_SHOW_ELEVATION_DEFAULT);
View elevationLabelTableRow1 = activity.findViewById(R.id.stats_elevation_label_table_row1);
View elevationValueTableRow1 = activity.findViewById(R.id.stats_elevation_value_table_row1);
View elevationLabelTableRow2 = activity.findViewById(R.id.stats_elevation_label_table_row2);
View elevationValueTableRow2 = activity.findViewById(R.id.stats_elevation_value_table_row2);
elevationLabelTableRow1.setVisibility(showElevation ? View.VISIBLE : View.GONE);
elevationValueTableRow1.setVisibility(showElevation ? View.VISIBLE : View.GONE);
elevationLabelTableRow2.setVisibility(showElevation ? View.VISIBLE : View.GONE);
elevationValueTableRow2.setVisibility(showElevation ? View.VISIBLE : View.GONE);
if (showElevation) {
double elevationGain = tripStatistics == null ? Double.NaN
: tripStatistics.getTotalElevationGain();
double minElevation = tripStatistics == null ? Double.NaN : tripStatistics.getMinElevation();
double maxElevation = tripStatistics == null ? Double.NaN : tripStatistics.getMaxElevation();
setElevationValue(activity, R.id.stats_elevation_gain_value, elevationGain, metricUnits);
setElevationValue(activity, R.id.stats_min_elevation_value, minElevation, metricUnits);
setElevationValue(activity, R.id.stats_max_elevation_value, maxElevation, metricUnits);
}
// Set grade
boolean showGrade = PreferencesUtils.getBoolean(
activity, R.string.stats_show_grade_key, PreferencesUtils.STATS_SHOW_GRADE_DEFAULT);
View gradeLabelTableRow = activity.findViewById(R.id.stats_grade_label_table_row);
View gradeValueTableRow = activity.findViewById(R.id.stats_grade_value_table_row);
gradeLabelTableRow.setVisibility(showGrade ? View.VISIBLE : View.GONE);
gradeValueTableRow.setVisibility(showGrade ? View.VISIBLE : View.GONE);
if (showGrade) {
double minGrade = tripStatistics == null ? Double.NaN : tripStatistics.getMinGrade();
double maxGrade = tripStatistics == null ? Double.NaN : tripStatistics.getMaxGrade();
setGradeValue(activity, R.id.stats_min_grade_value, minGrade);
setGradeValue(activity, R.id.stats_max_grade_value, maxGrade);
}
}
/**
* Sets a time label.
*
* @param activity the activity
* @param id the time label resource id
* @param totalTimeId the total time string id
* @param movingTimeId the moving time string id
* @param totalTime true to use total time
*/
private static void setTimeLabel(Activity activity, int id, int totalTimeId, int movingTimeId,
boolean totalTime) {
TextView textView = (TextView) activity.findViewById(id);
textView.setText(totalTime ? totalTimeId : movingTimeId);
}
/**
* Sets a speed label.
*
@@ -39,7 +202,7 @@ public class StatsUtils {
* @param paceId the pace string id
* @param reportSpeed true to report speed
*/
public static void setSpeedLabel(
private static void setSpeedLabel(
Activity activity, int id, int speedId, int paceId, boolean reportSpeed) {
TextView textView = (TextView) activity.findViewById(id);
textView.setText(reportSpeed ? speedId : paceId);
@@ -51,30 +214,34 @@ public class StatsUtils {
* @param activity the activity
* @param id the speed value resource id
* @param speed the speed in meters per second
* @param reportSpeed true to report speed
* @param metricUnits true to display in metric units
* @param reportSpeed true to report speed
*/
public static void setSpeedValue(
Activity activity, int id, double speed, boolean reportSpeed, boolean metricUnits) {
private static void setSpeedValue(
Activity activity, int id, double speed, boolean metricUnits, boolean reportSpeed) {
TextView textView = (TextView) activity.findViewById(id);
speed *= UnitConversions.MS_TO_KMH;
String value;
if (metricUnits) {
if (reportSpeed) {
value = activity.getString(R.string.value_float_kilometer_hour, speed);
} else {
// convert from hours to minutes
double pace = speed == 0 ? 0.0 : 60.0 / speed;
value = activity.getString(R.string.value_float_minute_kilometer, pace);
}
if (Double.isNaN(speed) || Double.isInfinite(speed)) {
value = activity.getString(R.string.value_unknown);
} else {
speed *= UnitConversions.KM_TO_MI;
if (reportSpeed) {
value = activity.getString(R.string.value_float_mile_hour, speed);
speed *= UnitConversions.MS_TO_KMH;
if (metricUnits) {
if (reportSpeed) {
value = activity.getString(R.string.value_float_kilometer_hour, speed);
} else {
// convert from hours to minutes
double pace = speed == 0 ? 0.0 : 60.0 / speed;
value = activity.getString(R.string.value_float_minute_kilometer, pace);
}
} else {
// convert from hours to minutes
double pace = speed == 0 ? 0.0 : 60.0 / speed;
value = activity.getString(R.string.value_float_minute_mile, pace);
speed *= UnitConversions.KM_TO_MI;
if (reportSpeed) {
value = activity.getString(R.string.value_float_mile_hour, speed);
} else {
// convert from hours to minutes
double pace = speed == 0 ? 0.0 : 60.0 / speed;
value = activity.getString(R.string.value_float_minute_mile, pace);
}
}
}
textView.setText(value);
@@ -88,16 +255,20 @@ public class StatsUtils {
* @param distance the distance in meters
* @param metricUnits true to display in metric units
*/
public static void setDistanceValue(
private static void setDistanceValue(
Activity activity, int id, double distance, boolean metricUnits) {
TextView textView = (TextView) activity.findViewById(id);
distance *= UnitConversions.M_TO_KM;
String value;
if (metricUnits) {
value = activity.getString(R.string.value_float_kilometer, distance);
if (Double.isNaN(distance) || Double.isInfinite(distance)) {
value = activity.getString(R.string.value_unknown);
} else {
distance *= UnitConversions.KM_TO_MI;
value = activity.getString(R.string.value_float_mile, distance);
distance *= UnitConversions.M_TO_KM;
if (metricUnits) {
value = activity.getString(R.string.value_float_kilometer, distance);
} else {
distance *= UnitConversions.KM_TO_MI;
value = activity.getString(R.string.value_float_mile, distance);
}
}
textView.setText(value);
}
@@ -109,31 +280,33 @@ public class StatsUtils {
* @param id the time value resource id
* @param time the time
*/
public static void setTimeValue(Activity activity, int id, long time) {
private static void setTimeValue(Activity activity, int id, long time) {
TextView textView = (TextView) activity.findViewById(id);
textView.setText(StringUtils.formatElapsedTime(time));
String value = time == -1L ? activity.getString(R.string.value_unknown)
: StringUtils.formatElapsedTime(time);
textView.setText(value);
}
/**
* Sets an altitude value.
* Sets an elevation value.
*
* @param activity the activity
* @param id the altitude value resource id
* @param altitude the altitude in meters
* @param id the elevation value resource id
* @param elevation the elevation in meters
* @param metricUnits true to display in metric units
*/
public static void setAltitudeValue(
Activity activity, int id, double altitude, boolean metricUnits) {
private static void setElevationValue(
Activity activity, int id, double elevation, boolean metricUnits) {
TextView textView = (TextView) activity.findViewById(id);
String value;
if (Double.isNaN(altitude) || Double.isInfinite(altitude)) {
if (Double.isNaN(elevation) || Double.isInfinite(elevation)) {
value = activity.getString(R.string.value_unknown);
} else {
if (metricUnits) {
value = activity.getString(R.string.value_float_meter, altitude);
value = activity.getString(R.string.value_float_meter, elevation);
} else {
altitude *= UnitConversions.M_TO_FT;
value = activity.getString(R.string.value_float_feet, altitude);
elevation *= UnitConversions.M_TO_FT;
value = activity.getString(R.string.value_float_feet, elevation);
}
}
textView.setText(value);
@@ -146,7 +319,7 @@ public class StatsUtils {
* @param id the grade value resource id
* @param grade the grade in fraction between 0 and 1
*/
public static void setGradeValue(Activity activity, int id, double grade) {
private static void setGradeValue(Activity activity, int id, double grade) {
TextView textView = (TextView) activity.findViewById(id);
String value;
if (Double.isNaN(grade) || Double.isInfinite(grade)) {
@@ -156,4 +329,23 @@ public class StatsUtils {
}
textView.setText(value);
}
/**
* Sets a coordinate value.
*
* @param activity the activity
* @param id the coordinate value resource id
* @param coordinate the coordinate in degrees
*/
private static void setCoordinateValue(Activity activity, int id, double coordinate) {
TextView textView = (TextView) activity.findViewById(id);
String value;
if (Double.isNaN(coordinate) || Double.isInfinite(coordinate)) {
value = activity.getString(R.string.value_unknown);
} else {
value = activity.getString(
R.string.value_coordinate_degree, Location.convert(coordinate, Location.FORMAT_DEGREES));
}
textView.setText(value);
}
}
@@ -157,19 +157,6 @@ public class StringUtils {
}
}
}
/**
* Formats the elapsed time and distance.
*
* @param context the context
* @param elapsedTime the elapsed time in milliseconds
* @param distance the distance in meters
* @param metric true to use metric. False to use imperial
*/
public static String formatTimeDistance(
Context context, long elapsedTime, double distance, boolean metric) {
return formatElapsedTime(elapsedTime) + " " + formatDistance(context, distance, metric);
}
/**
* Formats the given text as a XML CDATA element. This includes adding the
@@ -17,9 +17,11 @@
package com.google.android.apps.mytracks.util;
import com.google.android.apps.mytracks.TrackEditActivity;
import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.services.ITrackRecordingService;
import com.google.android.apps.mytracks.services.TrackRecordingService;
import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection;
import com.google.android.maps.mytracks.R;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
@@ -28,6 +30,7 @@ import android.content.Context;
import android.content.Intent;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;
import java.util.List;
@@ -83,7 +86,8 @@ public class TrackRecordingServiceConnectionUtils {
Log.e(TAG, "Failed to check if service is recording", e);
}
}
return PreferencesUtils.getRecordingTrackId(context) != -1L;
return PreferencesUtils.getLong(context, R.string.recording_track_id_key)
!= PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
}
/**
@@ -103,26 +107,27 @@ public class TrackRecordingServiceConnectionUtils {
* Need to remember the recordingTrackId before calling endCurrentTrack.
* endCurrentTrack sets the value to -1L.
*/
long recordingTrackId = PreferencesUtils.getRecordingTrackId(context);
long recordingTrackId = PreferencesUtils.getLong(context, R.string.recording_track_id_key);
trackRecordingService.endCurrentTrack();
if (recordingTrackId != -1L) {
Intent intent = new Intent(context, TrackEditActivity.class)
.putExtra(TrackEditActivity.EXTRA_SHOW_CANCEL, false)
.putExtra(TrackEditActivity.EXTRA_TRACK_ID, recordingTrackId);
if (recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT) {
Intent intent = IntentUtils.newIntent(context, TrackEditActivity.class)
.putExtra(TrackEditActivity.EXTRA_TRACK_ID, recordingTrackId)
.putExtra(TrackEditActivity.EXTRA_NEW_TRACK, true);
context.startActivity(intent);
}
} catch (Exception e) {
Log.e(TAG, "Unable to stop recording.", e);
}
} else {
PreferencesUtils.setRecordingTrackId(context, -1L);
PreferencesUtils.setLong(
context, R.string.recording_track_id_key, PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
}
trackRecordingServiceConnection.stop();
}
/**
* Resumes the track recording service connection.
*
*
* @param context the context
* @param trackRecordingServiceConnection the track recording service
* connection
@@ -131,7 +136,33 @@ public class TrackRecordingServiceConnectionUtils {
Context context, TrackRecordingServiceConnection trackRecordingServiceConnection) {
trackRecordingServiceConnection.bindIfRunning();
if (!isRecordingServiceRunning(context)) {
PreferencesUtils.setRecordingTrackId(context, -1L);
PreferencesUtils.setLong(
context, R.string.recording_track_id_key, PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
}
}
/**
* Adds a marker.
*/
public static void addMarker(Context context,
TrackRecordingServiceConnection trackRecordingServiceConnection,
WaypointCreationRequest waypointCreationRequest) {
ITrackRecordingService trackRecordingService = trackRecordingServiceConnection
.getServiceIfBound();
if (trackRecordingService == null) {
Log.d(TAG, "Unable to add marker, no track recording service");
} else {
try {
if (trackRecordingService.insertWaypoint(waypointCreationRequest) != -1L) {
Toast.makeText(context, R.string.marker_add_success, Toast.LENGTH_SHORT).show();
return;
}
} catch (RemoteException e) {
Log.e(TAG, "Unable to add marker", e);
} catch (IllegalStateException e) {
Log.e(TAG, "Unable to add marker.", e);
}
}
Toast.makeText(context, R.string.marker_add_error, Toast.LENGTH_LONG).show();
}
}
@@ -20,11 +20,13 @@ import static com.google.android.apps.mytracks.Constants.SETTINGS_NAME;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.TrackDetailActivity;
import com.google.android.apps.mytracks.TrackListActivity;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.services.ControlRecordingService;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.IntentUtils;
import com.google.android.apps.mytracks.util.PreferencesUtils;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
@@ -69,7 +71,7 @@ public class TrackWidgetProvider
private Context context;
private String unknown;
private TrackObserver trackObserver;
private boolean isMetric;
private boolean metricUnits;
private boolean reportSpeed;
private long selectedTrackId;
private SharedPreferences sharedPreferences;
@@ -79,7 +81,7 @@ public class TrackWidgetProvider
public TrackWidgetProvider() {
super();
contentHandler = new Handler();
selectedTrackId = -1;
selectedTrackId = PreferencesUtils.SELECTED_TRACK_ID_DEFAULT;
}
private void initialize(Context aContext) {
@@ -132,7 +134,7 @@ public class TrackWidgetProvider
private void updateTrack(String action) {
Track track = null;
if (selectedTrackId != -1) {
if (selectedTrackId != PreferencesUtils.SELECTED_TRACK_ID_DEFAULT) {
Log.d(TAG, "TrackWidgetProvider.updateTrack: Retrieving specified track.");
track = providerUtils.getTrack(selectedTrackId);
} else {
@@ -146,10 +148,12 @@ public class TrackWidgetProvider
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.track_widget);
// Make all of the stats open the mytracks activity.
Intent intent = new Intent(context, TrackDetailActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
Intent intent;
if (track != null) {
intent.putExtra(TrackDetailActivity.EXTRA_TRACK_ID, track.getId());
intent = IntentUtils.newIntent(context, TrackDetailActivity.class)
.putExtra(TrackDetailActivity.EXTRA_TRACK_ID, track.getId());
} else {
intent = IntentUtils.newIntent(context, TrackListActivity.class);
}
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.appwidget_track_statistics, pendingIntent);
@@ -174,11 +178,11 @@ public class TrackWidgetProvider
if (TRACK_STARTED_ACTION.equals(action)) {
// If a new track is started by this appwidget or elsewhere,
// toggle the button to active and have it disable the track if pressed.
setButtonIntent(views, R.string.track_action_end, R.drawable.appwidget_button_enabled);
setButtonIntent(views, R.string.track_action_end, R.drawable.app_widget_button_enabled);
} else {
// If a track is stopped by this appwidget or elsewhere,
// toggle the button to inactive and have it start a new track if pressed.
setButtonIntent(views, R.string.track_action_start, R.drawable.appwidget_button_disabled);
setButtonIntent(views, R.string.track_action_start, R.drawable.app_widget_button_disabled);
}
}
@@ -190,8 +194,8 @@ public class TrackWidgetProvider
* @param icon The resource id of the icon to show for the button
*/
private void setButtonIntent(RemoteViews views, int action, int icon) {
Intent intent = new Intent(context, ControlRecordingService.class);
intent.setAction(context.getString(action));
Intent intent = new Intent(context, ControlRecordingService.class)
.setAction(context.getString(action));
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.appwidget_button, pendingIntent);
@@ -214,10 +218,10 @@ public class TrackWidgetProvider
}
TripStatistics stats = track.getStatistics();
String distance = StringUtils.formatDistance(context, stats.getTotalDistance(), isMetric);
String distance = StringUtils.formatDistance(context, stats.getTotalDistance(), metricUnits);
String time = StringUtils.formatElapsedTime(stats.getMovingTime());
String speed = StringUtils.formatSpeed(
context, stats.getAverageMovingSpeed(), isMetric, reportSpeed);
context, stats.getAverageMovingSpeed(), metricUnits, reportSpeed);
views.setTextViewText(R.id.appwidget_distance_text, distance);
views.setTextViewText(R.id.appwidget_time_text, time);
@@ -226,18 +230,17 @@ public class TrackWidgetProvider
@Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
String metricUnitsKey = context.getString(R.string.metric_units_key);
if (key == null || key.equals(metricUnitsKey)) {
isMetric = prefs.getBoolean(metricUnitsKey, true);
if (key == null || PreferencesUtils.getKey(context, R.string.metric_units_key).equals(key)) {
metricUnits = PreferencesUtils.getBoolean(
context, R.string.metric_units_key, PreferencesUtils.METRIC_UNITS_DEFAULT);
}
String reportSpeedKey = context.getString(R.string.report_speed_key);
if (key == null || key.equals(reportSpeedKey)) {
reportSpeed = prefs.getBoolean(reportSpeedKey, true);
if (key == null || PreferencesUtils.getKey(context, R.string.report_speed_key).equals(key)) {
reportSpeed = PreferencesUtils.getBoolean(
context, R.string.report_speed_key, PreferencesUtils.REPORT_SPEED_DEFAULT);
}
if (key == null || key.equals(PreferencesUtils.getSelectedTrackIdKey(context))) {
selectedTrackId = PreferencesUtils.getSelectedTrackId(context);
if (key == null
|| PreferencesUtils.getKey(context, R.string.selected_track_id_key).equals(key)) {
selectedTrackId = PreferencesUtils.getLong(context, R.string.selected_track_id_key);
Log.d(TAG, "TrackWidgetProvider setting selecting track from preference: " + selectedTrackId);
}
}