diff --git a/MyTracks/res/layout/marker_detail.xml b/MyTracks/res/layout/marker_detail.xml index 70f303bd5..166b426d3 100644 --- a/MyTracks/res/layout/marker_detail.xml +++ b/MyTracks/res/layout/marker_detail.xml @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. --> + style="@style/StatsScrollView" > - - - + \ No newline at end of file diff --git a/MyTracks/res/layout/stats.xml b/MyTracks/res/layout/stats.xml index 82ce3bf09..d3edb9d15 100644 --- a/MyTracks/res/layout/stats.xml +++ b/MyTracks/res/layout/stats.xml @@ -15,42 +15,13 @@ See the License for the specific language governing permissions and limitations under the License. --> - + - - - - - - - - - - - - - - - - - - + android:orientation="vertical" + android:paddingLeft="8dp" + android:paddingRight="8dp" > + + \ No newline at end of file diff --git a/MyTracks/res/layout/stats_content.xml b/MyTracks/res/layout/stats_content.xml new file mode 100644 index 000000000..99ab08836 --- /dev/null +++ b/MyTracks/res/layout/stats_content.xml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MyTracks/res/layout/stats_core.xml b/MyTracks/res/layout/stats_core.xml deleted file mode 100644 index e7d3301e1..000000000 --- a/MyTracks/res/layout/stats_core.xml +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/MyTracks/res/layout/stats_large_item.xml b/MyTracks/res/layout/stats_large_item.xml new file mode 100644 index 000000000..d841b91cb --- /dev/null +++ b/MyTracks/res/layout/stats_large_item.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/MyTracks/res/layout/stats_small_item.xml b/MyTracks/res/layout/stats_small_item.xml new file mode 100644 index 000000000..0e2e817b5 --- /dev/null +++ b/MyTracks/res/layout/stats_small_item.xml @@ -0,0 +1,32 @@ + + + + + + + + + + \ No newline at end of file diff --git a/MyTracks/res/layout/aggregated_stats.xml b/MyTracks/res/layout/stats_small_item_1line.xml similarity index 52% rename from MyTracks/res/layout/aggregated_stats.xml rename to MyTracks/res/layout/stats_small_item_1line.xml index b32fc1498..81c960fc2 100644 --- a/MyTracks/res/layout/aggregated_stats.xml +++ b/MyTracks/res/layout/stats_small_item_1line.xml @@ -1,6 +1,6 @@ - - - - - \ No newline at end of file + + + + + \ No newline at end of file diff --git a/MyTracks/res/menu/list_context_menu.xml b/MyTracks/res/menu/list_context_menu.xml index 769974221..0c6a39231 100644 --- a/MyTracks/res/menu/list_context_menu.xml +++ b/MyTracks/res/menu/list_context_menu.xml @@ -15,6 +15,11 @@ See the License for the specific language governing permissions and limitations under the License. --> + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + @@ -285,7 +343,7 @@ limitations under the License. wrap_content wrap_content true - @color/track_widget_label + @color/stats_large_label 10dp bold @@ -342,7 +400,7 @@ limitations under the License. 18dp - diff --git a/MyTracks/res/xml/stats_settings.xml b/MyTracks/res/xml/stats_settings.xml index 6b0f4efd0..104963d49 100644 --- a/MyTracks/res/xml/stats_settings.xml +++ b/MyTracks/res/xml/stats_settings.xml @@ -29,16 +29,8 @@ limitations under the License. - - + android:key="@string/stats_show_grade_elevation_key" + android:title="@string/settings_stats_grade_elevation" /> infos = getPackageManager().queryIntentActivities( - new Intent().setType(SaveActivity.GOOGLE_EARTH_KML_MIME_TYPE), - PackageManager.MATCH_DEFAULT_ONLY); - for (ResolveInfo info : infos) { - if (info.activityInfo != null && info.activityInfo.packageName != null - && info.activityInfo.packageName.equals(SaveActivity.GOOGLE_EARTH_PACKAGE)) { - return true; - } - } - return false; - } } \ No newline at end of file diff --git a/MyTracks/src/com/google/android/apps/mytracks/TrackListActivity.java b/MyTracks/src/com/google/android/apps/mytracks/TrackListActivity.java index 5b89d1e34..870dd5ede 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/TrackListActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/TrackListActivity.java @@ -366,13 +366,13 @@ public class TrackListActivity extends AbstractSendToGoogleActivity @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - + if (BuildConfig.DEBUG) { ApiAdapterFactory.getApiAdapter().enableStrictMode(); } Intent intent = new Intent(this, RemoveTempFilesService.class); - startService(intent); - + startService(intent); + myTracksProviderUtils = MyTracksProviderUtils.Factory.get(this); sharedPreferences = getSharedPreferences(Constants.SETTINGS_NAME, Context.MODE_PRIVATE); @@ -385,13 +385,13 @@ public class TrackListActivity extends AbstractSendToGoogleActivity setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); // Show trackController when search dialog is dismissed SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE); - searchManager.setOnDismissListener(new SearchManager.OnDismissListener() { + searchManager.setOnDismissListener(new SearchManager.OnDismissListener() { @Override public void onDismiss() { - trackController.show(); + trackController.show(); } }); - + listView = (ListView) findViewById(R.id.track_list); listView.setEmptyView(findViewById(R.id.track_list_empty_view)); listView.setOnItemClickListener(new OnItemClickListener() { @@ -415,7 +415,7 @@ public class TrackListActivity extends AbstractSendToGoogleActivity int startTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.STARTTIME); int descriptionIndex = cursor.getColumnIndex(TracksColumns.DESCRIPTION); int sharedOwnerIndex = cursor.getColumnIndex(TracksColumns.SHAREDOWNER); - + boolean isRecording = cursor.getLong(idIndex) == recordingTrackId; String icon = cursor.getString(iconIndex); int iconId = TrackIconUtils.getIconDrawable(icon); @@ -540,13 +540,13 @@ public class TrackListActivity extends AbstractSendToGoogleActivity @Override protected boolean configureActionBarHomeAsUp() { - return false; + return false; } - + @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.track_list, menu); - + searchMenuItem = menu.findItem(R.id.track_list_search); startGpsMenuItem = menu.findItem(R.id.track_list_start_gps); importAllMenuItem = menu.findItem(R.id.track_list_import_all); @@ -620,7 +620,7 @@ public class TrackListActivity extends AbstractSendToGoogleActivity return super.onOptionsItemSelected(item); } } - + @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); @@ -649,7 +649,7 @@ public class TrackListActivity extends AbstractSendToGoogleActivity } return super.onKeyUp(keyCode, event); } - + @Override public boolean onSearchRequested() { // Hide trackController when search dialog is shown @@ -666,7 +666,7 @@ public class TrackListActivity extends AbstractSendToGoogleActivity public void onDeleteTrackDone() { // Do nothing } - + @Override public void onFileTypeDone(int menuId, TrackFileFormat trackFileFormat) { Intent intent; @@ -675,6 +675,7 @@ public class TrackListActivity extends AbstractSendToGoogleActivity AnalyticsUtils.sendPageViews( this, "/action/save_all_" + trackFileFormat.name().toLowerCase(Locale.US)); intent = IntentUtils.newIntent(this, SaveActivity.class) + .putExtra(SaveActivity.EXTRA_TRACK_IDS, new long[] {-1L}) .putExtra(SaveActivity.EXTRA_TRACK_FILE_FORMAT, (Parcelable) trackFileFormat); startActivity(intent); break; @@ -718,7 +719,7 @@ public class TrackListActivity extends AbstractSendToGoogleActivity showStartupDialogs(); return; } - finish(); + finish(); } private void checkGooglePlayServices() { @@ -812,6 +813,9 @@ public class TrackListActivity extends AbstractSendToGoogleActivity */ private boolean handleContextItem(int itemId, long[] trackIds) { switch (itemId) { + case R.id.list_context_menu_play: + confirmPlay(trackIds); + return true; case R.id.list_context_menu_share: confirmShare(trackIds[0]); return true; diff --git a/MyTracks/src/com/google/android/apps/mytracks/fragments/ConfirmDialogFragment.java b/MyTracks/src/com/google/android/apps/mytracks/fragments/ConfirmDialogFragment.java index 9826d903c..f55f09790 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/fragments/ConfirmDialogFragment.java +++ b/MyTracks/src/com/google/android/apps/mytracks/fragments/ConfirmDialogFragment.java @@ -47,7 +47,7 @@ public class ConfirmDialogFragment extends DialogFragment { /** * Called when confirm is done. */ - public void onConfirmDone(int confirmId, long trackId); + public void onConfirmDone(int confirmId, long[] trackIds); } public static final String CONFIRM_DIALOG_TAG = "confirmDialog"; @@ -55,17 +55,17 @@ public class ConfirmDialogFragment extends DialogFragment { private static final String KEY_CONFIRM_ID = "confirmId"; private static final String KEY_DEFAULT_VALUE = "defaultValue"; private static final String KEY_MESSAGE = "message"; - private static final String KEY_TRACK_ID = "trackId"; + private static final String KEY_TRACK_IDS = "trackIds"; private CheckBox checkBox; public static ConfirmDialogFragment newInstance( - int confirmId, boolean defaultValue, CharSequence message, long trackId) { + int confirmId, boolean defaultValue, CharSequence message, long[] trackIds) { Bundle bundle = new Bundle(); bundle.putInt(KEY_CONFIRM_ID, confirmId); bundle.putBoolean(KEY_DEFAULT_VALUE, defaultValue); bundle.putCharSequence(KEY_MESSAGE, message); - bundle.putLong(KEY_TRACK_ID, trackId); + bundle.putLongArray(KEY_TRACK_IDS, trackIds); ConfirmDialogFragment confirmDialogFragment = new ConfirmDialogFragment(); confirmDialogFragment.setArguments(bundle); @@ -93,9 +93,9 @@ public class ConfirmDialogFragment extends DialogFragment { boolean defaultValue = getArguments().getBoolean(KEY_DEFAULT_VALUE); fragmentActivity = getActivity(); if (!PreferencesUtils.getBoolean(fragmentActivity, confirmId, defaultValue)) { - long trackId = getArguments().getLong(KEY_TRACK_ID); + long[] trackIds = getArguments().getLongArray(KEY_TRACK_IDS); dismiss(); - caller.onConfirmDone(confirmId, trackId); + caller.onConfirmDone(confirmId, trackIds); } } @@ -106,15 +106,14 @@ public class ConfirmDialogFragment extends DialogFragment { textView.setText(getArguments().getCharSequence(KEY_MESSAGE)); checkBox = (CheckBox) view.findViewById(R.id.confirm_dialog_check_box); - return new AlertDialog.Builder(fragmentActivity).setNegativeButton( - R.string.generic_no, null) + return new AlertDialog.Builder(fragmentActivity).setNegativeButton(R.string.generic_no, null) .setPositiveButton(R.string.generic_yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { int confirmId = getArguments().getInt(KEY_CONFIRM_ID); - long trackId = getArguments().getLong(KEY_TRACK_ID); + long[] trackIds = getArguments().getLongArray(KEY_TRACK_IDS); PreferencesUtils.setBoolean(fragmentActivity, confirmId, !checkBox.isChecked()); - caller.onConfirmDone(confirmId, trackId); + caller.onConfirmDone(confirmId, trackIds); } }).setTitle(R.string.generic_confirm_title).setView(view).create(); } diff --git a/MyTracks/src/com/google/android/apps/mytracks/fragments/EnableSyncDialogFragment.java b/MyTracks/src/com/google/android/apps/mytracks/fragments/EnableSyncDialogFragment.java index 90c817970..43fbee5c9 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/fragments/EnableSyncDialogFragment.java +++ b/MyTracks/src/com/google/android/apps/mytracks/fragments/EnableSyncDialogFragment.java @@ -87,6 +87,13 @@ public class EnableSyncDialogFragment extends DialogFragment { }).setPositiveButton(R.string.generic_yes, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { + /* + * google_account_key can be set from the android backup service. If + * the user wants to enable sync, make sure google_account_key is + * cleared so the user can choose an account. + */ + PreferencesUtils.setString(fragmentActivity, R.string.google_account_key, + PreferencesUtils.GOOGLE_ACCOUNT_DEFAULT); caller.onEnableSyncDone(true); } }).setTitle(R.string.enable_sync_title).create(); diff --git a/MyTracks/src/com/google/android/apps/mytracks/fragments/InstallEarthDialogFragment.java b/MyTracks/src/com/google/android/apps/mytracks/fragments/InstallEarthDialogFragment.java index 801d1eb83..4d1c086e5 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/fragments/InstallEarthDialogFragment.java +++ b/MyTracks/src/com/google/android/apps/mytracks/fragments/InstallEarthDialogFragment.java @@ -16,7 +16,7 @@ package com.google.android.apps.mytracks.fragments; -import com.google.android.apps.mytracks.io.file.SaveActivity; +import com.google.android.apps.mytracks.util.GoogleEarthUtils; import com.google.android.maps.mytracks.R; import android.app.AlertDialog; @@ -32,7 +32,7 @@ import android.widget.Toast; /** * A DialogFragment to install Google Earth. - * + * * @author Jimmy Shih */ public class InstallEarthDialogFragment extends DialogFragment { @@ -40,17 +40,17 @@ public class InstallEarthDialogFragment extends DialogFragment { public static final String INSTALL_EARTH_DIALOG_TAG = "installEarthDialog"; private FragmentActivity fragmentActivity; - + @Override public Dialog onCreateDialog(Bundle savedInstanceState) { fragmentActivity = getActivity(); - return new AlertDialog.Builder(fragmentActivity) - .setMessage(R.string.track_detail_install_earth_message) - .setNegativeButton(R.string.generic_no, null) + return new AlertDialog.Builder(fragmentActivity).setMessage( + R.string.track_detail_install_earth_message).setNegativeButton(R.string.generic_no, null) .setPositiveButton(R.string.generic_yes, new DialogInterface.OnClickListener() { - @Override + @Override public void onClick(DialogInterface dialog, int which) { - Intent intent = new Intent().setData(Uri.parse(SaveActivity.GOOGLE_EARTH_MARKET_URL)); + Intent intent = new Intent().setData( + Uri.parse(GoogleEarthUtils.GOOGLE_EARTH_MARKET_URL)); try { startActivity(intent); } catch (ActivityNotFoundException e) { @@ -59,8 +59,6 @@ public class InstallEarthDialogFragment extends DialogFragment { .show(); } } - }) - .setTitle(R.string.generic_confirm_title) - .create(); + }).setTitle(R.string.generic_confirm_title).create(); } } \ No newline at end of file diff --git a/MyTracks/src/com/google/android/apps/mytracks/fragments/StatsFragment.java b/MyTracks/src/com/google/android/apps/mytracks/fragments/StatsFragment.java index 0e97205dd..84742c25c 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/fragments/StatsFragment.java +++ b/MyTracks/src/com/google/android/apps/mytracks/fragments/StatsFragment.java @@ -102,7 +102,7 @@ public class StatsFragment extends Fragment implements TrackDataListener { public void run() { if (isResumed()) { lastLocation = null; - StatsUtils.setLocationValues(getActivity(), lastLocation, true); + StatsUtils.setLocationValues(getActivity(), lastLocation, isSelectedTrackRecording()); } } }); @@ -118,11 +118,12 @@ public class StatsFragment extends Fragment implements TrackDataListener { if (isResumed()) { if (isSelectedTrackRecording() && !isSelectedTrackPaused()) { lastLocation = location; - StatsUtils.setLocationValues(getActivity(), location, true); + StatsUtils.setLocationValues(getActivity(), location, isSelectedTrackRecording()); } else { if (lastLocation != null) { lastLocation = null; - StatsUtils.setLocationValues(getActivity(), lastLocation, true); + StatsUtils.setLocationValues( + getActivity(), lastLocation, isSelectedTrackRecording()); } } } @@ -277,6 +278,6 @@ public class StatsFragment extends Fragment implements TrackDataListener { */ private void updateUi(FragmentActivity activity) { StatsUtils.setTripStatisticsValues(activity, lastTripStatistics); - StatsUtils.setLocationValues(activity, lastLocation, true); + StatsUtils.setLocationValues(activity, lastLocation, isSelectedTrackRecording()); } } diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/CsvTrackWriter.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/CsvTrackWriter.java index 641b24d72..5f44604ed 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/CsvTrackWriter.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/CsvTrackWriter.java @@ -58,7 +58,6 @@ public class CsvTrackWriter implements TrackFormatWriter { private final Context context; private PrintWriter printWriter; - private Track track; private int segmentIndex; private int pointIndex; @@ -72,8 +71,7 @@ public class CsvTrackWriter implements TrackFormatWriter { } @Override - public void prepare(Track aTrack, OutputStream out) { - track = aTrack; + public void prepare(OutputStream out) { printWriter = new PrintWriter(out); segmentIndex = 0; pointIndex = 0; @@ -85,7 +83,7 @@ public class CsvTrackWriter implements TrackFormatWriter { } @Override - public void writeHeader() { + public void writeHeader(Track track) { writeCommaSeparatedLine(context.getString(R.string.generic_name), context.getString(R.string.track_edit_activity_type_hint), context.getString(R.string.generic_description)); @@ -133,7 +131,7 @@ public class CsvTrackWriter implements TrackFormatWriter { } @Override - public void writeBeginTrack(Location firstPoint) { + public void writeBeginTrack(Track track, Location firstPoint) { writeCommaSeparatedLine(context.getString(R.string.description_track_segment), context.getString(R.string.description_track_point), context.getString(R.string.description_location_latitude), @@ -149,7 +147,7 @@ public class CsvTrackWriter implements TrackFormatWriter { } @Override - public void writeEndTrack(Location lastPoint) { + public void writeEndTrack(Track track, Location lastPoint) { // Do nothing } diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/GpxTrackWriter.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/GpxTrackWriter.java index ab61e4140..7161f77e2 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/GpxTrackWriter.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/GpxTrackWriter.java @@ -52,7 +52,6 @@ public class GpxTrackWriter implements TrackFormatWriter { } private final Context context; - private Track track; private PrintWriter printWriter; public GpxTrackWriter(Context context) { @@ -65,8 +64,7 @@ public class GpxTrackWriter implements TrackFormatWriter { } @Override - public void prepare(Track aTrack, OutputStream outputStream) { - this.track = aTrack; + public void prepare(OutputStream outputStream) { this.printWriter = new PrintWriter(outputStream); } @@ -79,7 +77,7 @@ public class GpxTrackWriter implements TrackFormatWriter { } @Override - public void writeHeader() { + public void writeHeader(Track track) { if (printWriter != null) { printWriter.println(""); printWriter.println(""); printWriter.println("" + StringUtils.formatCData(track.getName()) + ""); @@ -120,7 +118,7 @@ public class GpxTrackWriter implements TrackFormatWriter { } @Override - public void writeEndTrack(Location lastLocation) { + public void writeEndTrack(Track track, Location lastLocation) { if (printWriter != null) { printWriter.println(""); } diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/KmlTrackWriter.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/KmlTrackWriter.java index 25e7f0539..7c7f275e1 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/KmlTrackWriter.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/KmlTrackWriter.java @@ -24,6 +24,7 @@ import com.google.android.apps.mytracks.content.Sensor.SensorDataSet; import com.google.android.apps.mytracks.content.Track; import com.google.android.apps.mytracks.content.Waypoint; import com.google.android.apps.mytracks.content.Waypoint.WaypointType; +import com.google.android.apps.mytracks.util.GoogleEarthUtils; import com.google.android.apps.mytracks.util.StringUtils; import com.google.android.maps.mytracks.R; import com.google.common.annotations.VisibleForTesting; @@ -42,11 +43,6 @@ import java.util.ArrayList; */ public class KmlTrackWriter implements TrackFormatWriter { - /** - * ID of the KML feature to play a tour. - */ - public static final String TOUR_FEATURE_ID = "tour"; - private static final String WAYPOINT_STYLE = "waypoint"; private static final String STATISTICS_STYLE = "statistics"; private static final String START_STYLE = "start"; @@ -70,7 +66,6 @@ public class KmlTrackWriter implements TrackFormatWriter { private final Context context; private final DescriptionGenerator descriptionGenerator; - private Track track; private PrintWriter printWriter; private ArrayList powerList = new ArrayList(); private ArrayList cadenceList = new ArrayList(); @@ -95,8 +90,7 @@ public class KmlTrackWriter implements TrackFormatWriter { } @Override - public void prepare(Track aTrack, OutputStream outputStream) { - this.track = aTrack; + public void prepare(OutputStream outputStream) { this.printWriter = new PrintWriter(outputStream); } @@ -109,12 +103,12 @@ public class KmlTrackWriter implements TrackFormatWriter { } @Override - public void writeHeader() { + public void writeHeader(Track track) { if (printWriter != null) { printWriter.println(""); printWriter.println(""); + printWriter.println("xmlns:atom=\"http://www.w3.org/2005/Atom\">"); printWriter.println(""); printWriter.println("1"); printWriter.println("1"); @@ -170,11 +164,11 @@ public class KmlTrackWriter implements TrackFormatWriter { } @Override - public void writeBeginTrack(Location firstLocation) { + public void writeBeginTrack(Track track, Location firstLocation) { if (printWriter != null) { String name = context.getString(R.string.marker_label_start, track.getName()); writePlacemark(name, "", "", START_STYLE, firstLocation); - printWriter.println(""); + printWriter.println(""); printWriter.println("" + StringUtils.formatCData(track.getName()) + ""); printWriter.println( "" + StringUtils.formatCData(track.getDescription()) + ""); @@ -187,7 +181,7 @@ public class KmlTrackWriter implements TrackFormatWriter { } @Override - public void writeEndTrack(Location lastLocation) { + public void writeEndTrack(Track track, Location lastLocation) { if (printWriter != null) { printWriter.println(""); printWriter.println(""); diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveActivity.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveActivity.java index 4cf693e2b..4f42ca6f8 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveActivity.java @@ -18,6 +18,7 @@ package com.google.android.apps.mytracks.io.file; import com.google.android.apps.mytracks.util.DialogUtils; import com.google.android.apps.mytracks.util.FileUtils; +import com.google.android.apps.mytracks.util.GoogleEarthUtils; import com.google.android.apps.mytracks.util.IntentUtils; import com.google.android.maps.mytracks.R; @@ -27,7 +28,6 @@ import android.app.Dialog; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.Intent; -import android.net.Uri; import android.os.Bundle; import android.widget.Toast; @@ -42,23 +42,15 @@ import java.io.File; public class SaveActivity extends Activity { public static final String EXTRA_TRACK_FILE_FORMAT = "track_file_format"; - public static final String EXTRA_TRACK_ID = "track_id"; + public static final String EXTRA_TRACK_IDS = "track_ids"; public static final String EXTRA_PLAY_TRACK = "play_track"; public static final String EXTRA_SHARE_TRACK = "share_track"; - public static final String GOOGLE_EARTH_KML_MIME_TYPE = "application/vnd.google-earth.kml+xml"; - public static final String GOOGLE_EARTH_PACKAGE = "com.google.earth"; - public static final String GOOGLE_EARTH_MARKET_URL = "market://details?id=" - + GOOGLE_EARTH_PACKAGE; - private static final String - GOOGLE_EARTH_TOUR_FEATURE_ID = "com.google.earth.EXTRA.tour_feature_id"; - private static final String GOOGLE_EARTH_CLASS = "com.google.earth.EarthActivity"; - private static final int DIALOG_PROGRESS_ID = 0; private static final int DIALOG_RESULT_ID = 1; private TrackFileFormat trackFileFormat; - private long trackId; + private long[] trackIds; private boolean playTrack; private boolean shareTrack; private String directoryName; @@ -78,7 +70,7 @@ public class SaveActivity extends Activity { Intent intent = getIntent(); trackFileFormat = intent.getParcelableExtra(EXTRA_TRACK_FILE_FORMAT); - trackId = intent.getLongExtra(EXTRA_TRACK_ID, -1L); + trackIds = intent.getLongArrayExtra(EXTRA_TRACK_IDS); playTrack = intent.getBooleanExtra(EXTRA_PLAY_TRACK, false); shareTrack = intent.getBooleanExtra(EXTRA_SHARE_TRACK, false); @@ -104,7 +96,7 @@ public class SaveActivity extends Activity { saveAsyncTask = (SaveAsyncTask) retained; saveAsyncTask.setActivity(this); } else { - saveAsyncTask = new SaveAsyncTask(this, trackFileFormat, trackId, directory); + saveAsyncTask = new SaveAsyncTask(this, trackFileFormat, trackIds, directory); saveAsyncTask.execute(); } } @@ -175,23 +167,17 @@ public class SaveActivity extends Activity { removeDialog(DIALOG_PROGRESS_ID); if (successCount == 1 && totalCount == 1 && savedPath != null) { if (playTrack) { - Intent intent = new Intent().addFlags( - Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK) - .putExtra(GOOGLE_EARTH_TOUR_FEATURE_ID, KmlTrackWriter.TOUR_FEATURE_ID) - .setClassName(GOOGLE_EARTH_PACKAGE, GOOGLE_EARTH_CLASS) - .setDataAndType(Uri.fromFile(new File(savedPath)), GOOGLE_EARTH_KML_MIME_TYPE); - startActivity(intent); + startActivity(GoogleEarthUtils.getPlayInEarthIntent(savedPath)); finish(); return; } else if (shareTrack) { - Intent intent = IntentUtils.newShareFileIntent(this, trackId, savedPath, trackFileFormat); - startActivity( - Intent.createChooser(intent, getString(R.string.share_track_picker_title))); + Intent intent = IntentUtils.newShareFileIntent(this, trackIds[0], savedPath, trackFileFormat); + startActivity(Intent.createChooser(intent, getString(R.string.share_track_picker_title))); finish(); return; - } + } } - showDialog(DIALOG_RESULT_ID); + showDialog(DIALOG_RESULT_ID); } /** diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveAsyncTask.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveAsyncTask.java index ae4f68529..e7b434d3c 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveAsyncTask.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/SaveAsyncTask.java @@ -46,7 +46,7 @@ public class SaveAsyncTask extends AsyncTask { private SaveActivity saveActivity; private final TrackFileFormat trackFileFormat; - private final long trackId; + private final long[] trackIds; private final File directory; private final Context context; private final MyTracksProviderUtils myTracksProviderUtils; @@ -75,10 +75,10 @@ public class SaveAsyncTask extends AsyncTask { * @param directory the directory to save to */ public SaveAsyncTask( - SaveActivity saveActivity, TrackFileFormat trackFileFormat, long trackId, File directory) { + SaveActivity saveActivity, TrackFileFormat trackFileFormat, long[] trackIds, File directory) { this.saveActivity = saveActivity; this.trackFileFormat = trackFileFormat; - this.trackId = trackId; + this.trackIds = trackIds; this.directory = directory; context = saveActivity.getApplicationContext(); myTracksProviderUtils = MyTracksProviderUtils.Factory.get(context); @@ -118,16 +118,24 @@ public class SaveAsyncTask extends AsyncTask { @Override protected Boolean doInBackground(Void... params) { try { - if (trackId != -1L) { + if (trackIds.length == 1 && trackIds[0] == -1L) { + return saveAllTracks(); + } else { totalCount = 1; - if (saveOneTrack(trackId)) { + Track[] tracks = new Track[trackIds.length]; + for (int i = 0; i < trackIds.length; i++) { + tracks[i] = myTracksProviderUtils.getTrack(trackIds[i]); + if (tracks[i] == null) { + Log.d(TAG, "No track for " + trackIds[i]); + return false; + } + } + if (saveTracks(tracks)) { successCount = 1; return true; } else { return false; } - } else { - return saveAllTracks(); } } finally { // Release the wake lock if obtained @@ -160,17 +168,15 @@ public class SaveAsyncTask extends AsyncTask { } /** - * Saves one track. + * Saves tracks to one file. * - * @param id the track id + * @param tracks the tracks */ - private Boolean saveOneTrack(long id) { - Track track = myTracksProviderUtils.getTrack(id); - if (track == null) { - Log.d(TAG, "No track for " + id); + private Boolean saveTracks(Track[] tracks) { + if (tracks.length == 0) { return false; } - + Track track = tracks[0]; // Make sure the file doesn't exist yet (possibly by changing the filename) String fileName = FileUtils.buildUniqueFileName( directory, track.getName(), trackFileFormat.getExtension()); @@ -178,21 +184,21 @@ public class SaveAsyncTask extends AsyncTask { Log.d(TAG, "Unable to get a unique filename for " + track.getName()); return false; } - + trackWriter = new TrackWriter( - context, myTracksProviderUtils, track, trackFileFormat, new TrackWriter.OnWriteListener() { + context, myTracksProviderUtils, tracks, trackFileFormat, new TrackWriter.OnWriteListener() { @Override public void onWrite(int number, int max) { /* * If only saving one track, update the progress dialog once every * 500 points */ - if (trackId != -1L && number % 500 == 0) { + if (trackIds.length == 1 && trackIds[0] != -1L && number % 500 == 0) { publishProgress(number, max); } } }); - + File file = null; try { file = new File(directory, fileName); @@ -201,8 +207,8 @@ public class SaveAsyncTask extends AsyncTask { } catch (FileNotFoundException e) { Log.d(TAG, "File not found " + fileName, e); return false; - } - + } + if (trackWriter.wasSuccess()) { savedPath = file.getAbsolutePath(); } else { @@ -224,14 +230,13 @@ public class SaveAsyncTask extends AsyncTask { return false; } totalCount = cursor.getCount(); - int idIndex = cursor.getColumnIndexOrThrow(TracksColumns._ID); for (int i = 0; i < totalCount; i++) { if (isCancelled()) { return false; } cursor.moveToPosition(i); - long id = cursor.getLong(idIndex); - if (saveOneTrack(id)) { + Track track = myTracksProviderUtils.createTrack(cursor); + if (track != null && saveTracks(new Track[] { track })) { successCount++; } publishProgress(i + 1, totalCount); diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/TcxTrackWriter.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/TcxTrackWriter.java index 000245351..27dfa8b60 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/TcxTrackWriter.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/TcxTrackWriter.java @@ -84,7 +84,6 @@ public class TcxTrackWriter implements TrackFormatWriter { R.string.activity_type_walking }; private final Context context; - private Track track; private PrintWriter printWriter; private SportType sportType; @@ -93,10 +92,8 @@ public class TcxTrackWriter implements TrackFormatWriter { } @Override - public void prepare(Track aTrack, OutputStream out) { - this.track = aTrack; + public void prepare(OutputStream out) { this.printWriter = new PrintWriter(out); - this.sportType = getSportType(track.getCategory()); } @Override @@ -113,7 +110,7 @@ public class TcxTrackWriter implements TrackFormatWriter { } @Override - public void writeHeader() { + public void writeHeader(Track track) { if (printWriter != null) { printWriter.println(""); printWriter.println(""); printWriter.println("" + StringUtils.formatCData(track.getDescription()) + ""); diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackFormatWriter.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackFormatWriter.java index bcbe7b95d..79b61b5f3 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackFormatWriter.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackFormatWriter.java @@ -23,26 +23,30 @@ import android.location.Location; import java.io.OutputStream; /** - * Interface for writing a track to file. + * Interface for writing tracks to a file. * * The expected sequence of calls is: - *
    - *
  1. {@link #prepare} - *
  2. {@link #writeHeader} - *
  3. {@link #writeBeginWaypoints} - *
  4. For each waypoint: {@link #writeWaypoint} - *
  5. {@link #writeEndWaypoints} - *
  6. {@link #writeBeginTrack} - *
  7. For each segment: - *
      - *
    1. {@link #writeOpenSegment} - *
    2. For each location in the segment: {@link #writeLocation} - *
    3. {@link #writeCloseSegment} - *
    - *
  8. {@link #writeEndTrack} - *
  9. {@link #writeFooter} - *
  10. {@link #close} - *
+ *
    + *
  • {@link #prepare}
  • + *
  • {@link #writeHeader}
  • + *
  • For each track:
  • + *
      + *
    • {@link #writeBeginWaypoints} + *
    • For each waypoint: {@link #writeWaypoint} + *
    • {@link #writeEndWaypoints} + *
    • {@link #writeBeginTrack} + *
    • For each segment: + *
        + *
      • {@link #writeOpenSegment}
      • + *
      • For each location in the segment: {@link #writeLocation}
      • + *
      • {@link #writeCloseSegment}
      • + *
      + *
    • + *
    • {@link #writeEndTrack}
    • + *
    + *
  • {@link #writeFooter}
  • + *
  • {@link #close}
  • + *
* * @author Rodrigo Damazio */ @@ -54,12 +58,11 @@ public interface TrackFormatWriter { public String getExtension(); /** - * Sets up the writer to write the given track. + * Sets up the file handler. * - * @param track the track to write - * @param outputStream the output stream to write the track to + * @param outputStream the output stream for the file handler */ - public void prepare(Track track, OutputStream outputStream); + public void prepare(OutputStream outputStream); /** * Closes the underlying file handler. @@ -67,9 +70,11 @@ public interface TrackFormatWriter { public void close(); /** - * Writes the header. + * Writes the header for a file + * + * @param track the track */ - public void writeHeader(); + public void writeHeader(Track track); /** * Writes the footer. @@ -96,16 +101,18 @@ public interface TrackFormatWriter { /** * Writes the beginning of the track. * + * @param track the track * @param firstLocation the first location */ - public void writeBeginTrack(Location firstLocation); + public void writeBeginTrack(Track track, Location firstLocation); /** * Writes the end of the track. * + * @param track the track * @param lastLocation the last location */ - public void writeEndTrack(Location lastLocation); + public void writeEndTrack(Track track, Location lastLocation); /** * Writes the statements necessary to open a new segment. diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriter.java b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriter.java index e937ef44e..3a67fa81d 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriter.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/file/TrackWriter.java @@ -33,7 +33,7 @@ import android.util.Log; import java.io.OutputStream; /** - * Track Writer for writing a track to an {@link OutputStream}. + * Track Writer for writing tracks to an {@link OutputStream}. * * @author Sandor Dornbush * @author Rodrigo Damazio @@ -49,7 +49,7 @@ public class TrackWriter { * When a track location is written. * * @param number the location number - * @param max the maximum number of locations, for calculation of completion + * @param max the maximum number of locations in a track, for calculation of completion * percentage */ public void onWrite(int number, int max); @@ -58,7 +58,7 @@ public class TrackWriter { private final static String TAG = TrackWriter.class.getSimpleName(); private final MyTracksProviderUtils myTracksProviderUtils; - private final Track track; + private final Track[] tracks; private final TrackFormatWriter trackFormatWriter; private final OnWriteListener onWriteListener; @@ -70,20 +70,20 @@ public class TrackWriter { * * @param context the context * @param myTracksProviderUtils the my tracks provider utils - * @param track the track + * @param tracks the tracks * @param trackFileFormat the track file format * @param onWriteListener the on write listener */ - public TrackWriter(Context context, MyTracksProviderUtils myTracksProviderUtils, Track track, + public TrackWriter(Context context, MyTracksProviderUtils myTracksProviderUtils, Track[] tracks, TrackFileFormat trackFileFormat, OnWriteListener onWriteListener) { - this(myTracksProviderUtils, track, trackFileFormat.newFormatWriter(context), onWriteListener); + this(myTracksProviderUtils, tracks, trackFileFormat.newFormatWriter(context), onWriteListener); } @VisibleForTesting - public TrackWriter(MyTracksProviderUtils myTracksProviderUtils, Track track, + public TrackWriter(MyTracksProviderUtils myTracksProviderUtils, Track[] tracks, TrackFormatWriter trackFormatWriter, OnWriteListener onWriteListener) { this.myTracksProviderUtils = myTracksProviderUtils; - this.track = track; + this.tracks = tracks; this.trackFormatWriter = trackFormatWriter; this.onWriteListener = onWriteListener; } @@ -105,10 +105,14 @@ public class TrackWriter { @Override public void run() { try { - trackFormatWriter.prepare(track, outputStream); - trackFormatWriter.writeHeader(); - writeWaypoints(); - writeLocations(); + trackFormatWriter.prepare(outputStream); + trackFormatWriter.writeHeader(tracks[0]); + long startTime = tracks[0].getTripStatistics().getStartTime(); + for (int i = 0; i < tracks.length; i++) { + writeWaypoints(tracks[i]); + long offset = tracks[i].getTripStatistics().getStartTime() - startTime; + writeLocations(tracks[i], offset); + } trackFormatWriter.writeFooter(); trackFormatWriter.close(); success = true; @@ -147,7 +151,7 @@ public class TrackWriter { /** * Writes the waypoints. */ - private void writeWaypoints() { + private void writeWaypoints(Track track) { /* * TODO: Stream through the waypoints in chunks. I am leaving the number of * waypoints very high which should not be a problem because we don't try to @@ -185,7 +189,7 @@ public class TrackWriter { /** * Writes the locations. */ - private void writeLocations() throws InterruptedException { + private void writeLocations(Track track, long offset) throws InterruptedException { boolean wroteTrack = false; boolean wroteSegment = false; boolean isLastLocationValid = false; @@ -197,6 +201,7 @@ public class TrackWriter { int locationNumber = 0; while (iterator.hasNext()) { Location location = iterator.next(); + setLocationTime(location, offset); if (Thread.interrupted()) { throw new InterruptedException(); } @@ -205,8 +210,8 @@ public class TrackWriter { boolean isLocationValid = LocationUtils.isValidLocation(location); boolean isSegmentValid = isLocationValid && isLastLocationValid; if (!wroteTrack && isSegmentValid) { - // Found the first two consecutive locations that are valid - trackFormatWriter.writeBeginTrack(locationFactory.lastLocation); + // Found the first two consecutive locations that are valid + trackFormatWriter.writeBeginTrack(track, locationFactory.lastLocation); wroteTrack = true; } @@ -241,17 +246,30 @@ public class TrackWriter { } if (wroteTrack) { Location lastValidTrackPoint = myTracksProviderUtils.getLastValidTrackPoint(track.getId()); - trackFormatWriter.writeEndTrack(lastValidTrackPoint); + setLocationTime(lastValidTrackPoint, offset); + trackFormatWriter.writeEndTrack(track, lastValidTrackPoint); } else { // Write an empty track - trackFormatWriter.writeBeginTrack(null); - trackFormatWriter.writeEndTrack(null); + trackFormatWriter.writeBeginTrack(track, null); + trackFormatWriter.writeEndTrack(track, null); } } finally { iterator.close(); } } + /** + * Sets a location time. + * + * @param location the location + * @param offset the time offset + */ + private void setLocationTime(Location location, long offset) { + if (location != null) { + location.setTime(location.getTime() - offset); + } + } + /** * Track writer location factory. Keeping the last two locations. * diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/sync/SyncUtils.java b/MyTracks/src/com/google/android/apps/mytracks/io/sync/SyncUtils.java index bb3af6b1e..737a8b6c0 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/sync/SyncUtils.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/sync/SyncUtils.java @@ -427,7 +427,7 @@ public class SyncUtils { java.io.File file = new java.io.File(directory, FileUtils.buildUniqueFileName(directory, track.getName(), trackFileFormat.getExtension())); TrackWriter trackWriter = new TrackWriter( - context, myTracksProviderUtils, track, trackFileFormat, null); + context, myTracksProviderUtils, new Track[] {track}, trackFileFormat, null); trackWriter.writeTrack(new FileOutputStream(file)); if (trackWriter.wasSuccess()) { diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/GoogleEarthUtils.java b/MyTracks/src/com/google/android/apps/mytracks/util/GoogleEarthUtils.java new file mode 100644 index 000000000..d8af4215c --- /dev/null +++ b/MyTracks/src/com/google/android/apps/mytracks/util/GoogleEarthUtils.java @@ -0,0 +1,75 @@ +/* + * Copyright 2013 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; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.net.Uri; + +import java.io.File; +import java.util.List; + +/** + * Utilities for Google Earth. + * + * @author Jimmy Shih + */ +public class GoogleEarthUtils { + + private static final String GOOGLE_EARTH_CLASS = "com.google.earth.EarthActivity"; + private static final String GOOGLE_EARTH_KML_MIME_TYPE = "application/vnd.google-earth.kml+xml"; + private static final String GOOGLE_EARTH_PACKAGE = "com.google.earth"; + private static final String + GOOGLE_EARTH_TOUR_FEATURE_ID = "com.google.earth.EXTRA.tour_feature_id"; + + public static final String GOOGLE_EARTH_MARKET_URL = "market://details?id=" + + GOOGLE_EARTH_PACKAGE; + public static final String TOUR_FEATURE_ID_VALUE = "tour"; + + private GoogleEarthUtils() {} + + /** + * Returns true if Google Earth is installed. + * + * @param context the context + */ + public static boolean isEarthInstalled(Context context) { + List infos = context.getPackageManager().queryIntentActivities( + new Intent().setType(GOOGLE_EARTH_KML_MIME_TYPE), PackageManager.MATCH_DEFAULT_ONLY); + for (ResolveInfo info : infos) { + if (info.activityInfo != null && info.activityInfo.packageName != null + && info.activityInfo.packageName.equals(GOOGLE_EARTH_PACKAGE)) { + return true; + } + } + return false; + } + + /** + * Gets an intent to play a kml file in Google Earth. + * + * @param kmlFilePath the kml file path + */ + public static Intent getPlayInEarthIntent(String kmlFilePath) { + return new Intent().addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK) + .putExtra(GOOGLE_EARTH_TOUR_FEATURE_ID, TOUR_FEATURE_ID_VALUE) + .setClassName(GOOGLE_EARTH_PACKAGE, GOOGLE_EARTH_CLASS) + .setDataAndType(Uri.fromFile(new File(kmlFilePath)), GOOGLE_EARTH_KML_MIME_TYPE); + } +} diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/GoogleFeedbackUtils.java b/MyTracks/src/com/google/android/apps/mytracks/util/GoogleFeedbackUtils.java index 71f2b50b2..555ab28ae 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/util/GoogleFeedbackUtils.java +++ b/MyTracks/src/com/google/android/apps/mytracks/util/GoogleFeedbackUtils.java @@ -42,6 +42,8 @@ public class GoogleFeedbackUtils { private static Boolean available = null; + private GoogleFeedbackUtils() {} + /** * Returns true if the Google Feedback is available. * diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/GoogleLocationUtils.java b/MyTracks/src/com/google/android/apps/mytracks/util/GoogleLocationUtils.java index dc6e14bb7..58b4060f8 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/util/GoogleLocationUtils.java +++ b/MyTracks/src/com/google/android/apps/mytracks/util/GoogleLocationUtils.java @@ -23,7 +23,7 @@ import android.content.pm.ResolveInfo; /** * Utilities for Google location settings - * + * * @author Jimmy Shih */ public class GoogleLocationUtils { @@ -32,7 +32,9 @@ public class GoogleLocationUtils { ACTION_GOOGLE_LOCATION_SETTINGS = "com.google.android.gsf.GOOGLE_LOCATION_SETTINGS"; private static final String ACTION_GOOGLE_APPS_LOCATION_SETTINGS = "com.google.android.gsf.GOOGLE_APPS_LOCATION_SETTINGS"; - + + private GoogleLocationUtils() {} + /** * Returns true if the Google location settings is available. */ diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/PreferencesUtils.java b/MyTracks/src/com/google/android/apps/mytracks/util/PreferencesUtils.java index afae9d49c..0bd4fd413 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/util/PreferencesUtils.java +++ b/MyTracks/src/com/google/android/apps/mytracks/util/PreferencesUtils.java @@ -98,9 +98,7 @@ public class PreferencesUtils { public static final String SHARE_TRACK_DEFAULT = "DRIVE"; 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_SHOW_MOVING_TIME_DEFAULT = false; + public static final boolean STATS_SHOW_GRADE_ELEVATION_DEFAULT = false; public static final String TRACK_COLOR_MODE_DEFAULT = "SINGLE"; public static final int TRACK_COLOR_MODE_MEDIUM_DEFAULT = 15; public static final int TRACK_COLOR_MODE_PERCENTAGE_DEFAULT = 25; diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/StatsUtils.java b/MyTracks/src/com/google/android/apps/mytracks/util/StatsUtils.java index 42fc0913a..5460b2c50 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/util/StatsUtils.java +++ b/MyTracks/src/com/google/android/apps/mytracks/util/StatsUtils.java @@ -24,78 +24,87 @@ import android.location.Location; import android.view.View; import android.widget.TextView; +import java.util.Locale; + /** * Utilities for updating the statistics UI labels and values. - * + * * @author Jimmy Shih */ public class StatsUtils { + private static final String COORDINATE_DEGREE = "\u00B0"; + private static final String GRADE_PERCENTAGE = "%"; + + private static final String ELEVATION_FORMAT = "%1$.2f"; + private static final String GRADE_FORMAT = "%1$d"; + 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 + * @param isRecording true if recording */ - public static void setLocationValues(Activity activity, Location location, boolean showAll) { + public static void setLocationValues(Activity activity, Location location, boolean isRecording) { 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); + double speed = !isRecording || location == null ? Double.NaN : location.getSpeed(); + setSpeed(activity, R.id.stats_speed, R.string.stats_speed, R.string.stats_pace, speed, + metricUnits, reportSpeed); + + // Set elevation + boolean showGradeElevation = PreferencesUtils.getBoolean(activity, + R.string.stats_show_grade_elevation_key, + PreferencesUtils.STATS_SHOW_GRADE_ELEVATION_DEFAULT); + View elevation = activity.findViewById(R.id.stats_elevation); + + if (showGradeElevation && isRecording) { + double altitude = location == null ? Double.NaN : location.getAltitude(); + elevation.setVisibility(View.VISIBLE); + setElevationValue(activity, R.id.stats_elevation, -1, altitude, metricUnits); + } else { + elevation.setVisibility(View.GONE); + } // 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); - if (coordinateLabelTableRow == null || coordinateValueTableRow == null) { - return; - } - coordinateLabelTableRow.setVisibility(showCoordinate ? View.VISIBLE : View.GONE); - coordinateValueTableRow.setVisibility(showCoordinate ? View.VISIBLE : View.GONE); - if (showCoordinate) { + View coordinateHorizontalLine = activity.findViewById(R.id.stats_coordinate_horizontal_line); + View coordinateContainer = activity.findViewById(R.id.stats_coordinate_container); + + if (showCoordinate && isRecording) { 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); + coordinateHorizontalLine.setVisibility(View.VISIBLE); + coordinateContainer.setVisibility(View.VISIBLE); + setCoordinateValue(activity, R.id.stats_latitude, R.string.stats_latitude, latitude); + setCoordinateValue(activity, R.id.stats_longitude, R.string.stats_longitude, longitude); + } else { + coordinateHorizontalLine.setVisibility(View.GONE); + coordinateContainer.setVisibility(View.GONE); } } /** * 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); + setTimeValue(activity, R.id.stats_total_time, R.string.stats_total_time, totalTime); } /** * Sets the trip statistics values. - * + * * @param activity the activity * @param tripStatistics the trip statistics */ @@ -104,249 +113,206 @@ public class StatsUtils { 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 showMovingTime = PreferencesUtils.getBoolean(activity, - R.string.stats_show_moving_time_key, PreferencesUtils.STATS_SHOW_MOVING_TIME_DEFAULT); - + // Set total distance double totalDistance = tripStatistics == null ? Double.NaN : tripStatistics.getTotalDistance(); - setDistanceValue(activity, R.id.stats_distance_value, totalDistance, metricUnits); - + setDistanceValue(activity, totalDistance, metricUnits); + // Set total time - setTimeValue(activity, R.id.stats_total_time_value, + setTimeValue(activity, R.id.stats_total_time, R.string.stats_total_time, tripStatistics != null ? tripStatistics.getTotalTime() : -1L); - // Set moving time - setItemVisibility(activity, R.id.stats_moving_time_label, R.id.stats_moving_time_spacer, - R.id.stats_moving_time_value, showMovingTime); - if (showMovingTime) { - setTimeValue(activity, R.id.stats_moving_time_value, - tripStatistics != null ? tripStatistics.getMovingTime() : -1L); - } - - // Set average speed - setSpeedLabel(activity, R.id.stats_average_speed_label, R.string.stats_average_speed, - R.string.stats_average_pace, reportSpeed); + // Set average speed/pace double averageSpeed = tripStatistics != null ? tripStatistics.getAverageSpeed() : Double.NaN; - setSpeedValue(activity, R.id.stats_average_speed_value, averageSpeed, metricUnits, reportSpeed); - - // Set average moving speed - setItemVisibility(activity, R.id.stats_average_moving_speed_label, - R.id.stats_average_moving_speed_spacer, R.id.stats_average_moving_speed_value, - showMovingTime); - if (showMovingTime) { - setSpeedLabel(activity, R.id.stats_average_moving_speed_label, - R.string.stats_average_moving_speed, R.string.stats_average_moving_pace, reportSpeed); - double averageMovingSpeed = tripStatistics != null ? tripStatistics.getAverageMovingSpeed() - : Double.NaN; - setSpeedValue(activity, R.id.stats_average_moving_speed_value, averageMovingSpeed, - metricUnits, reportSpeed); - } + setSpeed(activity, R.id.stats_average_speed, R.string.stats_average_speed, + R.string.stats_average_pace, 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); + // Set moving time + setTimeValue(activity, R.id.stats_moving_time, R.string.stats_moving_time, + tripStatistics != null ? tripStatistics.getMovingTime() : -1L); + + // Set average moving speed/pace + double averageMovingSpeed = tripStatistics != null ? tripStatistics.getAverageMovingSpeed() + : Double.NaN; + setSpeed(activity, R.id.stats_average_moving_time, R.string.stats_average_moving_speed, + R.string.stats_average_moving_pace, averageMovingSpeed, metricUnits, reportSpeed); + + // Set max speed/pace 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); - if (elevationLabelTableRow1 == null - || elevationValueTableRow1 == null - || elevationLabelTableRow2 == null - || elevationValueTableRow2 == null) { - return; - } - 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) { + setSpeed(activity, R.id.stats_max_speed, R.string.stats_max_speed, R.string.stats_fastest_pace, + maxSpeed, metricUnits, reportSpeed); + + // Set grade/elevation + boolean showGradeElevation = PreferencesUtils.getBoolean(activity, + R.string.stats_show_grade_elevation_key, + PreferencesUtils.STATS_SHOW_GRADE_ELEVATION_DEFAULT); + View gradeElevationHorizontalLine = activity.findViewById( + R.id.stats_grade_elevation_horizontal_line); + View gradeElevationContainer = activity.findViewById(R.id.stats_grade_elevation_container); + + if (showGradeElevation) { + gradeElevationHorizontalLine.setVisibility(View.VISIBLE); + gradeElevationContainer.setVisibility(View.VISIBLE); + // Set grade + double minGrade = tripStatistics == null ? Double.NaN : tripStatistics.getMinGrade(); + double maxGrade = tripStatistics == null ? Double.NaN : tripStatistics.getMaxGrade(); + setGradeValue(activity, R.id.stats_grade_min, R.string.stats_min, minGrade); + setGradeValue(activity, R.id.stats_grade_max, R.string.stats_max, maxGrade); + + // Set elevation 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); - if (gradeLabelTableRow == null || gradeValueTableRow == null) { - return; - } - 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); - } - } - - private static void setItemVisibility( - Activity activity, int labelId, int spacerId, int valueId, boolean show) { - View label = activity.findViewById(labelId); - View spacer = activity.findViewById(spacerId); - View value = activity.findViewById(valueId); - if (label != null) { - label.setVisibility(show ? View.VISIBLE : View.GONE); - } - if (spacer != null) { - spacer.setVisibility(show ? View.VISIBLE : View.GONE); - } - if (value != null) { - value.setVisibility(show ? View.VISIBLE : View.GONE); + setElevationValue( + activity, R.id.stats_elevation_gain, R.string.stats_gain, elevationGain, metricUnits); + setElevationValue( + activity, R.id.stats_elevation_min, R.string.stats_min, minElevation, metricUnits); + setElevationValue( + activity, R.id.stats_elevation_max, R.string.stats_max, maxElevation, metricUnits); + } else { + gradeElevationHorizontalLine.setVisibility(View.GONE); + gradeElevationContainer.setVisibility(View.GONE); } } /** - * Sets a speed label. - * + * Sets speed. + * * @param activity the activity - * @param id the speed label resource id - * @param speedId the speed string id - * @param paceId the pace string id - * @param reportSpeed true to report speed - */ - private static void setSpeedLabel( - Activity activity, int id, int speedId, int paceId, boolean reportSpeed) { - TextView textView = (TextView) activity.findViewById(id); - if (textView == null) { - return; - } - textView.setText(reportSpeed ? speedId : paceId); - } - - /** - * Sets a speed value. - * - * @param activity the activity - * @param id the speed value resource id + * @param itemId the item id + * @param speedLabelId the speed label id + * @param paceLabelId the pace label id * @param speed the speed in meters per second - * @param metricUnits true to display in metric units - * @param reportSpeed true to report speed + * @param metricUnits true if metric units + * @param reportSpeed true if report speed */ - private static void setSpeedValue( - Activity activity, int id, double speed, boolean metricUnits, boolean reportSpeed) { - TextView textView = (TextView) activity.findViewById(id); - if (textView == null) { - return; - } - textView.setText(StringUtils.formatSpeed(activity, speed, metricUnits, reportSpeed)); + private static void setSpeed(Activity activity, int itemId, int speedLabelId, int paceLabelId, + double speed, boolean metricUnits, boolean reportSpeed) { + String parts[] = StringUtils.getSpeedParts(activity, speed, metricUnits, reportSpeed); + setItem(activity, itemId, reportSpeed ? speedLabelId : paceLabelId, parts[0], parts[1]); } /** - * Sets a distance value. - * + * Sets distance value. + * * @param activity the activity - * @param id the distance value resource id * @param distance the distance in meters - * @param metricUnits true to display in metric units + * @param metricUnits true if metric units */ - private static void setDistanceValue( - Activity activity, int id, double distance, boolean metricUnits) { - TextView textView = (TextView) activity.findViewById(id); - if (textView == null) { - return; - } - textView.setText(StringUtils.formatDistance(activity, distance, metricUnits)); + private static void setDistanceValue(Activity activity, double distance, boolean metricUnits) { + String parts[] = StringUtils.getDistanceParts(activity, distance, metricUnits); + setItem(activity, R.id.stats_distance, R.string.stats_distance, parts[0], parts[1]); } /** * Sets a time value. - * + * * @param activity the activity - * @param id the time value resource id + * @param itemId the item id + * @param labelId the label id * @param time the time */ - private static void setTimeValue(Activity activity, int id, long time) { - TextView textView = (TextView) activity.findViewById(id); - if (textView == null) { - return; - } + private static void setTimeValue(Activity activity, int itemId, int labelId, long time) { String value = time == -1L ? activity.getString(R.string.value_unknown) : StringUtils.formatElapsedTime(time); - textView.setText(value); + setItem(activity, itemId, labelId, value, null); } /** * Sets an elevation value. - * + * * @param activity the activity - * @param id the elevation value resource id + * @param itemId the item id + * @param labelId the label id * @param elevation the elevation in meters - * @param metricUnits true to display in metric units + * @param metricUnits true if metric units */ private static void setElevationValue( - Activity activity, int id, double elevation, boolean metricUnits) { - TextView textView = (TextView) activity.findViewById(id); - if (textView == null) { - return; - } + Activity activity, int itemId, int labelId, double elevation, boolean metricUnits) { String value; + String unit; if (Double.isNaN(elevation) || Double.isInfinite(elevation)) { - value = activity.getString(R.string.value_unknown); + value = null; + unit = null; } else { if (metricUnits) { - value = activity.getString(R.string.value_float_meter, elevation); + value = String.format(Locale.getDefault(), ELEVATION_FORMAT, elevation); + unit = activity.getString(R.string.unit_meter); } else { elevation *= UnitConversions.M_TO_FT; - value = activity.getString(R.string.value_float_feet, elevation); + value = String.format(Locale.getDefault(), ELEVATION_FORMAT, elevation); + unit = activity.getString(R.string.unit_feet); } } - textView.setText(value); + setItem(activity, itemId, labelId, value, unit); } /** * Sets a grade value. - * + * * @param activity the activity - * @param id the grade value resource id + * @param itemId the item id + * @param labelId the label id * @param grade the grade in fraction between 0 and 1 */ - private static void setGradeValue(Activity activity, int id, double grade) { - TextView textView = (TextView) activity.findViewById(id); - if (textView == null) { - return; - } - String value; - if (Double.isNaN(grade) || Double.isInfinite(grade)) { - value = activity.getString(R.string.value_unknown); - } else { - value = activity.getString(R.string.value_integer_percent, Math.round(grade * 100)); - } - textView.setText(value); + private static void setGradeValue(Activity activity, int itemId, int labelId, double grade) { + String value = Double.isNaN(grade) || Double.isInfinite(grade) ? null + : String.format(Locale.getDefault(), GRADE_FORMAT, Math.round(grade * 100)); + setItem(activity, itemId, labelId, value, GRADE_PERCENTAGE); } /** * Sets a coordinate value. - * + * * @param activity the activity - * @param id the coordinate value resource id + * @param itemId the item id + * @param labelId the label id * @param coordinate the coordinate in degrees */ - private static void setCoordinateValue(Activity activity, int id, double coordinate) { - TextView textView = (TextView) activity.findViewById(id); - if (textView == null) { + private static void setCoordinateValue( + Activity activity, int itemId, int labelId, double coordinate) { + String value = Double.isNaN(coordinate) || Double.isInfinite(coordinate) ? null + : Location.convert(coordinate, Location.FORMAT_DEGREES); + setItem(activity, itemId, labelId, value, COORDINATE_DEGREE); + } + + /** + * Sets an item. + * + * @param activity the activity + * @param itemId the item id + * @param labelId the label id. -1 to hide the label + * @param value the value, can be null + * @param unit the unit. Null to hide the unit + */ + private static void setItem( + Activity activity, int itemId, int labelId, String value, String unit) { + View view = activity.findViewById(itemId); + TextView labelTextView = (TextView) view.findViewById(R.id.stats_label); + TextView valueTextView = (TextView) view.findViewById(R.id.stats_value); + TextView unitTextView = (TextView) view.findViewById(R.id.stats_unit); + if (labelTextView == null || valueTextView == null || unitTextView == null) { return; } - String value; - if (Double.isNaN(coordinate) || Double.isInfinite(coordinate)) { - value = activity.getString(R.string.value_unknown); + if (labelId == -1) { + labelTextView.setVisibility(View.GONE); } else { - value = activity.getString( - R.string.value_coordinate_degree, Location.convert(coordinate, Location.FORMAT_DEGREES)); + labelTextView.setVisibility(View.VISIBLE); + labelTextView.setText(labelId); } - textView.setText(value); + + if (value == null) { + value = activity.getString(R.string.value_unknown); + unitTextView.setVisibility(View.GONE); + } else { + if (unit == null) { + unitTextView.setVisibility(View.GONE); + } else { + unitTextView.setVisibility(View.VISIBLE); + unitTextView.setText(unit); + } + } + valueTextView.setText(value); } } diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/StringUtils.java b/MyTracks/src/com/google/android/apps/mytracks/util/StringUtils.java index 7a41e4b51..0e09a817e 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/util/StringUtils.java +++ b/MyTracks/src/com/google/android/apps/mytracks/util/StringUtils.java @@ -151,7 +151,8 @@ public class StringUtils { /** * Gets the distance in an array of two strings. The first string is the - * distance. The second string is the unit. + * distance. The second string is the unit. The first string is null if the + * distance is invalid. * * @param context the context * @param distance the distance @@ -160,7 +161,7 @@ public class StringUtils { public static String[] getDistanceParts(Context context, double distance, boolean metricUnits) { String[] result = new String[2]; if (Double.isNaN(distance) || Double.isInfinite(distance)) { - result[0] = context.getString(R.string.value_unknown); + result[0] = null; result[1] = context.getString(metricUnits ? R.string.unit_meter : R.string.unit_feet); return result; } @@ -188,42 +189,9 @@ public class StringUtils { } /** - * Formats the speed. - * - * @param context the context - * @param speed the speed in meters per second - * @param metricUnits true to use metric units. False to use imperial units - * @param reportSpeed true to report as speed. False to report as pace - */ - public static String formatSpeed( - Context context, double speed, boolean metricUnits, boolean reportSpeed) { - if (Double.isNaN(speed) || Double.isInfinite(speed)) { - return context.getString(R.string.value_unknown); - } - speed *= UnitConversions.MS_TO_KMH; - if (metricUnits) { - if (reportSpeed) { - return context.getString(R.string.value_float_kilometer_hour, speed); - } else { - // convert from hours to minutes - double pace = speed == 0 ? 0.0 : 60.0 / speed; - return context.getString(R.string.value_float_minute_kilometer, pace); - } - } else { - speed *= UnitConversions.KM_TO_MI; - if (reportSpeed) { - return context.getString(R.string.value_float_mile_hour, speed); - } else { - // convert from hours to minutes - double pace = speed == 0 ? 0.0 : 60.0 / speed; - return context.getString(R.string.value_float_minute_mile, pace); - } - } - } - - /** - * Gets the speed in an array of two strings. The first string is the - * speed. The second string is the unit. + * Gets the speed in an array of two strings. The first string is the speed. + * The second string is the unit. The first string is null if speed is + * invalid. * * @param context the context * @param speed the speed @@ -241,7 +209,7 @@ public class StringUtils { } result[1] = context.getString(unitId); if (Double.isNaN(speed) || Double.isInfinite(speed)) { - result[0] = context.getString(R.string.value_unknown); + result[0] = null; return result; } speed *= UnitConversions.MS_TO_KMH; diff --git a/MyTracks/src/com/google/android/apps/mytracks/widgets/TrackWidgetProvider.java b/MyTracks/src/com/google/android/apps/mytracks/widgets/TrackWidgetProvider.java index b31afbea8..77f281f3e 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/widgets/TrackWidgetProvider.java +++ b/MyTracks/src/com/google/android/apps/mytracks/widgets/TrackWidgetProvider.java @@ -314,6 +314,9 @@ public class TrackWidgetProvider extends AppWidgetProvider { TripStatistics tripStatistics, boolean metricUnits) { double totalDistance = tripStatistics == null ? Double.NaN : tripStatistics.getTotalDistance(); String[] totalDistanceParts = StringUtils.getDistanceParts(context, totalDistance, metricUnits); + if (totalDistanceParts[0] == null) { + totalDistanceParts[0] = context.getString(R.string.value_unknown); + } remoteViews.setTextViewText(ids[0], context.getString(R.string.stats_distance)); remoteViews.setTextViewText(ids[1], totalDistanceParts[0]); remoteViews.setTextViewText(ids[2], totalDistanceParts[1]); @@ -367,6 +370,11 @@ public class TrackWidgetProvider extends AppWidgetProvider { Double speed = tripStatistics == null ? Double.NaN : tripStatistics.getAverageSpeed(); String[] speedParts = StringUtils.getSpeedParts(context, speed, metricUnits, reportSpeed); + + if (speedParts[0] == null) { + speedParts[0] = context.getString(R.string.value_unknown); + } + remoteViews.setTextViewText(ids[1], speedParts[0]); remoteViews.setTextViewText(ids[2], speedParts[1]); } @@ -406,6 +414,11 @@ public class TrackWidgetProvider extends AppWidgetProvider { Double speed = tripStatistics == null ? Double.NaN : tripStatistics.getAverageMovingSpeed(); String[] speedParts = StringUtils.getSpeedParts(context, speed, metricUnits, reportSpeed); + + if (speedParts[0] == null) { + speedParts[0] = context.getString(R.string.value_unknown); + } + remoteViews.setTextViewText(ids[1], speedParts[0]); remoteViews.setTextViewText(ids[2], speedParts[1]); } diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackFormatWriterTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackFormatWriterTest.java index c74feb0f1..41c7e6a92 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackFormatWriterTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackFormatWriterTest.java @@ -115,13 +115,13 @@ public abstract class TrackFormatWriterTest extends AndroidTestCase { */ protected String writeTrack(TrackFormatWriter writer) throws Exception { OutputStream output = new ByteArrayOutputStream(BUFFER_SIZE); - writer.prepare(track, output); - writer.writeHeader(); + writer.prepare(output); + writer.writeHeader(track); writer.writeBeginWaypoints(); writer.writeWaypoint(wp1); writer.writeWaypoint(wp2); writer.writeEndWaypoints(); - writer.writeBeginTrack(location1); + writer.writeBeginTrack(track, location1); writer.writeOpenSegment(); writer.writeLocation(location1); writer.writeLocation(location2); @@ -130,7 +130,7 @@ public abstract class TrackFormatWriterTest extends AndroidTestCase { writer.writeLocation(location3); writer.writeLocation(location4); writer.writeCloseSegment(); - writer.writeEndTrack(location4); + writer.writeEndTrack(track, location4); writer.writeFooter(); writer.close(); return output.toString(); diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackWriterTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackWriterTest.java index 9c25bf72a..983bfa7dd 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackWriterTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/io/file/TrackWriterTest.java @@ -76,7 +76,7 @@ public class TrackWriterTest extends AndroidTestCase { } }; - trackWriter = new TrackWriter(myTracksProviderUtils, track, trackFormatWriter, onWriteListener); + trackWriter = new TrackWriter(myTracksProviderUtils, new Track[] {track}, trackFormatWriter, onWriteListener); } @Override @@ -91,10 +91,10 @@ public class TrackWriterTest extends AndroidTestCase { public void testWriteTrack_emptyTrack() throws Exception { // Set expected mock behavior - trackFormatWriter.prepare(track, outputStream); - trackFormatWriter.writeHeader(); - trackFormatWriter.writeBeginTrack(null); - trackFormatWriter.writeEndTrack(null); + trackFormatWriter.prepare(outputStream); + trackFormatWriter.writeHeader(track); + trackFormatWriter.writeBeginTrack(track, null); + trackFormatWriter.writeEndTrack(track, null); trackFormatWriter.writeFooter(); trackFormatWriter.close(); @@ -123,10 +123,10 @@ public class TrackWriterTest extends AndroidTestCase { myTracksProviderUtils.bulkInsertTrackPoint(locations, locations.length, TRACK_ID)); // Set expected mock behavior - trackFormatWriter.prepare(track, outputStream); - trackFormatWriter.writeHeader(); - trackFormatWriter.writeBeginTrack(null); - trackFormatWriter.writeEndTrack(null); + trackFormatWriter.prepare(outputStream); + trackFormatWriter.writeHeader(track); + trackFormatWriter.writeBeginTrack(track, null); + trackFormatWriter.writeEndTrack(track, null); trackFormatWriter.writeFooter(); trackFormatWriter.close(); @@ -162,8 +162,8 @@ public class TrackWriterTest extends AndroidTestCase { waypoint.setId(i + 1); } - trackFormatWriter.prepare(track, outputStream); - trackFormatWriter.writeHeader(); + trackFormatWriter.prepare(outputStream); + trackFormatWriter.writeHeader(track); // Expect reading/writing of the waypoints (except the first) trackFormatWriter.writeBeginWaypoints(); @@ -172,7 +172,7 @@ public class TrackWriterTest extends AndroidTestCase { trackFormatWriter.writeEndWaypoints(); // Begin the track - trackFormatWriter.writeBeginTrack(locationEq(locations[0])); + trackFormatWriter.writeBeginTrack(trackEq(track), locationEq(locations[0])); // Write locations 1-2 trackFormatWriter.writeOpenSegment(); @@ -190,7 +190,7 @@ public class TrackWriterTest extends AndroidTestCase { trackFormatWriter.writeCloseSegment(); // End the track - trackFormatWriter.writeEndTrack(locationEq(locations[5])); + trackFormatWriter.writeEndTrack(trackEq(track), locationEq(locations[5])); trackFormatWriter.writeFooter(); trackFormatWriter.close(); @@ -266,6 +266,33 @@ public class TrackWriterTest extends AndroidTestCase { return null; } + /** + * Track equals. + * + * @param track1 the track + */ + private Track trackEq(final Track track1) { + EasyMock.reportMatcher(new IArgumentMatcher() { + @Override + public boolean matches(Object object) { + if (object == null || track1 == null) { + return track1 == object; + } + Track track2 = (Track) object; + + return track1.getName().equals(track2.getName()); + } + + @Override + public void appendTo(StringBuffer buffer) { + buffer.append("trackEq("); + buffer.append(track1); + buffer.append(")"); + } + }); + return null; + } + /** * Fills the locations. * diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/util/StringUtilsTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/util/StringUtilsTest.java index a2ca52478..8e03ef044 100644 --- a/MyTracksTest/src/com/google/android/apps/mytracks/util/StringUtilsTest.java +++ b/MyTracksTest/src/com/google/android/apps/mytracks/util/StringUtilsTest.java @@ -90,28 +90,6 @@ public class StringUtilsTest extends AndroidTestCase { assertEquals("328.08 ft", StringUtils.formatDistance(getContext(), 100, false)); } - /** - * Tests {@link StringUtils#formatSpeed(android.content.Context, double, - * boolean, boolean)}. - */ - public void testFormatSpeed() { - // Speed in metric - assertEquals("36.00 km/h", StringUtils.formatSpeed(getContext(), 10, true, true)); - // Speed in imperial - assertEquals("22.37 mi/h", StringUtils.formatSpeed(getContext(), 10, false, true)); - // Pace in metric - assertEquals("1.67 min/km", StringUtils.formatSpeed(getContext(), 10, true, false)); - // Pace in imperial - assertEquals("2.68 min/mi", StringUtils.formatSpeed(getContext(), 10, false, false)); - // zero pace - assertEquals("0.00 min/km", StringUtils.formatSpeed(getContext(), 0, true, false)); - assertEquals("0.00 min/mi", StringUtils.formatSpeed(getContext(), 0, false, false)); - // speed is NaN - assertEquals("-", StringUtils.formatSpeed(getContext(), Double.NaN, true, true)); - // speed is infinite - assertEquals("-", StringUtils.formatSpeed(getContext(), Double.NEGATIVE_INFINITY, true, true)); - } - /** * Tests {@link StringUtils#formatCData(String)}. */