forked from upstream-mirrors/OpenTracks
Merge heads
This commit is contained in:
@@ -124,8 +124,6 @@ public abstract class Constants {
|
||||
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";
|
||||
|
||||
public static final String SETTINGS_NAME = "SettingsActivity";
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,8 +40,8 @@ public class HelpActivity extends AbstractMyTracksActivity {
|
||||
mapsPublicUnlisted.setText(getString(
|
||||
R.string.help_maps_public_unlisted_answer, getString(R.string.maps_public_unlisted_url)));
|
||||
|
||||
TextView googleServices = (TextView) findViewById(R.id.help_google_services_answer);
|
||||
googleServices.setText(getString(R.string.help_google_services_answer,
|
||||
TextView sendTrack = (TextView) findViewById(R.id.help_send_track_answer);
|
||||
sendTrack.setText(getString(R.string.help_send_track_answer,
|
||||
getString(R.string.send_google_maps_url),
|
||||
getString(R.string.send_google_fusion_tables_url),
|
||||
getString(R.string.send_google_docs_url)));
|
||||
|
||||
@@ -278,23 +278,21 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac
|
||||
* Shows start up dialogs.
|
||||
*/
|
||||
public void showStartupDialogs() {
|
||||
if (!EulaUtils.getEulaValue(this)) {
|
||||
if (!EulaUtils.getAcceptEula(this)) {
|
||||
Fragment fragment = getSupportFragmentManager()
|
||||
.findFragmentByTag(EulaDialogFragment.EULA_DIALOG_TAG);
|
||||
if (fragment == null) {
|
||||
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)) {
|
||||
} else if (EulaUtils.getShowWelcome(this)) {
|
||||
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)) {
|
||||
} else if (EulaUtils.getShowCheckUnits(this)) {
|
||||
Fragment fragment = getSupportFragmentManager()
|
||||
.findFragmentByTag(CheckUnitsDialogFragment.CHECK_UNITS_DIALOG_TAG);
|
||||
if (fragment == null) {
|
||||
|
||||
@@ -27,7 +27,6 @@ import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* Manager for the external data listeners and their listening types.
|
||||
@@ -77,13 +76,6 @@ class TrackDataListeners {
|
||||
private final Map<TrackDataListener, ListenerRegistration> registeredListeners =
|
||||
new HashMap<TrackDataListener, ListenerRegistration>();
|
||||
|
||||
/**
|
||||
* Map of external paused listener to its registration details.
|
||||
* This will automatically discard listeners which are GCed.
|
||||
*/
|
||||
private final WeakHashMap<TrackDataListener, ListenerRegistration> oldListeners =
|
||||
new WeakHashMap<TrackDataListener, ListenerRegistration>();
|
||||
|
||||
/** Map of data type to external listeners interested in it. */
|
||||
private final Map<ListenerDataType, Set<TrackDataListener>> listenerSetsPerType =
|
||||
new EnumMap<ListenerDataType, Set<TrackDataListener>>(ListenerDataType.class);
|
||||
@@ -109,10 +101,7 @@ class TrackDataListeners {
|
||||
throw new IllegalStateException("Listener already registered");
|
||||
}
|
||||
|
||||
ListenerRegistration registration = oldListeners.remove(listener);
|
||||
if (registration == null) {
|
||||
registration = new ListenerRegistration(listener, dataTypes);
|
||||
}
|
||||
ListenerRegistration registration = new ListenerRegistration(listener, dataTypes);
|
||||
registeredListeners.put(listener, registration);
|
||||
|
||||
for (ListenerDataType type : dataTypes) {
|
||||
@@ -142,17 +131,10 @@ class TrackDataListeners {
|
||||
for (ListenerDataType type : match.types) {
|
||||
listenerSetsPerType.get(type).remove(listener);
|
||||
}
|
||||
|
||||
// Keep it around in case it's re-registered soon
|
||||
oldListeners.put(listener, match);
|
||||
}
|
||||
|
||||
public ListenerRegistration getRegistration(TrackDataListener listener) {
|
||||
ListenerRegistration registration = registeredListeners.get(listener);
|
||||
if (registration == null) {
|
||||
registration = oldListeners.get(listener);
|
||||
}
|
||||
return registration;
|
||||
return registeredListeners.get(listener);
|
||||
}
|
||||
|
||||
public Set<TrackDataListener> getListenersFor(ListenerDataType type) {
|
||||
|
||||
+2
-1
@@ -17,6 +17,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.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
@@ -69,7 +70,7 @@ public class CheckUnitsDialogFragment extends DialogFragment {
|
||||
* Tasks to perform when done.
|
||||
*/
|
||||
private void onDone() {
|
||||
PreferencesUtils.setBoolean(getActivity(), R.string.show_check_units_dialog_key, false);
|
||||
EulaUtils.setShowCheckUnits(getActivity());
|
||||
TrackListActivity trackListActivity = (TrackListActivity) getActivity();
|
||||
trackListActivity.showStartupDialogs();
|
||||
}
|
||||
|
||||
+7
-2
@@ -33,14 +33,19 @@ import android.support.v4.app.DialogFragment;
|
||||
public class DeleteAllTrackDialogFragment extends DialogFragment {
|
||||
|
||||
public static final String DELETE_ALL_TRACK_DIALOG_TAG = "deleteAllTrackDialog";
|
||||
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
return DialogUtils.createConfirmationDialog(getActivity(),
|
||||
R.string.track_list_delete_all_confirm_message, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
MyTracksProviderUtils.Factory.get(getActivity()).deleteAllTracks();
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MyTracksProviderUtils.Factory.get(getActivity()).deleteAllTracks();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+8
-2
@@ -56,8 +56,14 @@ public class DeleteOneMarkerDialogFragment extends DialogFragment {
|
||||
R.string.marker_delete_one_marker_confirm_message, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
MyTracksProviderUtils.Factory.get(getActivity()).deleteWaypoint(
|
||||
getArguments().getLong(KEY_MARKER_ID), new DescriptionGeneratorImpl(getActivity()));
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MyTracksProviderUtils.Factory.get(getActivity()).deleteWaypoint(
|
||||
getArguments().getLong(KEY_MARKER_ID),
|
||||
new DescriptionGeneratorImpl(getActivity()));
|
||||
}
|
||||
}).start();
|
||||
Intent intent = IntentUtils.newIntent(getActivity(), MarkerListActivity.class)
|
||||
.putExtra(MarkerListActivity.EXTRA_TRACK_ID, getArguments().getLong(KEY_TRACK_ID));
|
||||
startActivity(intent);
|
||||
|
||||
+8
-3
@@ -79,13 +79,18 @@ public class DeleteOneTrackDialogFragment extends DialogFragment {
|
||||
R.string.track_detail_delete_confirm_message, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
long trackId = getArguments().getLong(KEY_TRACK_ID);
|
||||
Context context = getActivity();
|
||||
final long trackId = getArguments().getLong(KEY_TRACK_ID);
|
||||
final Context context = getActivity();
|
||||
if (trackId == PreferencesUtils.getLong(context, R.string.recording_track_id_key)) {
|
||||
TrackRecordingServiceConnectionUtils.stop(
|
||||
context, caller.getTrackRecordingServiceConnection(), false);
|
||||
}
|
||||
MyTracksProviderUtils.Factory.get(context).deleteTrack(trackId);
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MyTracksProviderUtils.Factory.get(context).deleteTrack(trackId);
|
||||
}
|
||||
}).start();
|
||||
Intent intent = IntentUtils.newIntent(context, TrackListActivity.class);
|
||||
startActivity(intent);
|
||||
// Close the activity since its content can change after delete
|
||||
|
||||
@@ -36,6 +36,7 @@ public class EulaDialogFragment extends DialogFragment {
|
||||
public static final String EULA_DIALOG_TAG = "eulaDialog";
|
||||
private static final String KEY_HAS_ACCEPTED = "hasAccepted";
|
||||
private static final String GOOGLE_URL = "m.google.com";
|
||||
private static final String KOREAN = "ko";
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link EulaDialogFragment}.
|
||||
@@ -77,7 +78,7 @@ public class EulaDialogFragment extends DialogFragment {
|
||||
.setPositiveButton(R.string.eula_accept, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
EulaUtils.setEulaValue(getActivity());
|
||||
EulaUtils.setAcceptEula(getActivity());
|
||||
TrackListActivity trackListActivity = (TrackListActivity) getActivity();
|
||||
trackListActivity.showStartupDialogs();
|
||||
}
|
||||
@@ -98,12 +99,17 @@ public class EulaDialogFragment extends DialogFragment {
|
||||
*
|
||||
*/
|
||||
private String getEulaText() {
|
||||
return getString(R.string.eula_date)
|
||||
String tos = getString(R.string.eula_date)
|
||||
+ "\n\n"
|
||||
+ getString(R.string.eula_body, GOOGLE_URL)
|
||||
+ "\n\n"
|
||||
+ getString(R.string.eula_footer, GOOGLE_URL)
|
||||
+ "\n\n"
|
||||
+ getString(R.string.eula_copyright_year);
|
||||
boolean isKorean = getResources().getConfiguration().locale.getLanguage().equals(KOREAN);
|
||||
if (isKorean) {
|
||||
tos += "\n\n" + getString(R.string.eula_korean);
|
||||
}
|
||||
return tos;
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import com.google.android.apps.mytracks.util.LocationUtils;
|
||||
import com.google.android.maps.GeoPoint;
|
||||
import com.google.android.maps.MapController;
|
||||
import com.google.android.maps.MapView;
|
||||
import com.google.android.maps.Overlay;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.Intent;
|
||||
@@ -52,6 +53,7 @@ import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A fragment to display map to the user.
|
||||
@@ -89,8 +91,8 @@ public class MapFragment extends Fragment
|
||||
|
||||
// UI elements
|
||||
private View mapViewContainer;
|
||||
private MapOverlay mapOverlay;
|
||||
private MapView mapView;
|
||||
private MapOverlay mapOverlay;
|
||||
private ImageButton myLocationImageButton;
|
||||
private TextView messageTextView;
|
||||
|
||||
@@ -104,14 +106,16 @@ public class MapFragment extends Fragment
|
||||
public View onCreateView(
|
||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
mapViewContainer = ((TrackDetailActivity) getActivity()).getMapViewContainer();
|
||||
|
||||
mapView = (MapView) mapViewContainer.findViewById(R.id.map_view);
|
||||
mapOverlay = new MapOverlay(getActivity());
|
||||
|
||||
mapView = (MapView) mapViewContainer.findViewById(R.id.map_view);
|
||||
List<Overlay> overlays = mapView.getOverlays();
|
||||
overlays.clear();
|
||||
overlays.add(mapOverlay);
|
||||
|
||||
mapView.requestFocus();
|
||||
mapView.setOnTouchListener(this);
|
||||
mapView.setBuiltInZoomControls(true);
|
||||
mapView.getOverlays().add(mapOverlay);
|
||||
myLocationImageButton = (ImageButton) mapViewContainer.findViewById(R.id.map_my_location);
|
||||
myLocationImageButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
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.apps.mytracks.util.EulaUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
@@ -55,7 +55,7 @@ public class WelcomeDialogFragment extends DialogFragment {
|
||||
}
|
||||
|
||||
private void onDone() {
|
||||
PreferencesUtils.setBoolean(getActivity(), R.string.show_welcome_dialog_key, false);
|
||||
EulaUtils.setShowWelcome(getActivity());
|
||||
TrackListActivity trackListActivity = (TrackListActivity) getActivity();
|
||||
trackListActivity.showStartupDialogs();
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
/**
|
||||
* AsyncTask to send a track to Google Docs.
|
||||
@@ -127,6 +129,13 @@ public class SendDocsAsyncTask extends AbstractSendAsyncTask {
|
||||
if (track.getCategory() != null && !track.getCategory().equals("")) {
|
||||
title += "-" + track.getCategory();
|
||||
}
|
||||
try {
|
||||
title = URLEncoder.encode(title, "UTF-8");
|
||||
title = title.replace('+', ' ');
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Log.d(TAG, "No UTF-8 encoding", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the spreadsheet ID
|
||||
publishProgress(PROGRESS_GET_SPREADSHEET_ID);
|
||||
@@ -259,7 +268,8 @@ public class SendDocsAsyncTask extends AbstractSendAsyncTask {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
spreadsheetId = SendDocsUtils.createSpreadsheet(spreadsheetTitle, documentsAuthToken, context);
|
||||
spreadsheetId = SendDocsUtils.createSpreadsheet(
|
||||
spreadsheetTitle, documentsAuthToken, context);
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, "Unable to create spreadsheet", e);
|
||||
return false;
|
||||
|
||||
@@ -15,11 +15,12 @@
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.docs;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.io.fusiontables.SendFusionTablesUtils;
|
||||
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.io.maps.SendMapsUtils;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.apps.mytracks.util.ResourceUtils;
|
||||
@@ -311,10 +312,17 @@ public class SendDocsUtils {
|
||||
appendTag(builder, "maxelevation", getElevation(stats.getMaxElevation(), metricUnits));
|
||||
appendTag(builder, "elevationunit", elevationUnit);
|
||||
|
||||
if (track.getMapId().length() > 0) {
|
||||
appendTag(builder, "map", String.format(
|
||||
Locale.US, "%s?msa=0&msid=%s", Constants.MAPSHOP_BASE_URL, track.getMapId()));
|
||||
String map = SendMapsUtils.getMapUrl(track);
|
||||
if (map == null) {
|
||||
map = context.getString(R.string.value_unknown);
|
||||
}
|
||||
appendTag(builder, "map", map);
|
||||
|
||||
String fusionTable = SendFusionTablesUtils.getMapUrl(track);
|
||||
if (fusionTable == null) {
|
||||
fusionTable = context.getString(R.string.value_unknown);
|
||||
}
|
||||
appendTag(builder, "fusiontable", fusionTable);
|
||||
|
||||
builder.append("</entry>");
|
||||
return builder.toString();
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
@@ -42,19 +43,15 @@ import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
/**
|
||||
* Imports GPX XML files to the my tracks provider.
|
||||
*
|
||||
* TODO: Show progress indication to the user.
|
||||
*
|
||||
* Imports GPX file to My Tracks.
|
||||
*
|
||||
* @author Leif Hendrik Wilden
|
||||
* @author Steffen Horlacher
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class GpxImporter extends DefaultHandler {
|
||||
|
||||
/*
|
||||
* GPX-XML tag names and attributes.
|
||||
*/
|
||||
// GPX tag names and attributes.
|
||||
private static final String TAG_TRACK = "trk";
|
||||
private static final String TAG_TRACK_POINT = "trkpt";
|
||||
private static final Object TAG_TRACK_SEGMENT = "trkseg";
|
||||
@@ -66,20 +63,21 @@ public class GpxImporter extends DefaultHandler {
|
||||
private static final String ATT_LON = "lon";
|
||||
|
||||
/**
|
||||
* The maximum number of locations to buffer for bulk-insertion into the database.
|
||||
* The maximum number of locations to buffer for bulk-insertion into the
|
||||
* database.
|
||||
*/
|
||||
private static final int MAX_BUFFERED_LOCATIONS = 512;
|
||||
|
||||
/**
|
||||
* Utilities for accessing the contnet provider.
|
||||
* Utilities for accessing the content provider.
|
||||
*/
|
||||
private final MyTracksProviderUtils providerUtils;
|
||||
private final MyTracksProviderUtils myTracksProviderUtils;
|
||||
|
||||
/**
|
||||
* List of track ids written in the database. Only contains successfully
|
||||
* written tracks.
|
||||
*/
|
||||
private final List<Long> tracksWritten;
|
||||
private final List<Long> tracksIds;
|
||||
|
||||
/**
|
||||
* Contains the current elements content.
|
||||
@@ -87,15 +85,20 @@ public class GpxImporter extends DefaultHandler {
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* Currently reading location.
|
||||
* Currently location.
|
||||
*/
|
||||
private Location location;
|
||||
|
||||
/**
|
||||
* Previous location, required for calculations.
|
||||
* Last location.
|
||||
*/
|
||||
private Location lastLocation;
|
||||
|
||||
|
||||
/**
|
||||
* Last segment location.
|
||||
*/
|
||||
private Location lastSegmentLocation;
|
||||
|
||||
/**
|
||||
* Currently reading track.
|
||||
*/
|
||||
@@ -104,7 +107,7 @@ public class GpxImporter extends DefaultHandler {
|
||||
/**
|
||||
* Statistics builder for the current track.
|
||||
*/
|
||||
private TripStatisticsBuilder statsBuilder;
|
||||
private TripStatisticsBuilder tripStatisticsBuilder;
|
||||
|
||||
/**
|
||||
* Buffer of locations to be bulk-inserted into the database.
|
||||
@@ -115,82 +118,79 @@ public class GpxImporter extends DefaultHandler {
|
||||
* Number of locations buffered to be inserted into the database.
|
||||
*/
|
||||
private int numBufferedPointInserts = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Number of locations already processed.
|
||||
*/
|
||||
private int numberOfLocations;
|
||||
private int numberOfLocations = 0;
|
||||
|
||||
/**
|
||||
* Number of segments already processed.
|
||||
*/
|
||||
private int numberOfSegments;
|
||||
private int numberOfSegments = 0;
|
||||
|
||||
/**
|
||||
* Used to identify if a track was written to the database but not yet
|
||||
* finished successfully.
|
||||
*/
|
||||
private boolean isCurrentTrackRollbackable;
|
||||
private boolean isCurrentTrackRollbackable = false;
|
||||
|
||||
/**
|
||||
* Flag to indicate if we're inside a track's xml element.
|
||||
* Some sub elements like name may be used in other parts of the gpx file,
|
||||
* and we use this to ignore them.
|
||||
* Flag to indicate if we're inside a track's xml element. Some sub elements
|
||||
* like name may be used in other parts of the GPX file, and we use this to
|
||||
* ignore them.
|
||||
*/
|
||||
private boolean isInTrackElement;
|
||||
private boolean isInTrackElement = false;
|
||||
|
||||
/**
|
||||
* Counter to find out which child level of track we are processing.
|
||||
* Counter to find out which child level of the track we are processing.
|
||||
*/
|
||||
private int trackChildDepth;
|
||||
private int trackChildDepth = 0;
|
||||
|
||||
/**
|
||||
* SAX-Locator to get current line information.
|
||||
* SAX locator to get the current line information.
|
||||
*/
|
||||
private Locator locator;
|
||||
private Location lastSegmentLocation;
|
||||
|
||||
/**
|
||||
* Reads GPS tracks from a GPX file and writes tracks and their coordinates to
|
||||
* the database.
|
||||
*
|
||||
* @param is a input steam with gpx-xml data
|
||||
* @return long[] array of track ids written in the database
|
||||
* @throws SAXException a parsing error
|
||||
* @throws ParserConfigurationException internal error
|
||||
* @throws IOException a file reading problem
|
||||
* @param inputStream an input stream for the GPX file
|
||||
* @param myTracksProviderUtils my tracks provider utils
|
||||
* @return long[] array of track ids written to the database.
|
||||
*/
|
||||
public static long[] importGPXFile(final InputStream is,
|
||||
final MyTracksProviderUtils providerUtils)
|
||||
public static long[] importGPXFile(
|
||||
final InputStream inputStream, final MyTracksProviderUtils myTracksProviderUtils)
|
||||
throws ParserConfigurationException, SAXException, IOException {
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
GpxImporter handler = new GpxImporter(providerUtils);
|
||||
SAXParser parser = factory.newSAXParser();
|
||||
long[] trackIds = null;
|
||||
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
|
||||
SAXParser saxParser = saxParserFactory.newSAXParser();
|
||||
GpxImporter gpxImporter = new GpxImporter(myTracksProviderUtils);
|
||||
long[] trackIds = new long[0];
|
||||
|
||||
try {
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
parser.parse(is, handler);
|
||||
saxParser.parse(inputStream, gpxImporter);
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
Log.d(Constants.TAG, "Total import time: " + (end - start) + "ms");
|
||||
|
||||
trackIds = handler.getImportedTrackIds();
|
||||
trackIds = gpxImporter.getImportedTrackIds();
|
||||
if (trackIds.length == 0) {
|
||||
throw new IOException("No track imported.");
|
||||
}
|
||||
} finally {
|
||||
// delete track if not finished
|
||||
handler.rollbackUnfinishedTracks();
|
||||
// Delete track if not finished
|
||||
gpxImporter.rollbackUnfinishedTracks();
|
||||
}
|
||||
|
||||
return trackIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor, requires providerUtils for writing tracks the database.
|
||||
*/
|
||||
public GpxImporter(MyTracksProviderUtils providerUtils) {
|
||||
this.providerUtils = providerUtils;
|
||||
tracksWritten = new ArrayList<Long>();
|
||||
public GpxImporter(MyTracksProviderUtils myTracksProviderUtils) {
|
||||
this.myTracksProviderUtils = myTracksProviderUtils;
|
||||
tracksIds = new ArrayList<Long>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -199,16 +199,18 @@ public class GpxImporter extends DefaultHandler {
|
||||
if (content == null) {
|
||||
content = newContent;
|
||||
} else {
|
||||
// In 99% of the cases, a single call to this method will be made for each
|
||||
// sequence of characters we're interested in, so we'll rarely be
|
||||
// concatenating strings, thus not justifying the use of a StringBuilder.
|
||||
/*
|
||||
* In 99% of the cases, a single call to this method will be made for each
|
||||
* sequence of characters we're interested in, so we'll rarely be
|
||||
* concatenating strings, thus not justifying the use of a StringBuilder.
|
||||
*/
|
||||
content += newContent;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String name,
|
||||
Attributes attributes) throws SAXException {
|
||||
public void startElement(String uri, String localName, String name, Attributes attributes)
|
||||
throws SAXException {
|
||||
if (isInTrackElement) {
|
||||
trackChildDepth++;
|
||||
if (localName.equals(TAG_TRACK_POINT)) {
|
||||
@@ -216,8 +218,7 @@ public class GpxImporter extends DefaultHandler {
|
||||
} else if (localName.equals(TAG_TRACK_SEGMENT)) {
|
||||
onTrackSegmentElementStart();
|
||||
} else if (localName.equals(TAG_TRACK)) {
|
||||
String msg = createErrorMessage("Invalid GPX-XML detected");
|
||||
throw new SAXException(msg);
|
||||
throw new SAXException(createErrorMessage("Invalid GPX detected."));
|
||||
}
|
||||
} else if (localName.equals(TAG_TRACK)) {
|
||||
isInTrackElement = true;
|
||||
@@ -227,8 +228,7 @@ public class GpxImporter extends DefaultHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String name)
|
||||
throws SAXException {
|
||||
public void endElement(String uri, String localName, String name) throws SAXException {
|
||||
if (!isInTrackElement) {
|
||||
content = null;
|
||||
return;
|
||||
@@ -270,33 +270,58 @@ public class GpxImporter extends DefaultHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Track object and insert empty track in database. Track will be
|
||||
* updated with missing values later.
|
||||
* Rolls back last track if possible.
|
||||
*/
|
||||
public void rollbackUnfinishedTracks() {
|
||||
if (isCurrentTrackRollbackable) {
|
||||
myTracksProviderUtils.deleteTrack(track.getId());
|
||||
isCurrentTrackRollbackable = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On track element start.
|
||||
*/
|
||||
private void onTrackElementStart() {
|
||||
track = new Track();
|
||||
numberOfLocations = 0;
|
||||
|
||||
Uri trackUri = providerUtils.insertTrack(track);
|
||||
long trackId = Long.parseLong(trackUri.getLastPathSegment());
|
||||
Uri uri = myTracksProviderUtils.insertTrack(track);
|
||||
long trackId = Long.parseLong(uri.getLastPathSegment());
|
||||
track.setId(trackId);
|
||||
isCurrentTrackRollbackable = true;
|
||||
}
|
||||
|
||||
private void onDescriptionElementEnd() {
|
||||
track.setDescription(content.toString().trim());
|
||||
}
|
||||
/**
|
||||
* On track element end.
|
||||
*/
|
||||
private void onTrackElementEnd() {
|
||||
if (lastLocation != null) {
|
||||
flushPoints();
|
||||
|
||||
private void onNameElementEnd() {
|
||||
track.setName(content.toString().trim());
|
||||
// Calculate statistics for the imported track
|
||||
tripStatisticsBuilder.pauseAt(lastLocation.getTime());
|
||||
track.setStopId(getLastPointId());
|
||||
} else {
|
||||
tripStatisticsBuilder = new TripStatisticsBuilder(0);
|
||||
tripStatisticsBuilder.pauseAt(0);
|
||||
}
|
||||
track.setTripStatistics(tripStatisticsBuilder.getStatistics());
|
||||
track.setNumberOfPoints(numberOfLocations);
|
||||
myTracksProviderUtils.updateTrack(track);
|
||||
tracksIds.add(track.getId());
|
||||
isCurrentTrackRollbackable = false;
|
||||
lastSegmentLocation = null;
|
||||
lastLocation = null;
|
||||
tripStatisticsBuilder = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Track segment started.
|
||||
* On track segment start.
|
||||
*/
|
||||
private void onTrackSegmentElementStart() {
|
||||
if (numberOfSegments > 0) {
|
||||
// Add a segment separator:
|
||||
// Add a segment separator
|
||||
location = new Location(LocationManager.GPS_PROVIDER);
|
||||
location.setLatitude(100.0);
|
||||
location.setLongitude(100.0);
|
||||
@@ -304,73 +329,61 @@ public class GpxImporter extends DefaultHandler {
|
||||
if (lastLocation != null) {
|
||||
location.setTime(lastLocation.getTime());
|
||||
}
|
||||
insertTrackPoint(location);
|
||||
insertPoint(location);
|
||||
lastLocation = location;
|
||||
lastSegmentLocation = null;
|
||||
location = null;
|
||||
}
|
||||
|
||||
numberOfSegments++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads trackpoint attributes and assigns them to the current location.
|
||||
*
|
||||
* @param attributes xml attributes
|
||||
* On track segment element end.
|
||||
*/
|
||||
private void onTrackSegmentElementEnd() {
|
||||
// Nothing to be done
|
||||
}
|
||||
|
||||
/**
|
||||
* On track point element start.
|
||||
*
|
||||
* @param attributes the attributes
|
||||
*/
|
||||
private void onTrackPointElementStart(Attributes attributes) throws SAXException {
|
||||
if (location != null) {
|
||||
String errorMsg = createErrorMessage("Found a track point inside another one.");
|
||||
throw new SAXException(errorMsg);
|
||||
throw new SAXException(createErrorMessage("Found a track point inside another one."));
|
||||
}
|
||||
|
||||
location = createLocationFromAttributes(attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a location with the position parsed from the given
|
||||
* attributes.
|
||||
*
|
||||
* @param attributes the attributes to parse
|
||||
* @return the created location
|
||||
* @throws SAXException if the attributes cannot be parsed
|
||||
*/
|
||||
private Location createLocationFromAttributes(Attributes attributes) throws SAXException {
|
||||
String latitude = attributes.getValue(ATT_LAT);
|
||||
String longitude = attributes.getValue(ATT_LON);
|
||||
|
||||
|
||||
if (latitude == null || longitude == null) {
|
||||
throw new SAXException(createErrorMessage("Point with no longitude or latitude"));
|
||||
throw new SAXException(createErrorMessage("Point with no longitude or latitude."));
|
||||
}
|
||||
|
||||
// create new location and set attributes
|
||||
Location loc = new Location(LocationManager.GPS_PROVIDER);
|
||||
|
||||
Location newLocation = new Location(LocationManager.GPS_PROVIDER);
|
||||
try {
|
||||
loc.setLatitude(Double.parseDouble(latitude));
|
||||
loc.setLongitude(Double.parseDouble(longitude));
|
||||
newLocation.setLatitude(Double.parseDouble(latitude));
|
||||
newLocation.setLongitude(Double.parseDouble(longitude));
|
||||
} catch (NumberFormatException e) {
|
||||
String msg = createErrorMessage(
|
||||
"Unable to parse lat/long: " + latitude + "/" + longitude);
|
||||
throw new SAXException(msg, e);
|
||||
throw new SAXException(createErrorMessage(
|
||||
"Unable to parse latitude/longitude: " + latitude + "/" + longitude), e);
|
||||
}
|
||||
return loc;
|
||||
location = newLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Track point finished, write in database.
|
||||
*
|
||||
* @throws SAXException - thrown if track point is invalid
|
||||
* On track point element end.
|
||||
*/
|
||||
private void onTrackPointElementEnd() throws SAXException {
|
||||
if (LocationUtils.isValidLocation(location)) {
|
||||
if (statsBuilder == null) {
|
||||
if (tripStatisticsBuilder == null) {
|
||||
// first point did not have a time, start stats builder without it
|
||||
statsBuilder = new TripStatisticsBuilder(0);
|
||||
tripStatisticsBuilder = new TripStatisticsBuilder(0);
|
||||
}
|
||||
statsBuilder.addLocation(location, location.getTime());
|
||||
tripStatisticsBuilder.addLocation(location, location.getTime());
|
||||
|
||||
// insert in db
|
||||
insertTrackPoint(location);
|
||||
insertPoint(location);
|
||||
|
||||
// first track point?
|
||||
if (lastLocation == null && numberOfSegments == 1) {
|
||||
@@ -382,78 +395,31 @@ public class GpxImporter extends DefaultHandler {
|
||||
location = null;
|
||||
} else {
|
||||
// invalid location - abort import
|
||||
String msg = createErrorMessage("Invalid location detected: " + location);
|
||||
throw new SAXException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private void insertTrackPoint(Location loc) {
|
||||
bufferedPointInserts[numBufferedPointInserts] = loc;
|
||||
numBufferedPointInserts++;
|
||||
numberOfLocations++;
|
||||
|
||||
if (numBufferedPointInserts >= MAX_BUFFERED_LOCATIONS) {
|
||||
flushPointInserts();
|
||||
}
|
||||
}
|
||||
|
||||
private void flushPointInserts() {
|
||||
if (numBufferedPointInserts <= 0) { return; }
|
||||
|
||||
providerUtils.bulkInsertTrackPoints(bufferedPointInserts, numBufferedPointInserts, track.getId());
|
||||
numBufferedPointInserts = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Track segment finished.
|
||||
*/
|
||||
private void onTrackSegmentElementEnd() {
|
||||
// Nothing to be done
|
||||
}
|
||||
|
||||
/**
|
||||
* Track finished - update in database.
|
||||
*/
|
||||
private void onTrackElementEnd() {
|
||||
if (lastLocation != null) {
|
||||
flushPointInserts();
|
||||
|
||||
// Calculate statistics for the imported track and update
|
||||
statsBuilder.pauseAt(lastLocation.getTime());
|
||||
track.setStopId(getLastPointId());
|
||||
track.setNumberOfPoints(numberOfLocations);
|
||||
track.setTripStatistics(statsBuilder.getStatistics());
|
||||
providerUtils.updateTrack(track);
|
||||
tracksWritten.add(track.getId());
|
||||
isCurrentTrackRollbackable = false;
|
||||
lastSegmentLocation = null;
|
||||
lastLocation = null;
|
||||
statsBuilder = null;
|
||||
} else {
|
||||
// track contains no track points makes no real
|
||||
// sense to import it as we have no location
|
||||
// information -> roll back
|
||||
rollbackUnfinishedTracks();
|
||||
throw new SAXException(createErrorMessage("Invalid location detected: " + location));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting time and doing additional calculations as this is the last value
|
||||
* required. Also sets the start time for track and statistics as there is no
|
||||
* start time in the track root element.
|
||||
*
|
||||
* @throws SAXException on parsing errors
|
||||
* On time element end. Sets location time and doing additional calculations
|
||||
* as this is the last value required for the location. Also sets the start time
|
||||
* for the trip statistics builder as there is no start time in the track root
|
||||
* element.
|
||||
*/
|
||||
private void onTimeElementEnd() throws SAXException {
|
||||
if (location == null) { return; }
|
||||
if (location == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (content == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the time
|
||||
long time;
|
||||
try {
|
||||
time = StringUtils.getTime(content.trim());
|
||||
} catch (IllegalArgumentException e) {
|
||||
String msg = createErrorMessage("Unable to parse time: " + content);
|
||||
throw new SAXException(msg, e);
|
||||
throw new SAXException(createErrorMessage("Unable to parse time: " + content), e);
|
||||
}
|
||||
|
||||
// Calculate derived attributes from previous point
|
||||
@@ -465,11 +431,12 @@ public class GpxImporter extends DefaultHandler {
|
||||
Log.w(Constants.TAG, "Found negative time change.");
|
||||
} else {
|
||||
|
||||
// We don't have a speed and bearing in GPX, make something up from
|
||||
// the last two points.
|
||||
// TODO GPS points tend to have some inherent imprecision,
|
||||
// speed and bearing will likely be off, so the statistics for things like
|
||||
// max speed will also be off.
|
||||
/*
|
||||
* We don't have a speed and bearing in GPX, make something up from the
|
||||
* last two points. GPS points tend to have some inherent imprecision,
|
||||
* speed and bearing will likely be off, so the statistics for things
|
||||
* like max speed will also be off.
|
||||
*/
|
||||
float speed = location.distanceTo(lastLocation) * 1000.0f / timeDifference;
|
||||
location.setSpeed(speed);
|
||||
location.setBearing(lastSegmentLocation.bearingTo(location));
|
||||
@@ -480,69 +447,96 @@ public class GpxImporter extends DefaultHandler {
|
||||
location.setTime(time);
|
||||
|
||||
// initialize start time with time of first track point
|
||||
if (statsBuilder == null) {
|
||||
statsBuilder = new TripStatisticsBuilder(time);
|
||||
if (tripStatisticsBuilder == null) {
|
||||
tripStatisticsBuilder = new TripStatisticsBuilder(time);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On altitude element end.
|
||||
*/
|
||||
private void onAltitudeElementEnd() throws SAXException {
|
||||
if (location != null) {
|
||||
if (location != null && content != null) {
|
||||
try {
|
||||
location.setAltitude(Double.parseDouble(content));
|
||||
} catch (NumberFormatException e) {
|
||||
String msg = createErrorMessage("Unable to parse altitude: " + content);
|
||||
throw new SAXException(msg, e);
|
||||
throw new SAXException(createErrorMessage("Unable to parse altitude: " + content), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the last track if it was not completely imported.
|
||||
* On name element end.
|
||||
*/
|
||||
public void rollbackUnfinishedTracks() {
|
||||
if (isCurrentTrackRollbackable) {
|
||||
providerUtils.deleteTrack(track.getId());
|
||||
isCurrentTrackRollbackable = false;
|
||||
private void onNameElementEnd() {
|
||||
if (content != null) {
|
||||
track.setName(content.toString().trim());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all track ids of the tracks created by this importer run.
|
||||
* On description element end.
|
||||
*/
|
||||
private void onDescriptionElementEnd() {
|
||||
if (content != null) {
|
||||
track.setDescription(content.toString().trim());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a point.
|
||||
*
|
||||
* @return array of track ids
|
||||
* @param newLocation the location
|
||||
*/
|
||||
private void insertPoint(Location newLocation) {
|
||||
bufferedPointInserts[numBufferedPointInserts] = newLocation;
|
||||
numBufferedPointInserts++;
|
||||
numberOfLocations++;
|
||||
|
||||
if (numBufferedPointInserts >= MAX_BUFFERED_LOCATIONS) {
|
||||
flushPoints();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the points to the database.
|
||||
*/
|
||||
private void flushPoints() {
|
||||
if (numBufferedPointInserts <= 0) {
|
||||
return;
|
||||
}
|
||||
myTracksProviderUtils.bulkInsertTrackPoints(
|
||||
bufferedPointInserts, numBufferedPointInserts, track.getId());
|
||||
numBufferedPointInserts = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the imported track ids.
|
||||
*
|
||||
*/
|
||||
private long[] getImportedTrackIds() {
|
||||
// Convert from java.lang.Long for convenience
|
||||
long[] result = new long[tracksWritten.size()];
|
||||
long[] result = new long[tracksIds.size()];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = tracksWritten.get(i);
|
||||
result[i] = tracksIds.get(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of the last point inserted into the database.
|
||||
* Gets the last point id inserted into the database.
|
||||
*/
|
||||
private long getLastPointId() {
|
||||
flushPointInserts();
|
||||
|
||||
return providerUtils.getLastLocationId(track.getId());
|
||||
flushPoints();
|
||||
return myTracksProviderUtils.getLastLocationId(track.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a parsing error message with current line information.
|
||||
* Creates an error message.
|
||||
*
|
||||
* @param details details about the error, will be appended
|
||||
* @return error message string with current line information
|
||||
* @param message the message
|
||||
*/
|
||||
private String createErrorMessage(String details) {
|
||||
StringBuffer msg = new StringBuffer();
|
||||
msg.append("Parsing error at line: ");
|
||||
msg.append(locator.getLineNumber());
|
||||
msg.append(" column: ");
|
||||
msg.append(locator.getColumnNumber());
|
||||
msg.append(". ");
|
||||
msg.append(details);
|
||||
return msg.toString();
|
||||
private String createErrorMessage(String message) {
|
||||
return String.format(Locale.US, "Parsing error at line: %d column: %d. %s",
|
||||
locator.getLineNumber(), locator.getColumnNumber(), message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,7 +318,9 @@ class TrackWriterImpl implements TrackWriter {
|
||||
locationFactory);
|
||||
try {
|
||||
if (!it.hasNext()) {
|
||||
Log.w(Constants.TAG, "Unable to get any points to write");
|
||||
// Writes an empty track
|
||||
writer.writeBeginTrack(null);
|
||||
writer.writeEndTrack(null);
|
||||
return;
|
||||
}
|
||||
int pointNumber = 0;
|
||||
|
||||
+2
-3
@@ -277,9 +277,8 @@ public class SendFusionTablesAsyncTask extends AbstractSendAsyncTask {
|
||||
distances.add(tripStatisticsBuilder.getStatistics().getTotalDistance());
|
||||
elevations.add(elevationBuffer.getAverage());
|
||||
DescriptionGenerator descriptionGenerator = new DescriptionGeneratorImpl(context);
|
||||
track.setDescription("<p>" + track.getDescription() + "</p><p>"
|
||||
+ descriptionGenerator.generateTrackDescription(track, distances, elevations, true)
|
||||
+ "</p>");
|
||||
track.setDescription(
|
||||
descriptionGenerator.generateTrackDescription(track, distances, elevations, true));
|
||||
String name = context.getString(R.string.marker_label_end, track.getName());
|
||||
if (!createNewPoint(name, track.getDescription(), lastLocation, MARKER_TYPE_END)) {
|
||||
Log.d(TAG, "Unable to create the end marker");
|
||||
|
||||
+4
-1
@@ -52,7 +52,10 @@ public class SendFusionTablesUtils {
|
||||
* @return the url.
|
||||
*/
|
||||
public static String getMapUrl(Track track) {
|
||||
if (track == null || track.getTripStatistics() == null || track.getTableId() == null) {
|
||||
if (track == null
|
||||
|| track.getTripStatistics() == null
|
||||
|| track.getTableId() == null
|
||||
|| track.getTableId().length() == 0) {
|
||||
Log.e(TAG, "Invalid track");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -54,11 +54,12 @@ public class SendMapsUtils {
|
||||
* @return the url if available.
|
||||
*/
|
||||
public static String getMapUrl(Track track) {
|
||||
if (track == null || track.getMapId() == null) {
|
||||
if (track == null
|
||||
|| track.getMapId() == null
|
||||
|| track.getMapId().length() == 0) {
|
||||
Log.e(TAG, "Invalid track");
|
||||
return null;
|
||||
}
|
||||
|
||||
return MapsClient.buildMapUrl(track.getMapId());
|
||||
}
|
||||
|
||||
|
||||
+3
-25
@@ -17,7 +17,6 @@
|
||||
package com.google.android.apps.mytracks.settings;
|
||||
|
||||
import com.google.android.apps.mytracks.util.DialogUtils;
|
||||
import com.google.android.apps.mytracks.util.PreferencesUtils;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.Dialog;
|
||||
@@ -48,23 +47,12 @@ public class SharingSettingsActivity extends AbstractSettingsActivity {
|
||||
defaultMapPublicCheckBoxPreference = (CheckBoxPreference) findPreference(
|
||||
getString(R.string.default_map_public_key));
|
||||
defaultMapPublicCheckBoxPreference.setSummaryOn(getString(
|
||||
R.string.settings_sharing_map_public_summary,
|
||||
R.string.settings_sharing_new_map_public_summary_on,
|
||||
getString(R.string.maps_public_unlisted_url)));
|
||||
defaultMapPublicCheckBoxPreference.setSummaryOff(getString(
|
||||
R.string.settings_sharing_map_unlisted_summary,
|
||||
R.string.settings_sharing_new_map_public_summary_off,
|
||||
getString(R.string.maps_public_unlisted_url)));
|
||||
boolean defaultMapPublic = PreferencesUtils.getBoolean(
|
||||
this, R.string.default_map_public_key, PreferencesUtils.DEFAULT_MAP_PUBLIC_DEFAULT);
|
||||
updateDefaultMapPublicTitle(defaultMapPublic);
|
||||
defaultMapPublicCheckBoxPreference.setOnPreferenceChangeListener(
|
||||
new OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
updateDefaultMapPublicTitle((Boolean) newValue);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
allowAccessCheckBoxPreference = (CheckBoxPreference) findPreference(
|
||||
getString(R.string.allow_access_key));
|
||||
allowAccessCheckBoxPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
|
||||
@@ -94,14 +82,4 @@ public class SharingSettingsActivity extends AbstractSettingsActivity {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the title for the default map public check box preference.
|
||||
*
|
||||
* @param value the value
|
||||
*/
|
||||
private void updateDefaultMapPublicTitle(boolean value) {
|
||||
defaultMapPublicCheckBoxPreference.setTitle(value ? R.string.settings_sharing_map_public
|
||||
: R.string.settings_sharing_map_unlisted);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,21 +29,47 @@ public class EulaUtils {
|
||||
private static final String EULA_PREFERENCE_FILE = "eula";
|
||||
|
||||
// Accepting Google mobile terms of service
|
||||
private static final String EULA_PREFERENCE_KEY = "eula.google_mobile_tos_accepted";
|
||||
|
||||
private static final String ACCEPT_EULA_PREFERENCE_KEY = "eula.google_mobile_tos_accepted";
|
||||
private static final String SHOW_WELCOME_PREFERENCE_KEY = "showWelcome";
|
||||
private static final String SHOW_CHECK_UNITS_PREFERENCE_KEY = "showCheckUnits";
|
||||
|
||||
private EulaUtils() {}
|
||||
|
||||
public static boolean getEulaValue(Context context) {
|
||||
SharedPreferences sharedPreferences = context.getSharedPreferences(
|
||||
EULA_PREFERENCE_FILE, Context.MODE_PRIVATE);
|
||||
return sharedPreferences.getBoolean(EULA_PREFERENCE_KEY, false);
|
||||
public static boolean getAcceptEula(Context context) {
|
||||
return getValue(context, ACCEPT_EULA_PREFERENCE_KEY, false);
|
||||
}
|
||||
|
||||
public static void setEulaValue(Context context) {
|
||||
public static void setAcceptEula(Context context) {
|
||||
setValue(context, ACCEPT_EULA_PREFERENCE_KEY, true);
|
||||
}
|
||||
|
||||
public static boolean getShowWelcome(Context context) {
|
||||
return getValue(context, SHOW_WELCOME_PREFERENCE_KEY, true);
|
||||
}
|
||||
|
||||
public static void setShowWelcome(Context context) {
|
||||
setValue(context, SHOW_WELCOME_PREFERENCE_KEY, false);
|
||||
}
|
||||
|
||||
public static boolean getShowCheckUnits(Context context) {
|
||||
return getValue(context, SHOW_CHECK_UNITS_PREFERENCE_KEY, true);
|
||||
}
|
||||
|
||||
public static void setShowCheckUnits(Context context) {
|
||||
setValue(context, SHOW_CHECK_UNITS_PREFERENCE_KEY, false);
|
||||
}
|
||||
|
||||
private static boolean getValue(Context context, String key, boolean defaultValue) {
|
||||
SharedPreferences sharedPreferences = context.getSharedPreferences(
|
||||
EULA_PREFERENCE_FILE, Context.MODE_PRIVATE);
|
||||
return sharedPreferences.getBoolean(key, defaultValue);
|
||||
}
|
||||
|
||||
private static void setValue(Context context, String key, boolean value) {
|
||||
SharedPreferences sharedPreferences = context.getSharedPreferences(
|
||||
EULA_PREFERENCE_FILE, Context.MODE_PRIVATE);
|
||||
Editor editor = sharedPreferences.edit();
|
||||
editor.putBoolean(EULA_PREFERENCE_KEY, true);
|
||||
editor.putBoolean(key, value);
|
||||
ApiAdapterFactory.getApiAdapter().applyPreferenceChanges(editor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,9 +73,7 @@ public class PreferencesUtils {
|
||||
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 SHOW_CHECK_UNITS_DIALOG_DEFAULT = true;
|
||||
public static final boolean SHOW_CONFIRM_SHARING_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;
|
||||
|
||||
@@ -29,10 +29,13 @@ import java.util.HashMap;
|
||||
*/
|
||||
public class TrackIconUtils {
|
||||
|
||||
private static final String AIRPLANE = "AIRPLANE";
|
||||
private static final String BIKE = "BIKE";
|
||||
private static final String BOAT = "BOAT";
|
||||
private static final String DRIVE = "DRIVE";
|
||||
private static final String RUN = "RUN";
|
||||
private static final String SKI = "SKI";
|
||||
private static final String SNOW_BOARDING = "SNOW_BOARDING";
|
||||
private static final String WALK = "WALK";
|
||||
|
||||
private TrackIconUtils() {}
|
||||
@@ -40,13 +43,21 @@ public class TrackIconUtils {
|
||||
private static HashMap<String, Integer> map = new HashMap<String, Integer>();
|
||||
|
||||
static {
|
||||
map.put(AIRPLANE, R.drawable.track_airplane);
|
||||
map.put(BIKE, R.drawable.track_bike);
|
||||
map.put(BOAT, R.drawable.track_boat);
|
||||
map.put(DRIVE, R.drawable.track_drive);
|
||||
map.put(RUN, R.drawable.track_run);
|
||||
map.put(SKI, R.drawable.track_ski);
|
||||
map.put(SNOW_BOARDING, R.drawable.track_snow_boarding);
|
||||
map.put(WALK, R.drawable.track_walk);
|
||||
}
|
||||
|
||||
private static int[] airplane = new int[] {
|
||||
R.string.activity_type_airplane,
|
||||
R.string.activity_type_commercial_airplane,
|
||||
R.string.activity_type_rc_airplane
|
||||
};
|
||||
private static int[] bike = new int[] {
|
||||
R.string.activity_type_biking,
|
||||
R.string.activity_type_cycling,
|
||||
@@ -55,6 +66,12 @@ public class TrackIconUtils {
|
||||
R.string.activity_type_mountain_biking,
|
||||
R.string.activity_type_road_biking,
|
||||
R.string.activity_type_track_cycling };
|
||||
private static int[] boat = new int[] {
|
||||
R.string.activity_type_boat,
|
||||
R.string.activity_type_ferry,
|
||||
R.string.activity_type_motor_boating,
|
||||
R.string.activity_type_rc_boat
|
||||
};
|
||||
private static int[] drive = new int[] {
|
||||
R.string.activity_type_atv,
|
||||
R.string.activity_type_driving,
|
||||
@@ -68,6 +85,9 @@ public class TrackIconUtils {
|
||||
private static int[] ski = new int[] {
|
||||
R.string.activity_type_cross_country_skiing,
|
||||
R.string.activity_type_skiing };
|
||||
private static int[] snowBoarding = new int[] {
|
||||
R.string.activity_type_snow_boarding
|
||||
};
|
||||
private static int[] walk = new int[] {
|
||||
R.string.activity_type_hiking,
|
||||
R.string.activity_type_off_trail_hiking,
|
||||
@@ -95,9 +115,15 @@ public class TrackIconUtils {
|
||||
* @param activityType the activity type
|
||||
*/
|
||||
public static String getIconValue(Context context, String activityType) {
|
||||
if (inList(context, activityType, airplane)) {
|
||||
return AIRPLANE;
|
||||
}
|
||||
if (inList(context, activityType, bike)) {
|
||||
return BIKE;
|
||||
}
|
||||
if (inList(context, activityType, boat)) {
|
||||
return BOAT;
|
||||
}
|
||||
if (inList(context, activityType, drive)) {
|
||||
return DRIVE;
|
||||
}
|
||||
@@ -107,6 +133,9 @@ public class TrackIconUtils {
|
||||
if (inList(context, activityType, ski)) {
|
||||
return SKI;
|
||||
}
|
||||
if (inList(context, activityType, snowBoarding)) {
|
||||
return SNOW_BOARDING;
|
||||
}
|
||||
if (inList(context, activityType, walk)) {
|
||||
return WALK;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.database.ContentObserver;
|
||||
import android.os.Handler;
|
||||
import android.support.v4.app.TaskStackBuilder;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
/**
|
||||
@@ -178,7 +179,7 @@ public class TrackWidgetProvider extends AppWidgetProvider
|
||||
if (action != null) {
|
||||
updateButton(remoteViews, action);
|
||||
}
|
||||
updateStatistics(remoteViews);
|
||||
updateView(remoteViews);
|
||||
|
||||
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
||||
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(
|
||||
@@ -195,25 +196,25 @@ public class TrackWidgetProvider extends AppWidgetProvider
|
||||
* @param action the action
|
||||
*/
|
||||
private void updateButton(RemoteViews remoteViews, String action) {
|
||||
int trackAction = trackStartedBroadcastAction.equals(action) ? R.string.track_action_end
|
||||
: R.string.track_action_start;
|
||||
boolean isRecording = trackStartedBroadcastAction.equals(action);
|
||||
remoteViews.setViewVisibility(R.id.track_widget_record_button, isRecording ? View.GONE
|
||||
: View.VISIBLE);
|
||||
remoteViews.setViewVisibility(R.id.track_widget_stop_button, isRecording ? View.VISIBLE
|
||||
: View.INVISIBLE);
|
||||
Intent intent = new Intent(context, ControlRecordingService.class).setAction(
|
||||
context.getString(trackAction));
|
||||
context.getString(isRecording ? R.string.track_action_end : R.string.track_action_start));
|
||||
PendingIntent pendingIntent = PendingIntent.getService(
|
||||
context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
remoteViews.setOnClickPendingIntent(R.id.track_widget_button, pendingIntent);
|
||||
|
||||
int icon = trackStartedBroadcastAction.equals(action) ? R.drawable.app_widget_button_enabled
|
||||
: R.drawable.app_widget_button_disabled;
|
||||
remoteViews.setImageViewResource(R.id.track_widget_button, icon);
|
||||
remoteViews.setOnClickPendingIntent(isRecording ? R.id.track_widget_stop_button
|
||||
: R.id.track_widget_record_button, pendingIntent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates statistics.
|
||||
* Updates view.
|
||||
*
|
||||
* @param remoteViews the remote views
|
||||
*/
|
||||
private void updateStatistics(RemoteViews remoteViews) {
|
||||
private void updateView(RemoteViews remoteViews) {
|
||||
Track track = selectedTrackId != PreferencesUtils.SELECTED_TRACK_ID_DEFAULT
|
||||
? myTracksProviderUtils.getTrack(selectedTrackId) : myTracksProviderUtils.getLastTrack();
|
||||
TripStatistics tripStatistics = track == null ? null : track.getTripStatistics();
|
||||
@@ -249,7 +250,9 @@ public class TrackWidgetProvider extends AppWidgetProvider
|
||||
}
|
||||
TaskStackBuilder taskStackBuilder = TaskStackBuilder.from(context);
|
||||
taskStackBuilder.addNextIntent(intent);
|
||||
PendingIntent pendingIntent = taskStackBuilder.getPendingIntent(0, 0);
|
||||
remoteViews.setOnClickPendingIntent(
|
||||
R.id.track_widget_statistics, taskStackBuilder.getPendingIntent(0, 0));
|
||||
R.id.track_widget_statistics, pendingIntent);
|
||||
remoteViews.setOnClickPendingIntent(R.id.track_widget_icon, pendingIntent);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user