diff --git a/MyTracks/AndroidManifest.xml b/MyTracks/AndroidManifest.xml
index 99a9f617d..3598aec25 100755
--- a/MyTracks/AndroidManifest.xml
+++ b/MyTracks/AndroidManifest.xml
@@ -161,7 +161,7 @@ limitations under the License.
-
+
diff --git a/MyTracks/res/layout/about.xml b/MyTracks/res/layout/about.xml
index 51f432b90..753d860e8 100644
--- a/MyTracks/res/layout/about.xml
+++ b/MyTracks/res/layout/about.xml
@@ -58,6 +58,11 @@ limitations under the License.
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:orientation="vertical">
+
+
+
+
+
+ - Inactiu
+ - 1 min
+ - 2 min
+ - 5 min
+ - 10 min
+ - 15 min
+ - 30 min
+ - 60 min
+
+
+
+
+ - 1 m
+ - 2 m
+ - 3 m
+ - 4 m
+ - 5 m (recomanat)
+ - 10 m
+ - 100 m
+
+
+
+ - 3 ft
+ - 6 ft
+ - 10 ft
+ - 13 ft
+ - 16 ft (recomanat)
+ - 33 ft
+ - 328 ft
+
+
+
+
+ - 50 m
+ - 100 m
+ - 200 m (recomanat)
+ - 500 m
+ - 1000 m
+ - 5000 m
+
+
+
+ - 164 ft
+ - 328 ft
+ - 656 ft (recomanat)
+ - 1640 ft
+ - 0.6 miles
+ - 3.1 miles
+
+
+
+
+ - poca precisió (adaptable)
+ - gran precisió (adaptable)
+ - el millor (recomanat)
+ - 2 s
+ - 3 s
+ - 4 s
+ - 5 s
+ - 10 s
+ - 20 s
+ - 30 s
+ - 1 min
+ - 2 min
+ - 5 min
+ - 10 min
+ - 15 min
+ - 30 min
+
+
+
+
+ - 10 m (senyal GPS excel·lent)
+ - 20 m
+ - 50 m
+ - 100 m
+ - 200 m (recomanat)
+ - 500 m
+ - 1000 m
+ - 2000 m
+ - 5000 m (senyal GPS pobre)
+
+
+
+ - 33 ft (senyal GPS excel·lent)
+ - 66 ft
+ - 165 ft
+ - 328 ft
+ - 656 ft (recomanat)
+ - 1640 ft
+ - 0.6 miles
+ - 1.2 miles
+ - 3.1 miles (senyal GPS pobre)
+
+
+
+
+ - Sense divisió
+ - 100 km
+ - 50 km
+ - 25 km
+ - 10 km
+ - 5 km
+ - 1 km
+ - 60 min
+ - 30 min
+ - 15 min
+ - 10 min
+ - 5 min
+ - 2 min
+ - 1 min
+
+
+
+ - No splitting
+ - 100 mi
+ - 50 mi
+ - 25 mi
+ - 10 mi
+ - 5 mi
+ - 1 mi
+ - 60 min
+ - 30 min
+ - 15 min
+ - 10 min
+ - 5 min
+ - 2 min
+ - 1 min
+
+
+
+
+ - Mai
+ - 5 min
+ - 10 min
+ - 15 min
+ - Always
+
+
+
+
+ - desconegut
+ - tipus barrejats
+ - altre
+
+ - córrer
+ - córrer al carrer
+ - pista d\'atletisme
+ - córrer en ruta
+ - a peu
+ - caminar de presa
+ - senderisme
+ - ruta de senderisme
+ - senderisme fora de ruta
+ - escalada
+
+ - ciclisme
+ - bici al carrer
+ - bici de muntanya
+ - ruta de bici
+
+ - patinatge
+ - patinatge en línia
+ - skate
+
+ - snow shoeing
+ - skiing
+ - snow boarding
+ - sled
+ - ice sailing
+
+ - pesca
+ - rem
+ - caiac
+ - rem
+ - llanxa motora
+ - ferry
+ - RC boat
+ - surf
+ - windsurf
+ - kitesurf
+ - esquí aquàtic
+ - wakeboard
+
+ - avió
+ - hidroavió
+ - avió comercial
+ - helicòpter
+ - globus aerostàtic
+ - dirigible
+ - avió RC
+ - helicòpter RC
+ - salt d\'esquí
+ - vol sense motor
+ - ala delta
+ - parapent
+
+ - riding
+ - horse back riding
+ - donkey back riding
+
+ - conducció d\'automòbil
+ - conducció de bus
+ - tren
+ - moto
+ - dirtbike
+ - ATV
+
+ - landsailing
+ - frisbee
+ - ultimate frisbee
+
+
+
+ - ATM
+ - banc
+ - bar
+ - barbeque
+ - edifici
+ - parada de bús
+ - cafeteria
+ - acampada
+ - càmping
+ - església
+ - cafeteria
+ - botiga de conveniència
+ - aigua potable
+ - caiguda de roques
+ - ferry
+ - llar de foc
+ - estació de bombers
+ - pesca
+ - benzinera
+ - camp de golf
+ - botiga de queviures
+ - perruqueria
+ - port
+ - ruta de senderisme
+ - hotel
+ - casa
+ - informació
+ - intersecció
+ - bústia
+ - mercat
+ - punt de trobada
+ - opera
+ - parking
+ - oficina de correus
+ - sot
+ - comissaria dels mossos
+ - encreuament ferroviari
+ - restaurant
+ - compres
+ - vista
+ - magatzem
+ - piscina
+ - telèfon
+ - teatre
+ - serveis
+ - informació turística
+ - túnel
+ - arbre
+ - cascada
+ - font d\'aigua
+ - punt de referència
+
+
+
+ - Cap
+ - Zephyr Bluetooth
+
+
+
diff --git a/MyTracks/res/values-ca/strings.xml b/MyTracks/res/values-ca/strings.xml
new file mode 100644
index 000000000..1a001c3e2
--- /dev/null
+++ b/MyTracks/res/values-ca/strings.xml
@@ -0,0 +1,449 @@
+
+
+
+
+ Enregistra la ruta
+ Atura l\'enregistrament
+ Mode de satèl·lit
+ Mode de mapa
+ La meva ubicació
+ Rutes
+ Marcadors
+ Elimina totes les rutes
+ Paràmetres
+ Elevació
+ Seleccioneu la ruta que es visualitzarà
+ Ruta actual
+ Darrer segment
+ Estat del sensor
+ Estadístiques agregades
+
+
+ No s\'ha trobat cap gestor d\'ubicacions en aquest dispositiu.
+ No s\'ha trobat cap proveïdor d\'ubicació GPS en aquest dispositiu.
+ S\'ha produït un error quan s\'enviava la ruta a Google My Map. Proveu més tard.
+ S\'ha prdouït un error quan s\'enviava la ruta a Google Docs. Proveu més tard.
+ No es pot iniciar l\'enregistrament. Proveu de nou.
+ No es pot aturar l\'enregistrament. Proveu de nou.
+ No es pot llegir des del fitxer.
+ El fitxer no conté un format GPX vàlid.
+ S\'ha produït un error. Proveu de nou.
+ No existeix la ruta.
+ Aquest fitxer és massa gran (ha d\'ésser inferior a 500KB. S\'està cancel·lant.
+ No es pot inserir un marcador. No hi ha cap ubicació fixa disponible.
+
+
+ S\'està esperant per tenir una posició GPS fixa. Assegureu-vos que el cel és visible.
+ Ara s\'està enregistrant una ruta nova.
+ S\'ha aturat l\'enregistrament de la ruta.
+ S\'ha creat un Google My Map nou a maps.google.com.
+ S\'ha enviat la ruta a maps.google.com.
+ S\'ha enviat la ruta a un full de càlcul a docs.google.com.
+ S\'ha enviat la ruta a docs.google.com.
+ Poden passar uns minuts abans que les rutes noves apareguin.
+ Piqueu aquí per anar als paràmetres de seguretat i ubicació i activeu \'habilita els satèl·lits GPS\'. Premeu el botó d\'anar enrere per tornar.
+ Nota: Es mostra una ubicació determinada a partir de les xarxes sense fils i antenes telefòniques.
+ No es pot determinar la ubicació. Habiliteu més fonts d\'ubicació (vegeu els paràmetres de seguretat i ubicació) i assegureu-vos que el cel és visible. Proveu de nou més tard.
+ S\'ha inserit un marcader de punt de ruta.
+ S\'ha inserit un marcador d\'estadístiques.
+
+
+ Espereu...
+ S\'està enviant la ruta a Google.
+ S\'està llegint la ruta...
+ S\'està preparant la ruta...
+ S\'està to Google Maps...
+ S\'està autenticant a Google Docs...
+ S\'està enviant la ruta a Google Docs...
+ S\'està enviant a Google Maps...
+ S\'està creant un My Map nou...
+ S\'està imporant una ruta GPS. Això pot trigar una estona.
+ S\'està escrivint a la targeta SD. Això pot trigar una estona.
+ S\'estan actualitzant les estadístiques de la ruta...
+
+
+ Esteu segur?
+ Tots els marcadors i rutes s\'eliminaran d\'aquest telèfon.
+ La ruta i els seus marcadors s\'eliminaran de forma permanent d\'aquest telèfon.
+ El marcador s\'eliminarà de forma permanent d\'aquest telèfon.
+
+
+ Creat per My Tracks a l\'Android.
+ Creat per <a href=\'http://mytracks.appspot.com\'>My Tracks</a> a l\'Android.
+ Mapa nou
+
+
+ Punts
+ Enregistrat
+ Tipus d\'activitat
+ Tipus de marcador
+ (Part %d)
+
+
+ S\'està enregistrant la ruta...
+ Ruta %d
+
+
+ No
+ Sí
+ D\'acord
+ Error
+ Fet
+ Punt de referència
+
+
+ (Inici)
+ (Fi)
+
+
+ Mostra
+ Envia a Google My Maps
+ Envia a un Google My Map nou
+ Envia a Google Docs
+ Envia a Google...
+ Elimina del telèfon...
+ Edita els detalls
+ Escriu a la targeta SD...
+ Anomena i desa com un fitxer GPX
+ Anomena i desa com un fitxer KML
+ Anomena i desa com un fitxer CSV
+ Anomena i desa com un fitxer TCX
+ Envia a Google My Maps
+ Elimina totes les rutes
+
+ Exporta totes les rutes
+ Exporta les finalitzades
+ Seleccioneu una ruta. Mantingueu el dit per veure més opcions.
+ Totes les rutes:
+ Aquesta ruta
+ Comparteix amb amics...
+ Un enllaç a Google My Map
+ Un fitxer GPX
+ Un fitxer KML
+ Un fitxer CSV
+ Un fitxer TCX
+ Neteja el mapa
+
+
+ Elimina tots els marcadors
+ Aquest marcador
+ Elimina
+ Edita els detalls
+ Mostra al mapa
+ Insereix un punt de referència
+ Insereix estadístiques
+ Seleccioneu un marcador. Mantingueu el dit per veure més opcions.
+
+
+ Detalls de la ruta
+ Nom de la ruta
+ Descripció de la ruta
+ Tipus d\'activitat (p.e. senderisme, bicicleta, còrrer, escalada...)
+
+
+ Detalls del marcador
+ Nom del marcador
+ Descripció del marcador
+ Tipus de marcador (e.g. edifici, sot, vista...)
+
+
+ Paràmetres de My Tracks
+ Visualització
+ Enregistrament
+ Compartició
+
+ No es troba disponible a la vostra versió de l\'Android
+
+ Freqüència d\'avís
+ Temps mínin entre dos avisos de veu
+
+ Distància mínima entre punts
+ La distància més petita entre dos punts enregistrats de la vostra posició
+
+ Distància màxima entre punts
+ Si dos punts estan més lluny d\'això, es dividirà la ruta
+
+ Temps mínim entre punts
+ Interval de temps mínim entre dos enregistraments de la vostra posició
+
+ Precisió míima
+ S\'aturarà l\'enregistrament si la vostra posició no és així de precisa com a mínim
+
+ Fes servir unitats mètriques
+ Totes les distàncies es mostraran en unitats mètriques
+ Totes les distàncies es mostraran en unitats imperials
+
+ Fes el mapa públic
+ Els mapes pujats seran visibles per tothom a maps.google.com
+ Els mapes pujats no es llistaran públicament a maps.google.com
+
+ Mostra la velocitat
+ Es mostrarà la velocitat
+ Es mostrarà el ritme de pas
+
+ Comparteix només l\'URL
+ Només s\'enviarà l\'URL del mapa quan es comparteixi
+ També s\'inclouran els continguts de la ruta quan es comparteixi
+
+ Freqüència de divisió
+ Temps o distància màxima a partir de la qual s\'insertarà un marcador de divisió nou
+
+ Temps d\'espera per reprende la ruta
+ Temps màxim en minuts a partir del qual l\'anterior ruta enregistrada no es reprendrà en actualitzar el telèfon
+
+ Data i hora com a nom de la ruta
+ El nom per defecte de la ruta serà la data i hora en que s\'ha iniciat.
+ Els noms de les rutes seran números que s\'incrementaran per a cada nova ruta.
+
+ Ritme de pas
+
+ Suportat només en Android 2.0 i superior
+ Tipus de sensor
+ El tipus de sensor al qual es connecta.
+ Identificador del sensor
+ L\'identificador enviat als sensors.
+ L\'identificador ha de ser un valor sencer.
+ Sensor bluetooth
+ El sensor bluetooth al qual es connecta.
+ Pantalla d\'estadístiques modulars
+ La pantalla d\'estadístiques es divideix en mòduls diferents.
+ Mostra totes les estadístiques en una sola pantalla.
+
+ Còpia de seguretat (BETA)
+ Còpia de seguretat a la targeta SD
+ Fes la còpia ara
+ Escriu una còpia completa de totes les rutes i els paràmetres a la targeta SD
+ Restaura ara
+ Restaura totes les rutes i els paràmetres des de la targeta SD.
+ No es poden gestionar les còpies de seguretat mentre s\'enregistra una ruta.
+
+
+ La restauració d\'una còpia de seguretat des de la targeta SD sobreescriurà totes les rutes i paràmetres. Esteu segur?
+ Seleccioneu la còpia que es restaurarà
+ No s\'ha trobat cap còpia de seguretat.
+ S\'estan escrivint totes les rutes i els paràmetres a la targeta SD. Això pot trigar una estona...
+ S\'estan llegint totes les rutes i els paràmetres de la targeta SD. Això pot trigar una estona...
+
+
+ Satèl·lits GPS
+
+
+ Seleccioneu un mapa del vostre compte:
+ Crea un mapa nou...
+ Envia a Google My Maps
+ S\'estan carregant els mapes...
+ No s\'han pogut carregar els vostres mapes en aquest moment
+ Selecciona aquest mapa
+ Edita els detalls del mapa
+ Comparteix el mapa amb amics
+ Comparteix la ruta amb amics
+ Elimina el mapa del vostre compte
+ Títol del mapa:
+ Descripció del mapa:
+ Fes que aquest mapa i els seus continguts apareguen als resultats de cerca
+ No permetis que aquest mapa ni els seus continguts es mostrin als resultats de cerca, tot i que sí es podrà visualitzar per altres amb l\'adreça URL directa
+ Aquest mapa i els seus continguts es mostraran als resultats de cerca
+ Ni els mapes ni els seus continguts es mostraran als resultats de cerca, però podran visualitzar-se per altres a través d\'un enllaç directe.
+ Tanca
+ Edita
+ Cancel·la
+ Desa
+
+
+ M\'agradaria compartir un mapa amb tu
+ Crec que estaràs interessat en aquest mapa:
+
+ %s
+ M\'agradaria compartir una ruta amb tu
+ Crec que estaràs interessat en aquesta ruta.
+
+ Per verue aquesta ruta fes servir Google Earth o altre programari de mapes.
+
+
+ Públic
+ No llistat
+ Encara no teniu cap mapa.
+
+
+
+ Average Moving Speed
+ Average Moving Pace
+
+
+ Velocitat mitjana
+ Ritme de pas mitjà
+
+ Gràfic d\'elevació
+ Guany d\'elevació
+ Elevació
+ Latitud
+ Longitud
+
+
+ Elevació mínima
+ Grau mínim
+ Ritme de pas mínima
+
+
+ Elevació màxima
+ Grau màxim
+ Velocitat màxima
+
+ S\'està carregant la ruta...
+
+
+ Configuració del gràfic
+
+ Eix X
+ Per distància
+ Per temps
+
+
+ Eix Y
+
+
+
+ hora
+ hores
+ minut
+ minuts
+ segon
+ segons
+
+
+ kilòmetres
+ milles
+
+
+ kilòmetres per hora
+ per kilòmetre
+ milles per hora
+ per milla
+
+
+ Temps en moviment
+ Temps total
+ Temps
+ La targeta SD no està disponible
+ Velocitat
+ Heu d\'iniciar la marxa.
+ Estadístiques
+ Distància total
+ Distància
+ Energia
+ Cadència
+ Freqüència cardíaca
+ Freqüència cardíaca màxima
+ S\'està esperant...
+
+
+ Acord de llicencia d\'usuari final
+ Accepta
+ Rebutja
+
+
+ Quant a
+ Ajuda
+ Equip:
+ Versió:
+ Assistència
+ Assistència:
+
+
+ Envia a...
+ Envia ara
+ Crea un mapa nou
+ Seleccioneu un mapa existent
+ Envia les estadístiques de la ruta
+ Envia les estadístiques i els punts
+
+
+ No s\'ha trobat cap compte
+ No s\'ha trobat cap compte on pujar les rutes.
+ Trieu un compte
+
+
+ No s\'ha trobat cap dispositiu d\'emmagatzematge extern. Assegureu-vos que la targeta SD està inserida i que el telèfon no està connectat a un ordinador.
+ No es pot escriure a un fitxer.
+ No es pot llegir des del fitxer.
+ No es pot crear el directori a la targeta SD.
+ S\'ha finalitzat l\'escriptura a la targeta SD.
+ S\'ha finalitzat la lectura a la targeta SD.
+
+
+ Comprovació d\'actualitzacions
+ Actualitza ara
+ Continua sense actualitzar
+ La vostra versió de %1$s podria no funcionar correctament a partir d\'ara i no està suportada. Actualitzeu per continuar fent servir %1$s.
+ La vostra versió de %1$s podria no funcionar correctament a partir d\'ara. Heu d\'actualitzar-la ara o continuar fent-la servir pel vostre compte. Algunes funcionalitats com la sincronització podrien no funcionar fins que no actualitzeu.
+ Hi ha una nova versió disponible de %1$s. Podeu continuar fent servir la vostra versió sense cap problema, però no aconseguireu les darreres funcionalitats fins que no actualitzeu.
+
+
+ Benvingut
+ D\'acord
+ Quant a My Tracks
+
+
+ Sense distància My Tracks
+
+ My Tracks %1$s %2$.2f %3$s en %4$s at %5$s %6$s
+
+
+ Avís de les unitats de mesura
+ Les unitats són mètriques per defecte. Voleu canviar aquest paràmetre?
+
+
+ Rati d\'error: %1$d
+ Relació senyal/soroll: %1$d
+ Ec/lo: %1$.1f dB
+ Intensistat GSM: %1$d
+ Intensitat CDMA: %1$d dBm
+ Intensitat EVDO: %1$d dBm
+
+
+ Opcions del Bluetooth
+ Associació de dispositius
+ Obriu els paràmetres de bluetooth de l\'Android per associar un dispositiu
+ bluetoothSensorsEnabled
+ Opcions del sensor
+
+
+ Connectat a %s
+ Connexió del sensor bluetooth...
+ El sensor bluetooth no està connectat
+
+
+ Dades del sensor de temps
+ S\'ha habilitat el mesurador de potència
+ S\'ha habilitat el monitor de la freqüència cardíaca
+ Cap gestor de sensors
+ Habilitat
+ S\'està connectant
+ S\'ha connectat
+ S\'ha desconnectat
+ Cap servei de sensor
+ S\'està cercant
+ S\'està enviant
+
+
diff --git a/MyTracks/res/values-pl/strings.xml b/MyTracks/res/values-pl/strings.xml
index 2d597a9e2..017176bb3 100644
--- a/MyTracks/res/values-pl/strings.xml
+++ b/MyTracks/res/values-pl/strings.xml
@@ -361,6 +361,8 @@ limitations under the License.
Wersja:
Wsparcie
Wsparcie:
+
+ Bartłomiej Niechwiej
Wyślij do...
diff --git a/MyTracks/res/values/strings.xml b/MyTracks/res/values/strings.xml
index b837dcc82..c2d8886e9 100644
--- a/MyTracks/res/values/strings.xml
+++ b/MyTracks/res/values/strings.xml
@@ -388,6 +388,7 @@ limitations under the License.
mytracks@googlegroups.com
mytracks.appspot.com
Copyright 2009 Google Inc.
+ Bartlomiej Niechwiej
Dylan Casey
Leif Hendrik Wilden
Rodrigo Damazio Bovendorp
diff --git a/MyTracks/res/values/urls.xml b/MyTracks/res/values/urls.xml
new file mode 100644
index 000000000..14ab85638
--- /dev/null
+++ b/MyTracks/res/values/urls.xml
@@ -0,0 +1,21 @@
+
+
+
+
+ http://maps.google.com/mapfiles/ms/micons/blue-pushpin.png
+ http://maps.google.com/mapfiles/ms/micons/ylw-pushpin.png
+
\ No newline at end of file
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java b/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java
index 60ff3a840..57d0377b6 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java
@@ -25,7 +25,7 @@ import com.google.android.apps.mymaps.MyMapsConstants;
import com.google.android.apps.mymaps.MyMapsList;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
-import com.google.android.apps.mytracks.content.Waypoint;
+import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.io.AuthManager;
import com.google.android.apps.mytracks.io.AuthManagerFactory;
import com.google.android.apps.mytracks.io.GpxImporter;
@@ -63,6 +63,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.RemoteException;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -93,9 +94,6 @@ import org.xml.sax.SAXException;
public class MyTracks extends TabActivity implements OnTouchListener,
OnSharedPreferenceChangeListener, ProgressIndicator {
- private static final String WAYPOINT_ICON_URL =
- "http://maps.google.com/mapfiles/ms/micons/blue-pushpin.png";
-
/**
* Singleton instance
*/
@@ -432,7 +430,13 @@ public class MyTracks extends TabActivity implements OnTouchListener,
public boolean onTrackballEvent(MotionEvent event) {
if (isRecording()) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
- insertStatisticsMarker();
+ try {
+ insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS);
+ } catch (RemoteException e) {
+ Log.e(MyTracksConstants.TAG, "Cannot insert statistics marker.", e);
+ } catch (IllegalStateException e) {
+ Log.e(MyTracksConstants.TAG, "Cannot insert statistics marker.", e);
+ }
return true;
}
}
@@ -888,90 +892,25 @@ public class MyTracks extends TabActivity implements OnTouchListener,
/**
* Inserts a waypoint marker.
*
- * @return the id of the inserted statistics marker, or
- * -1 unable to find location
- * -2 track recording service is not running?
- * -3 remote exception when contacting track recording service
- * -4 inserting marker into provider failed
+ * @return Id of the inserted statistics marker.
+ * @throws RemoteException If the call on the service failed.
*/
- public long insertWaypointMarker() {
- Location location = getCurrentLocation();
- if (location == null) {
+ public long insertWaypoint(WaypointCreationRequest request) throws RemoteException {
+ if (trackRecordingService == null) {
+ throw new IllegalStateException("The recording service is not bound.");
+ }
+ try {
+ long waypointId = trackRecordingService.insertWaypoint(request);
+ if (waypointId >= 0) {
+ Toast.makeText(this, R.string.status_statistics_inserted,
+ Toast.LENGTH_LONG).show();
+ }
+ return waypointId;
+ } catch (RemoteException e) {
Toast.makeText(this, R.string.error_unable_to_insert_marker,
Toast.LENGTH_LONG).show();
- return -1;
+ throw e;
}
- if (trackRecordingService != null) {
- try {
- Waypoint wpt = new Waypoint();
- wpt.setName(getString(R.string.waypoint));
- wpt.setType(Waypoint.TYPE_WAYPOINT);
- wpt.setTrackId(recordingTrackId);
- wpt.setIcon(WAYPOINT_ICON_URL);
- wpt.setLocation(location);
- long waypointId = trackRecordingService.insertWaypointMarker(wpt);
- if (waypointId >= 0) {
- Toast.makeText(this, R.string.status_waypoint_inserted,
- Toast.LENGTH_LONG).show();
- return waypointId;
- } else {
- Toast.makeText(this, R.string.error_unable_to_insert_marker,
- Toast.LENGTH_LONG).show();
- Log.e(MyTracksConstants.TAG, "Cannot insert waypoint marker?");
- return -4;
- }
- // TODO: We catch Exception, because after eliminating the service process
- // all exceptions it may throw are no longer wrapped in a RemoteException.
- } catch (Exception e) {
- Toast.makeText(this, R.string.error_unable_to_insert_marker,
- Toast.LENGTH_LONG).show();
- Log.e(MyTracksConstants.TAG, "Cannot insert waypoint marker.", e);
- }
- return -3;
- }
- return -2;
- }
-
- /**
- * Inserts a statistics marker.
- *
- * @return the id of the inserted statistics marker, or
- * -1 unable to find location
- * -2 track recording service is not running?
- * -3 remote exception when contacting track recording service
- * -4 inserting marker into provider failed
- */
- public long insertStatisticsMarker() {
- Location location = getLastLocation();
- if (location == null) {
- Toast.makeText(this, R.string.error_unable_to_insert_marker,
- Toast.LENGTH_LONG).show();
- return -1;
- }
- if (trackRecordingService != null) {
- try {
- long waypointId =
- trackRecordingService.insertStatisticsMarker(location);
- if (waypointId >= 0) {
- Toast.makeText(this, R.string.status_statistics_inserted,
- Toast.LENGTH_LONG).show();
- return waypointId;
- } else {
- Toast.makeText(this, R.string.error_unable_to_insert_marker,
- Toast.LENGTH_LONG).show();
- Log.e(MyTracksConstants.TAG, "Cannot insert statistics marker?");
- return -4;
- }
- // TODO: We catch Exception, because after eliminating the service process
- // all exceptions it may throw are no longer wrapped in a RemoteException.
- } catch (Exception e) {
- Toast.makeText(this, R.string.error_unable_to_insert_marker,
- Toast.LENGTH_LONG).show();
- Log.e(MyTracksConstants.TAG, "Cannot insert statistics marker?", e);
- }
- return -3;
- }
- return -2;
}
/**
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracksWaypointDetails.java b/MyTracks/src/com/google/android/apps/mytracks/MyTracksWaypointDetails.java
index d159fb236..5e9f110b7 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracksWaypointDetails.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/MyTracksWaypointDetails.java
@@ -42,6 +42,8 @@ import android.widget.ImageView;
public class MyTracksWaypointDetails extends Activity
implements OnClickListener {
+ public static final String WAYPOINT_ID_EXTRA = "com.google.android.apps.mytracks.WAYPOINT_ID";
+
/**
* The id of the way point being edited (taken from bundle, "waypointid")
*/
@@ -78,7 +80,7 @@ public class MyTracksWaypointDetails extends Activity
}
// Required extra when launching this intent:
- waypointId = getIntent().getLongExtra("waypointid", -1);
+ waypointId = getIntent().getLongExtra(WAYPOINT_ID_EXTRA, -1);
if (waypointId < 0) {
Log.d(MyTracksConstants.TAG,
"MyTracksWaypointsDetails intent was launched w/o waypoint id.");
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracksWaypointsList.java b/MyTracks/src/com/google/android/apps/mytracks/MyTracksWaypointsList.java
index 594c9fb98..f3c151169 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracksWaypointsList.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/MyTracksWaypointsList.java
@@ -17,6 +17,7 @@ package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Waypoint;
+import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.content.WaypointsColumns;
import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.maps.mytracks.R;
@@ -28,6 +29,8 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuItem;
@@ -87,7 +90,7 @@ public class MyTracksWaypointsList extends ListActivity
protected void onListItemClick(ListView l, View v, int position, long id) {
Intent result = new Intent();
result.putExtra("trackid", trackId);
- result.putExtra("waypointid", id);
+ result.putExtra(MyTracksWaypointDetails.WAYPOINT_ID_EXTRA, id);
setResult(MyTracksConstants.EDIT_WAYPOINT, result);
finish();
}
@@ -103,7 +106,7 @@ public class MyTracksWaypointsList extends ListActivity
case MyTracksConstants.MENU_EDIT: {
Intent intent = new Intent(this, MyTracksWaypointDetails.class);
intent.putExtra("trackid", trackId);
- intent.putExtra("waypointid", waypointId);
+ intent.putExtra(MyTracksWaypointDetails.WAYPOINT_ID_EXTRA, waypointId);
startActivity(intent);
return true;
}
@@ -165,27 +168,34 @@ public class MyTracksWaypointsList extends ListActivity
@Override
public void onClick(View v) {
+ WaypointCreationRequest request;
switch (v.getId()) {
- case R.id.waypointslist_btn_insert_waypoint: {
- long id = MyTracks.getInstance().insertWaypointMarker();
- if (id >= 0) {
- Intent intent = new Intent(this, MyTracksWaypointDetails.class);
- intent.putExtra("waypointid", id);
- startActivity(intent);
- }
+ case R.id.waypointslist_btn_insert_waypoint:
+ request = WaypointCreationRequest.DEFAULT_MARKER;
break;
- }
- case R.id.waypointslist_btn_insert_statistics: {
- long id = MyTracks.getInstance().insertStatisticsMarker();
- if (id >= 0) {
- Intent intent = new Intent(this, MyTracksWaypointDetails.class);
- intent.putExtra("waypointid", id);
- startActivity(intent);
- }
+ case R.id.waypointslist_btn_insert_statistics:
+ request = WaypointCreationRequest.DEFAULT_STATISTICS;
break;
- }
-
+ default:
+ return;
}
+ long id;
+ try {
+ id = MyTracks.getInstance().insertWaypoint(request);
+ } catch (RemoteException e) {
+ Log.e(MyTracksConstants.TAG, "Cannot insert marker.", e);
+ return;
+ } catch (IllegalStateException e) {
+ Log.e(MyTracksConstants.TAG, "Cannot insert marker.", e);
+ return;
+ }
+ if (id < 0) {
+ Log.e(MyTracksConstants.TAG, "Failed to insert marker.");
+ return;
+ }
+ Intent intent = new Intent(this, MyTracksWaypointDetails.class);
+ intent.putExtra(MyTracksWaypointDetails.WAYPOINT_ID_EXTRA, id);
+ startActivity(intent);
}
private void setListAdapter() {
diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/SplitManager.java b/MyTracks/src/com/google/android/apps/mytracks/services/SplitManager.java
index e8a92bfc7..f63e87531 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/services/SplitManager.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/services/SplitManager.java
@@ -16,6 +16,7 @@
package com.google.android.apps.mytracks.services;
import com.google.android.apps.mytracks.MyTracksConstants;
+import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.util.UnitConversions;
import android.util.Log;
@@ -111,7 +112,7 @@ public class SplitManager {
}
if (distance > this.nextSplitDistance) {
- service.insertStatisticsMarker(service.getLastLocation());
+ service.insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS);
calculateNextSplit();
}
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/TimeSplitTask.java b/MyTracks/src/com/google/android/apps/mytracks/services/TimeSplitTask.java
index 9535ad4b0..333ce6ae4 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/services/TimeSplitTask.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/services/TimeSplitTask.java
@@ -16,6 +16,9 @@
package com.google.android.apps.mytracks.services;
+import com.google.android.apps.mytracks.content.WaypointCreationRequest;
+
+
/**
* A simple task to insert statistics markers every n minutes.
* @author Sandor Dornbush
@@ -24,7 +27,7 @@ public class TimeSplitTask implements PeriodicTask {
@Override
public void run(TrackRecordingService service) {
- service.insertStatisticsMarker(service.getLastLocation());
+ service.insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS);
}
@Override
diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java b/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java
index b3610bd44..55147ebd3 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java
@@ -26,6 +26,7 @@ import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.content.Waypoint;
+import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.content.WaypointsColumns;
import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
import com.google.android.apps.mytracks.services.sensors.SensorManager;
@@ -70,9 +71,6 @@ import java.util.TimerTask;
*/
public class TrackRecordingService extends Service implements LocationListener {
- private static final String STATISTICS_ICON_URL =
- "http://maps.google.com/mapfiles/ms/micons/ylw-pushpin.png";
-
static final int MAX_AUTO_RESUME_TRACK_RETRY_ATTEMPTS = 3;
private NotificationManager notificationManager;
@@ -429,7 +427,7 @@ public class TrackRecordingService extends Service implements LocationListener {
lastValidLocation = null;
Waypoint waypoint = providerUtils.getFirstWaypoint(recordingTrackId);
- if (waypoint != null) {
+ if (waypoint != null && waypoint.getStatistics() != null) {
currentWaypointId = waypoint.getId();
waypointStatsBuilder = new TripStatisticsBuilder(
waypoint.getStatistics());
@@ -860,50 +858,62 @@ public class TrackRecordingService extends Service implements LocationListener {
return isRecording;
}
- public long insertWaypointMarker(Waypoint waypoint) {
+ public long insertWaypoint(WaypointCreationRequest request) {
if (!isRecording()) {
throw new IllegalStateException(
"Unable to insert waypoint marker while not recording!");
}
-
- if (waypoint.getLocation() == null) {
- if (lastValidLocation == null) {
- Log.w(MyTracksConstants.TAG, "Cannot insert waypoint with no location");
- return -1;
- }
-
- waypoint.setLocation(lastValidLocation);
+ if (request == null) {
+ request = WaypointCreationRequest.DEFAULT_MARKER;
}
-
- if (waypoint.getTrackId() < 0) {
- waypoint.setTrackId(recordingTrackId);
+ Waypoint wpt = new Waypoint();
+ switch (request.getType()) {
+ case MARKER:
+ buildMarker(wpt, request);
+ break;
+ case STATISTICS:
+ buildStatisticsMarker(wpt);
+ break;
}
-
- waypoint.setLength(length);
- waypoint.setDuration(waypoint.getLocation().getTime()
- - statsBuilder.getStatistics().getStartTime());
- Uri uri = providerUtils.insertWaypoint(waypoint);
+ wpt.setTrackId(recordingTrackId);
+ wpt.setLength(length);
+ if (lastValidLocation != null) {
+ // A null location is ok, and expected on track start.
+ wpt.setLocation(lastLocation);
+ wpt.setDuration(lastLocation.getTime()
+ - statsBuilder.getStatistics().getStartTime());
+ }
+ Uri uri = providerUtils.insertWaypoint(wpt);
return Long.parseLong(uri.getLastPathSegment());
}
+ private void buildMarker(Waypoint wpt, WaypointCreationRequest request) {
+ wpt.setType(Waypoint.TYPE_WAYPOINT);
+ if (request.getIconUrl() == null) {
+ wpt.setIcon(getString(R.string.waypoint_icon_url));
+ } else {
+ wpt.setIcon(request.getIconUrl());
+ }
+ if (request.getName() == null) {
+ wpt.setName(getString(R.string.waypoint));
+ } else {
+ wpt.setName(request.getName());
+ }
+ if (request.getDescription() != null) {
+ wpt.setDescription(request.getDescription());
+ }
+ }
+
/**
- * Inserts a statistics marker. A statistics marker holds the stats for the
- * last segment up to this marker.
+ * Build a statistics marker.
+ * A statistics marker holds the stats for the* last segment up to this marker.
*
- * @param location the location where to insert
+ * @param Waypoint The waypoint which will be populated with stats data.
* @return the unique id of the inserted marker
*/
- public long insertStatisticsMarker(Location location) {
- if (!isRecording()) {
- throw new IllegalStateException(
- "Unable to insert statistics marker while not recording!");
- }
-
+ private void buildStatisticsMarker(Waypoint waypoint) {
StringUtils utils = new StringUtils(TrackRecordingService.this);
- // Create a new waypoint to save
- Waypoint waypoint = new Waypoint();
-
// Set stop and total time in the stats data
final long time = System.currentTimeMillis();
waypointStatsBuilder.pauseAt(time);
@@ -913,24 +923,18 @@ public class TrackRecordingService extends Service implements LocationListener {
waypoint.setDuration(time - statsBuilder.getStatistics().getStartTime());
// Set the rest of the waypoint data
- waypoint.setTrackId(recordingTrackId);
waypoint.setType(Waypoint.TYPE_STATISTICS);
- waypoint.setName(TrackRecordingService.this.getString(R.string.statistics));
+ waypoint.setName(getString(R.string.statistics));
waypoint.setStatistics(waypointStatsBuilder.getStatistics());
waypoint.setDescription(utils.generateWaypointDescription(waypoint));
- waypoint.setLocation(location);
- waypoint.setIcon(STATISTICS_ICON_URL);
- waypoint.setLength(length);
+ waypoint.setIcon(getString(R.string.stats_icon_url));
waypoint.setStartId(providerUtils.getLastLocationId(recordingTrackId));
- Uri uri = providerUtils.insertWaypoint(waypoint);
- // Create a new stats keeper for the next marker
+ // Create a new stats keeper for the next marker.
waypointStatsBuilder = new TripStatisticsBuilder(time);
- updateCurrentWaypoint();
- return Long.parseLong(uri.getLastPathSegment());
}
-
+
private ServiceBinder binder = new ServiceBinder(this);
/**
@@ -961,79 +965,54 @@ public class TrackRecordingService extends Service implements LocationListener {
@Override
public boolean isRecording() {
+ checkService();
+ return service.isRecording();
+ }
+
+ private void checkService() {
if (service == null) {
throw new IllegalStateException("The service has been already detached!");
}
- return service.isRecording();
}
@Override
public long getRecordingTrackId() {
- if (service == null) {
- throw new IllegalStateException("The service has been already detached!");
- }
+ checkService();
return service.recordingTrackId;
}
@Override
public boolean hasRecorded() {
- if (service == null) {
- throw new IllegalStateException("The service has been already detached!");
- }
+ checkService();
return service.providerUtils.getLastTrackId() >= 0;
}
@Override
public long startNewTrack() {
- if (service == null) {
- throw new IllegalStateException("The service has been already detached!");
- }
+ checkService();
return service.startNewTrack();
}
/**
- * Insert the given waypoint marker. Users can insert waypoint markers
- * to tag locations with a name, description, category etc.
+ * Inserts a waypoint marker in the track being recorded.
*
- * @param waypoint a waypoint
- * @return the unique id of the inserted marker
+ * @param request Details of the waypoint to insert
+ * @return the unique ID of the inserted marker
*/
- @Override
- public long insertWaypointMarker(Waypoint waypoint) {
- if (service == null) {
- throw new IllegalStateException("The service has been already detached!");
- }
- return service.insertWaypointMarker(waypoint);
- }
-
- /**
- * Insert a statistics marker. A statistics marker holds the stats for
- * the last segment up to this marker.
- *
- * @param location the location where to insert
- * @return the unique id of the inserted marker
- */
- @Override
- public long insertStatisticsMarker(Location location) {
- if (service == null) {
- throw new IllegalStateException("The service has been already detached!");
- }
- return service.insertStatisticsMarker(location);
+ public long insertWaypoint(WaypointCreationRequest request) {
+ checkService();
+ return service.insertWaypoint(request);
}
@Override
public void endCurrentTrack() {
- if (service == null) {
- throw new IllegalStateException("The service has been already detached!");
- }
+ checkService();
service.endCurrentTrack();
}
@Override
public void deleteAllTracks() {
- if (service == null) {
- throw new IllegalStateException("The service has been already detached!");
- }
+ checkService();
if (isRecording()) {
throw new IllegalStateException("Cannot delete all tracks while recording!");
}
@@ -1042,14 +1021,13 @@ public class TrackRecordingService extends Service implements LocationListener {
@Override
public void recordLocation(Location loc) {
- if (service == null) {
- throw new IllegalStateException("The service has been already detached!");
- }
+ checkService();
service.onLocationChanged(loc);
}
@Override
public byte[] getSensorData() {
+ checkService();
if (service.sensorManager == null) {
Log.d(MyTracksConstants.TAG, "No sensor manager for data.");
return null;
@@ -1063,6 +1041,7 @@ public class TrackRecordingService extends Service implements LocationListener {
@Override
public int getSensorState() {
+ checkService();
if (service.sensorManager == null) {
Log.d(MyTracksConstants.TAG, "No sensor manager for data.");
return Sensor.SensorState.NONE.getNumber();
@@ -1095,7 +1074,7 @@ public class TrackRecordingService extends Service implements LocationListener {
providerUtils.updateTrack(track);
statsBuilder = new TripStatisticsBuilder(startTime);
waypointStatsBuilder = new TripStatisticsBuilder(startTime);
- currentWaypointId = insertStatisticsMarker(null);
+ currentWaypointId = insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS);
setUpAnnouncer();
length = 0;
showNotification();
diff --git a/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtils.java b/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtils.java
index 56c70db13..2dd891ac2 100644
--- a/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtils.java
+++ b/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtils.java
@@ -21,6 +21,7 @@ import android.database.Cursor;
import android.location.Location;
import android.net.Uri;
+import java.util.Iterator;
import java.util.List;
/**
@@ -309,6 +310,87 @@ public interface MyTracksProviderUtils {
* @return a new waypoint object
*/
Waypoint createWaypoint(Cursor cursor);
+
+ /**
+ * A lightweight wrapper around the original {@link Cursor} with a method to clean up.
+ */
+ interface LocationIterator extends Iterator {
+ /**
+ * Returns ID of the most recently retrieved track point through a call to {@link #next()}.
+ *
+ * @return the ID of the most recent track point ID.
+ */
+ long getLocationId();
+
+ /**
+ * Should be called in case the underlying iterator hasn't reached the last record.
+ */
+ void close();
+ }
+
+ /**
+ * A factory for creating new {@class Location}s.
+ */
+ interface LocationFactory {
+ /**
+ * Creates a new {@link Location} object to be populated from the underlying database record.
+ * It's up to the implementing class to decide whether to create a new instance or reuse
+ * existing to optimize for speed.
+ *
+ * @return a {@link Location} to be populated from the database.
+ */
+ Location createLocation();
+ }
+
+ /**
+ * The default {@class Location}s factory, which creates a new location of 'gps' type.
+ */
+ LocationFactory DEFAULT_LOCATION_FACTORY = new LocationFactory() {
+ @Override
+ public Location createLocation() {
+ return new Location("gps");
+ }
+ };
+
+ /**
+ * Creates a new read-only iterator over all track points for the given track. It provides
+ * a lightweight way of iterating over long tracks without failing due to the underlying cursor
+ * limitations. Since it's a read-only iterator, {@link Iterator#remove()} always throws
+ * {@class UnsupportedOperationException}.
+ *
+ * Each call to {@link LocationIterator#next()} may advance to the next DB record, and if so,
+ * the iterator calls {@link LocationFactory#createLocation()} and populates it with information
+ * retrieved from the record.
+ *
+ * When done with iteration, you must call {@link LocationIterator#close()} to make sure that all
+ * resources are properly deallocated.
+ *
+ * Example use:
+ *
+ * ...
+ * LocationIterator it = providerUtils.getLocationIterator(
+ * 1, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
+ * try {
+ * for (Location loc : it) {
+ * ... // Do something useful with the location.
+ * }
+ * } finally {
+ * it.close();
+ * }
+ * ...
+ *
+ *
+ * @param trackId the ID of a track to retrieve locations for.
+ * @param startTrackPointId the ID of the first track point to load, or -1 to start from
+ * the first point.
+ * @param descending if true the results will be returned in descending ID
+ * order (latest location first).
+ * @param locationFactory the factory for creating new locations.
+ *
+ * @return the read-only iterator over the given track's points.
+ */
+ LocationIterator getLocationIterator(long trackId, long startTrackPointId, boolean descending,
+ LocationFactory locationFactory);
/**
* A factory which can produce instances of {@link MyTracksProviderUtils},
diff --git a/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImpl.java b/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImpl.java
index d47442af2..4dfaa11fb 100644
--- a/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImpl.java
+++ b/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImpl.java
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.content;
-import static com.google.android.apps.mytracks.lib.MyTracksLibConstants.*;
+import static com.google.android.apps.mytracks.lib.MyTracksLibConstants.TAG;
import com.google.android.apps.mytracks.content.Sensor;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.protobuf.InvalidProtocolBufferException;
@@ -29,6 +29,7 @@ import android.util.Log;
import java.util.ArrayList;
import java.util.List;
+import java.util.NoSuchElementException;
/**
* Helper class providing easy access to locations and tracks in the
@@ -39,6 +40,8 @@ import java.util.List;
public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
private final ContentResolver contentResolver;
+
+ private int defaultCursorBatchSize = 2000;
public MyTracksProviderUtilsImpl(ContentResolver contentResolver) {
this.contentResolver = contentResolver;
@@ -124,7 +127,6 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
private static ContentValues createContentValues(Waypoint waypoint) {
ContentValues values = new ContentValues();
- TripStatistics stats = waypoint.getStatistics();
// Values id < 0 indicate no id is available:
if (waypoint.getId() >= 0) {
@@ -138,21 +140,24 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
values.put(WaypointsColumns.TYPE, waypoint.getType());
values.put(WaypointsColumns.LENGTH, waypoint.getLength());
values.put(WaypointsColumns.DURATION, waypoint.getDuration());
- values.put(WaypointsColumns.STARTTIME, stats.getStartTime());
values.put(WaypointsColumns.STARTID, waypoint.getStartId());
values.put(WaypointsColumns.STOPID, waypoint.getStopId());
- values.put(WaypointsColumns.TOTALDISTANCE, stats.getTotalDistance());
- values.put(WaypointsColumns.TOTALTIME, stats.getTotalTime());
- values.put(WaypointsColumns.MOVINGTIME, stats.getMovingTime());
- values.put(WaypointsColumns.AVGSPEED, stats.getAverageSpeed());
- values.put(WaypointsColumns.AVGMOVINGSPEED, stats.getAverageMovingSpeed());
- values.put(WaypointsColumns.MAXSPEED, stats.getMaxSpeed());
- values.put(WaypointsColumns.MINELEVATION, stats.getMinElevation());
- values.put(WaypointsColumns.MAXELEVATION, stats.getMaxElevation());
- values.put(WaypointsColumns.ELEVATIONGAIN, stats.getTotalElevationGain());
- values.put(WaypointsColumns.MINGRADE, stats.getMinGrade());
- values.put(WaypointsColumns.MAXGRADE, stats.getMaxGrade());
+ TripStatistics stats = waypoint.getStatistics();
+ if (stats != null) {
+ values.put(WaypointsColumns.TOTALDISTANCE, stats.getTotalDistance());
+ values.put(WaypointsColumns.TOTALTIME, stats.getTotalTime());
+ values.put(WaypointsColumns.MOVINGTIME, stats.getMovingTime());
+ values.put(WaypointsColumns.AVGSPEED, stats.getAverageSpeed());
+ values.put(WaypointsColumns.AVGMOVINGSPEED, stats.getAverageMovingSpeed());
+ values.put(WaypointsColumns.MAXSPEED, stats.getMaxSpeed());
+ values.put(WaypointsColumns.MINELEVATION, stats.getMinElevation());
+ values.put(WaypointsColumns.MAXELEVATION, stats.getMaxElevation());
+ values.put(WaypointsColumns.ELEVATIONGAIN, stats.getTotalElevationGain());
+ values.put(WaypointsColumns.MINGRADE, stats.getMinGrade());
+ values.put(WaypointsColumns.MAXGRADE, stats.getMaxGrade());
+ values.put(WaypointsColumns.STARTTIME, stats.getStartTime());
+ }
Location location = waypoint.getLocation();
if (location != null) {
@@ -184,55 +189,78 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
fillLocation(cursor, location);
return location;
}
+
+ /**
+ * A cache of track column indices.
+ */
+ private static class CachedTrackColumnIndices {
+ public final int idxId;
+ public final int idxLatitude;
+ public final int idxLongitude;
+ public final int idxAltitude;
+ public final int idxTime;
+ public final int idxBearing;
+ public final int idxAccuracy;
+ public final int idxSpeed;
+ public final int idxSensor;
- @Override
- public void fillLocation(Cursor cursor, Location location) {
+ public CachedTrackColumnIndices(Cursor cursor) {
+ idxId = cursor.getColumnIndex(TrackPointsColumns._ID);
+ idxLatitude = cursor.getColumnIndexOrThrow(TrackPointsColumns.LATITUDE);
+ idxLongitude = cursor.getColumnIndexOrThrow(TrackPointsColumns.LONGITUDE);
+ idxAltitude = cursor.getColumnIndexOrThrow(TrackPointsColumns.ALTITUDE);
+ idxTime = cursor.getColumnIndexOrThrow(TrackPointsColumns.TIME);
+ idxBearing = cursor.getColumnIndexOrThrow(TrackPointsColumns.BEARING);
+ idxAccuracy = cursor.getColumnIndexOrThrow(TrackPointsColumns.ACCURACY);
+ idxSpeed = cursor.getColumnIndexOrThrow(TrackPointsColumns.SPEED);
+ idxSensor = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR);
+ }
+ }
+
+ private void fillLocation(Cursor cursor, CachedTrackColumnIndices columnIndices,
+ Location location) {
location.reset();
-
- int idxLatitude = cursor.getColumnIndexOrThrow(TrackPointsColumns.LATITUDE);
- int idxLongitude =
- cursor.getColumnIndexOrThrow(TrackPointsColumns.LONGITUDE);
- int idxAltitude = cursor.getColumnIndexOrThrow(TrackPointsColumns.ALTITUDE);
- int idxTime = cursor.getColumnIndexOrThrow(TrackPointsColumns.TIME);
- int idxBearing = cursor.getColumnIndexOrThrow(TrackPointsColumns.BEARING);
- int idxAccuracy = cursor.getColumnIndexOrThrow(TrackPointsColumns.ACCURACY);
- int idxSpeed = cursor.getColumnIndexOrThrow(TrackPointsColumns.SPEED);
- int idxSensor = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR);
-
- if (!cursor.isNull(idxLatitude)) {
- location.setLatitude(1. * cursor.getInt(idxLatitude) / 1E6);
+
+ if (!cursor.isNull(columnIndices.idxLatitude)) {
+ location.setLatitude(1. * cursor.getInt(columnIndices.idxLatitude) / 1E6);
}
- if (!cursor.isNull(idxLongitude)) {
- location.setLongitude(1. * cursor.getInt(idxLongitude) / 1E6);
+ if (!cursor.isNull(columnIndices.idxLongitude)) {
+ location.setLongitude(1. * cursor.getInt(columnIndices.idxLongitude) / 1E6);
}
- if (!cursor.isNull(idxAltitude)) {
- location.setAltitude(cursor.getFloat(idxAltitude));
+ if (!cursor.isNull(columnIndices.idxAltitude)) {
+ location.setAltitude(cursor.getFloat(columnIndices.idxAltitude));
}
- if (!cursor.isNull(idxTime)) {
- location.setTime(cursor.getLong(idxTime));
+ if (!cursor.isNull(columnIndices.idxTime)) {
+ location.setTime(cursor.getLong(columnIndices.idxTime));
}
- if (!cursor.isNull(idxBearing)) {
- location.setBearing(cursor.getFloat(idxBearing));
+ if (!cursor.isNull(columnIndices.idxBearing)) {
+ location.setBearing(cursor.getFloat(columnIndices.idxBearing));
}
- if (!cursor.isNull(idxSpeed)) {
- location.setSpeed(cursor.getFloat(idxSpeed));
+ if (!cursor.isNull(columnIndices.idxSpeed)) {
+ location.setSpeed(cursor.getFloat(columnIndices.idxSpeed));
}
- if (!cursor.isNull(idxAccuracy)) {
- location.setAccuracy(cursor.getFloat(idxAccuracy));
+ if (!cursor.isNull(columnIndices.idxAccuracy)) {
+ location.setAccuracy(cursor.getFloat(columnIndices.idxAccuracy));
}
if (location instanceof MyTracksLocation &&
- !cursor.isNull(idxSensor)) {
+ !cursor.isNull(columnIndices.idxSensor)) {
MyTracksLocation mtLocation = (MyTracksLocation) location;
// TODO get the right buffer.
Sensor.SensorDataSet sensorData;
try {
- sensorData = Sensor.SensorDataSet.parseFrom(cursor.getBlob(idxSensor));
+ sensorData = Sensor.SensorDataSet.parseFrom(cursor.getBlob(columnIndices.idxSensor));
mtLocation.setSensorData(sensorData);
} catch (InvalidProtocolBufferException e) {
Log.w(TAG, "Failed to parse sensor data.", e);
}
}
}
+
+ @Override
+ public void fillLocation(Cursor cursor, Location location) {
+ CachedTrackColumnIndices columnIndicies = new CachedTrackColumnIndices(cursor);
+ fillLocation(cursor, columnIndicies, location);
+ }
@Override
public Track createTrack(Cursor cursor) {
@@ -378,7 +406,6 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
int idxSpeed = cursor.getColumnIndexOrThrow(WaypointsColumns.SPEED);
Waypoint waypoint = new Waypoint();
- TripStatistics stats = waypoint.getStatistics();
if (!cursor.isNull(idxId)) {
waypoint.setId(cursor.getLong(idxId));
@@ -407,41 +434,57 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
if (!cursor.isNull(idxDuration)) {
waypoint.setDuration(cursor.getLong(idxDuration));
}
- if (!cursor.isNull(idxStartTime)) {
- stats.setStartTime(cursor.getLong(idxStartTime));
- }
if (!cursor.isNull(idxStartId)) {
waypoint.setStartId(cursor.getLong(idxStartId));
}
if (!cursor.isNull(idxStopId)) {
waypoint.setStopId(cursor.getLong(idxStopId));
}
+
+ TripStatistics stats = new TripStatistics();
+ boolean hasStats = false;
+ if (!cursor.isNull(idxStartTime)) {
+ stats.setStartTime(cursor.getLong(idxStartTime));
+ hasStats = true;
+ }
if (!cursor.isNull(idxTotalDistance)) {
stats.setTotalDistance(cursor.getFloat(idxTotalDistance));
+ hasStats = true;
}
if (!cursor.isNull(idxTotalTime)) {
stats.setTotalTime(cursor.getLong(idxTotalTime));
+ hasStats = true;
}
if (!cursor.isNull(idxMovingTime)) {
stats.setMovingTime(cursor.getLong(idxMovingTime));
+ hasStats = true;
}
if (!cursor.isNull(idxMaxSpeed)) {
stats.setMaxSpeed(cursor.getFloat(idxMaxSpeed));
+ hasStats = true;
}
if (!cursor.isNull(idxMinElevation)) {
stats.setMinElevation(cursor.getFloat(idxMinElevation));
+ hasStats = true;
}
if (!cursor.isNull(idxMaxElevation)) {
stats.setMaxElevation(cursor.getFloat(idxMaxElevation));
+ hasStats = true;
}
if (!cursor.isNull(idxElevationGain)) {
stats.setTotalElevationGain(cursor.getFloat(idxElevationGain));
+ hasStats = true;
}
if (!cursor.isNull(idxMinGrade)) {
stats.setMinGrade(cursor.getFloat(idxMinGrade));
+ hasStats = true;
}
if (!cursor.isNull(idxMaxGrade)) {
stats.setMaxGrade(cursor.getFloat(idxMaxGrade));
+ hasStats = true;
+ }
+ if (hasStats) {
+ waypoint.setStatistics(stats);
}
Location location = new Location("");
@@ -775,13 +818,12 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
public Cursor getLocationsCursor(long trackId, long minTrackPointId,
int maxLocations, boolean descending) {
String selection;
- if (minTrackPointId > 0) {
- selection = String.format("%s=%d AND %s>=%d",
- TrackPointsColumns.TRACKID, trackId,
- TrackPointsColumns._ID, minTrackPointId);
+ if (minTrackPointId >= 0) {
+ selection = String.format("%s=%d AND %s%s%d",
+ TrackPointsColumns.TRACKID, trackId, TrackPointsColumns._ID,
+ descending ? "<=" : ">=", minTrackPointId);
} else {
- selection = String.format("%s=%d",
- TrackPointsColumns.TRACKID, trackId);
+ selection = String.format("%s=%d", TrackPointsColumns.TRACKID, trackId);
}
String sortOrder = "_id " + (descending ? "DESC" : "ASC");
@@ -789,8 +831,7 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
sortOrder += " LIMIT " + maxLocations;
}
- return contentResolver.query(
- TrackPointsColumns.CONTENT_URI, null, selection, null, sortOrder);
+ return contentResolver.query(TrackPointsColumns.CONTENT_URI, null, selection, null, sortOrder);
}
@Override
@@ -938,4 +979,85 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
contentResolver.update(TracksColumns.CONTENT_URI,
createContentValues(track), "_id=" + track.getId(), null);
}
+
+ @Override
+ public LocationIterator getLocationIterator(final long trackId, final long startTrackPointId,
+ final boolean descending, final LocationFactory locationFactory) {
+ if (locationFactory == null) {
+ throw new IllegalArgumentException("Expecting non-null locationFactory");
+ }
+ return new LocationIterator() {
+ private long lastTrackPointId = startTrackPointId;
+ private Cursor cursor = getCursor(startTrackPointId);
+ private final CachedTrackColumnIndices columnIndices = cursor != null ?
+ new CachedTrackColumnIndices(cursor) : null;
+
+ private Cursor getCursor(long trackPointId) {
+ return getLocationsCursor(trackId, trackPointId, defaultCursorBatchSize, descending);
+ }
+
+ private boolean advanceCursorToNextBatch() {
+ long pointId = lastTrackPointId + (descending ? -1 : 1);
+ Log.d(TAG, "Advancing cursor point ID: " + pointId);
+ cursor.close();
+ cursor = getCursor(pointId);
+ return cursor != null;
+ }
+
+ @Override
+ public long getLocationId() {
+ return lastTrackPointId;
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (cursor == null) {
+ return false;
+ }
+ if (cursor.isAfterLast()) {
+ return false;
+ }
+ if (cursor.isLast()) {
+ // If the current batch size was less that max, we can safely return, otherwise
+ // we need to advance to the next batch.
+ return cursor.getCount() == defaultCursorBatchSize &&
+ advanceCursorToNextBatch() && !cursor.isAfterLast();
+ }
+
+ return true;
+ }
+
+ @Override
+ public Location next() {
+ if (cursor == null ||
+ !(cursor.moveToNext() || advanceCursorToNextBatch() || cursor.moveToNext())) {
+ throw new NoSuchElementException();
+ }
+
+ lastTrackPointId = cursor.getLong(columnIndices.idxId);
+ Location location = locationFactory.createLocation();
+ fillLocation(cursor, columnIndices, location);
+
+ return location;
+ }
+
+ @Override
+ public void close() {
+ if (cursor != null) {
+ cursor.close();
+ cursor = null;
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ // @VisibleForTesting
+ void setDefaultCursorBatchSize(int defaultCursorBatchSize) {
+ this.defaultCursorBatchSize = defaultCursorBatchSize;
+ }
}
diff --git a/MyTracksLib/src/com/google/android/apps/mytracks/content/Waypoint.java b/MyTracksLib/src/com/google/android/apps/mytracks/content/Waypoint.java
index a2649a501..3d020eee2 100644
--- a/MyTracksLib/src/com/google/android/apps/mytracks/content/Waypoint.java
+++ b/MyTracksLib/src/com/google/android/apps/mytracks/content/Waypoint.java
@@ -85,7 +85,7 @@ public final class Waypoint implements Parcelable {
/** Stop track point id */
private long stopId = -1;
- private TripStatistics stats = new TripStatistics();
+ private TripStatistics stats;
/** The length of the track, without smoothing. */
private double length;
diff --git a/MyTracksLib/src/com/google/android/apps/mytracks/content/WaypointCreationRequest.aidl b/MyTracksLib/src/com/google/android/apps/mytracks/content/WaypointCreationRequest.aidl
new file mode 100644
index 000000000..c0d008f36
--- /dev/null
+++ b/MyTracksLib/src/com/google/android/apps/mytracks/content/WaypointCreationRequest.aidl
@@ -0,0 +1,2 @@
+package com.google.android.apps.mytracks.content;
+parcelable WaypointCreationRequest;
\ No newline at end of file
diff --git a/MyTracksLib/src/com/google/android/apps/mytracks/content/WaypointCreationRequest.java b/MyTracksLib/src/com/google/android/apps/mytracks/content/WaypointCreationRequest.java
new file mode 100644
index 000000000..e1b8463d9
--- /dev/null
+++ b/MyTracksLib/src/com/google/android/apps/mytracks/content/WaypointCreationRequest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2010 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.content;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A request for the service to create a waypoint at the current location.
+ *
+ * @author Sandor Dornbush
+ */
+public class WaypointCreationRequest implements Parcelable {
+
+ public static enum WaypointType {
+ MARKER,
+ STATISTICS;
+ }
+
+ private WaypointType type;
+ private String name;
+ private String description;
+ private String iconUrl;
+
+ public final static WaypointCreationRequest DEFAULT_MARKER =
+ new WaypointCreationRequest(WaypointType.MARKER);
+ public final static WaypointCreationRequest DEFAULT_STATISTICS =
+ new WaypointCreationRequest(WaypointType.STATISTICS);
+
+ private WaypointCreationRequest(WaypointType type) {
+ this.type = type;
+ }
+
+ public WaypointCreationRequest(WaypointType type, String name,
+ String description, String iconUrl) {
+ this.type = type;
+ this.name = name;
+ this.description = description;
+ this.iconUrl = iconUrl;
+ }
+
+ public static class Creator implements Parcelable.Creator {
+
+ @Override
+ public WaypointCreationRequest createFromParcel(Parcel source) {
+ int i = source.readInt();
+ if (i > WaypointType.values().length) {
+ throw new IllegalArgumentException("Could not find waypoint type: " + i);
+ }
+ WaypointCreationRequest request = new WaypointCreationRequest(WaypointType.values()[i]);
+ request.description = source.readString();
+ request.iconUrl = source.readString();
+ request.name = source.readString();
+ return request;
+ }
+
+ public WaypointCreationRequest[] newArray(int size) {
+ return new WaypointCreationRequest[size];
+ }
+ }
+
+ public static final Creator CREATOR = new Creator();
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int arg1) {
+ parcel.writeInt(type.ordinal());
+ parcel.writeString(description);
+ parcel.writeString(iconUrl);
+ parcel.writeString(name);
+ }
+
+ public WaypointType getType() {
+ return type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getIconUrl() {
+ return iconUrl;
+ }
+}
\ No newline at end of file
diff --git a/MyTracksLib/src/com/google/android/apps/mytracks/services/ITrackRecordingService.aidl b/MyTracksLib/src/com/google/android/apps/mytracks/services/ITrackRecordingService.aidl
index 39484aef0..b4ffcec0e 100644
--- a/MyTracksLib/src/com/google/android/apps/mytracks/services/ITrackRecordingService.aidl
+++ b/MyTracksLib/src/com/google/android/apps/mytracks/services/ITrackRecordingService.aidl
@@ -15,7 +15,7 @@
*/
package com.google.android.apps.mytracks.services;
-import com.google.android.apps.mytracks.content.Waypoint;
+import com.google.android.apps.mytracks.content.WaypointCreationRequest;
/**
* MyTracks service.
@@ -45,18 +45,10 @@ interface ITrackRecordingService {
/**
* Inserts a waypoint marker in the track being recorded.
*
- * @param waypoint the waypoint to insert
+ * @param request Details for the waypoint to be inserted.
* @return the unique ID of the inserted marker
*/
- long insertWaypointMarker(in Waypoint waypoint);
-
- /**
- * Inserts a statistics marker in the track being recorded.
- *
- * @param location the location at which to insert the marker
- * @return the unique ID of the inserted marker
- */
- long insertStatisticsMarker(in Location location);
+ long insertWaypoint(in WaypointCreationRequest request);
/**
* Inserts a location in the track being recorded.
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImplTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImplTest.java
new file mode 100644
index 000000000..9107221a9
--- /dev/null
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImplTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2010 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.content;
+
+import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationFactory;
+import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
+import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext;
+
+import android.content.Context;
+import android.location.Location;
+import android.test.AndroidTestCase;
+import android.test.RenamingDelegatingContext;
+import android.test.mock.MockContentResolver;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A unit test for {@link MyTracksProviderUtilsImpl}.
+ *
+ * @author Bartlomiej Niechwiej
+ */
+public class MyTracksProviderUtilsImplTest extends AndroidTestCase {
+ private Context context;
+ private MyTracksProviderUtils providerUtils;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ MockContentResolver mockContentResolver = new MockContentResolver();
+ RenamingDelegatingContext targetContext = new RenamingDelegatingContext(
+ getContext(), getContext(), "test.");
+ context = new MockContext(mockContentResolver, targetContext);
+ MyTracksProvider provider = new MyTracksProvider();
+ provider.attachInfo(context, null);
+ mockContentResolver.addProvider(MyTracksProviderUtils.AUTHORITY, provider);
+ setContext(context);
+
+ providerUtils = MyTracksProviderUtils.Factory.get(context);
+ }
+
+ public void testLocationIterator_noPoints() {
+ testIterator(1, 0, 1, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
+ }
+
+ public void testLocationIterator_customFactory() {
+ final Location location = new Location("test_location");
+ final AtomicInteger counter = new AtomicInteger();
+ testIterator(1, 15, 4, false, new LocationFactory() {
+ @Override
+ public Location createLocation() {
+ counter.incrementAndGet();
+ return location;
+ }
+ });
+ // Make sure we were called exactly as many times as we had track points.
+ assertEquals(15, counter.get());
+ }
+
+ public void testLocationIterator_nullFactory() {
+ try {
+ testIterator(1, 15, 4, false, null);
+ fail("Expecting IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expected.
+ }
+ }
+
+ public void testLocationIterator_noBatchAscending() {
+ testIterator(1, 50, 100, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
+ testIterator(2, 50, 50, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
+ }
+
+ public void testLocationIterator_noBatchDescending() {
+ testIterator(1, 50, 100, true, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
+ testIterator(2, 50, 50, true, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
+ }
+
+ public void testLocationIterator_batchAscending() {
+ testIterator(1, 50, 11, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
+ testIterator(2, 50, 25, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
+ }
+
+ public void testLocationIterator_batchDescending() {
+ testIterator(1, 50, 11, true, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
+ testIterator(2, 50, 25, true, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
+ }
+
+ public void testLocationIterator_largeTrack() {
+ testIterator(1, 20000, 2000, false, MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
+ }
+
+ private List testIterator(long trackId, int numPoints, int batchSize,
+ boolean descending, LocationFactory locationFactory) {
+ long lastPointId = initializeTrack(trackId, numPoints);
+ ((MyTracksProviderUtilsImpl) providerUtils).setDefaultCursorBatchSize(batchSize);
+ List locations = new ArrayList(numPoints);
+ LocationIterator it = providerUtils.getLocationIterator(trackId, -1, descending, locationFactory);
+ try {
+ while (it.hasNext()) {
+ Location loc = it.next();
+ assertNotNull(loc);
+ locations.add(loc);
+ // Make sure the IDs are returned in the right order.
+ assertEquals(descending ? lastPointId - locations.size() + 1
+ : lastPointId - numPoints + locations.size(), it.getLocationId());
+ }
+ assertEquals(numPoints, locations.size());
+ } finally {
+ it.close();
+ }
+ return locations;
+ }
+
+ private long initializeTrack(long id, int numPoints) {
+ Track track = new Track();
+ track.setId(id);
+ track.setName("Test: " + id);
+ track.setNumberOfPoints(numPoints);
+ providerUtils.insertTrack(track);
+ track = providerUtils.getTrack(id);
+ assertNotNull(track);
+
+ Location[] locations = new Location[numPoints];
+ for (int i = 0; i < numPoints; ++i) {
+ Location loc = new Location("test");
+ loc.setLatitude(37.0 + (double) i / 10000.0);
+ loc.setLongitude(57.0 - (double) i / 10000.0);
+ loc.setAccuracy((float) i / 100.0f);
+ loc.setAltitude(i * 2.5);
+ locations[i] = loc;
+ }
+ providerUtils.bulkInsertTrackPoints(locations, numPoints, id);
+
+ // Load all inserted locations.
+ long lastPointId = -1;
+ int counter = 0;
+ LocationIterator it = providerUtils.getLocationIterator(id, -1, false,
+ MyTracksProviderUtils.DEFAULT_LOCATION_FACTORY);
+ try {
+ while (it.hasNext()) {
+ it.next();
+ lastPointId = it.getLocationId();
+ counter++;
+ }
+ } finally {
+ it.close();
+ }
+
+ assertTrue(numPoints == 0 || lastPointId > 0);
+ assertEquals(numPoints, track.getNumberOfPoints());
+ assertEquals(numPoints, counter);
+
+ return lastPointId;
+ }
+}
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/content/WaypointCreationRequestTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/content/WaypointCreationRequestTest.java
new file mode 100644
index 000000000..2cc88b895
--- /dev/null
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/content/WaypointCreationRequestTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010 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.content;
+
+import com.google.android.apps.mytracks.content.WaypointCreationRequest.WaypointType;
+
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+
+/**
+ * Tests for the WaypointCreationRequest class.
+ * {@link WaypointCreationRequest}
+ *
+ * @author Sandor Dornbush
+ */
+public class WaypointCreationRequestTest extends AndroidTestCase {
+
+ public void testTypeParceling() {
+ WaypointCreationRequest original = WaypointCreationRequest.DEFAULT_MARKER;
+ Parcel p = Parcel.obtain();
+ original.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ WaypointCreationRequest copy = WaypointCreationRequest.CREATOR.createFromParcel(p);
+ assertEquals(original.getType(), copy.getType());
+ assertNull(copy.getName());
+ assertNull(copy.getDescription());
+ assertNull(copy.getIconUrl());
+ }
+
+ public void testAllAttributesParceling() {
+ WaypointCreationRequest original =
+ new WaypointCreationRequest(WaypointType.MARKER, "name", "description", "img.png");
+ Parcel p = Parcel.obtain();
+ original.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ WaypointCreationRequest copy = WaypointCreationRequest.CREATOR.createFromParcel(p);
+ assertEquals(original.getType(), copy.getType());
+ assertEquals("name", copy.getName());
+ assertEquals("description", copy.getDescription());
+ assertEquals("img.png", copy.getIconUrl());
+ }
+}
diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/services/TrackRecordingServiceTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/services/TrackRecordingServiceTest.java
index 9f48ac210..db0236aa2 100644
--- a/MyTracksTest/src/com/google/android/apps/mytracks/services/TrackRecordingServiceTest.java
+++ b/MyTracksTest/src/com/google/android/apps/mytracks/services/TrackRecordingServiceTest.java
@@ -22,6 +22,7 @@ import com.google.android.apps.mytracks.content.MyTracksProvider;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.Waypoint;
+import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.maps.mytracks.R;
@@ -77,9 +78,11 @@ public class TrackRecordingServiceTest
}
/**
- * A context wrapper with the user provided {@link ContentResolver}.
+ * A context wrapper with the user provided {@link ContentResolver}.
+ *
+ * TODO: Move to test utils package.
*/
- private static class MockContext extends ContextWrapper {
+ public static class MockContext extends ContextWrapper {
private final ContentResolver contentResolver;
public MockContext(ContentResolver contentResolver, Context base) {
@@ -546,9 +549,8 @@ public class TrackRecordingServiceTest
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertFalse(service.isRecording());
- Location loc = new Location("gps");
try {
- service.insertStatisticsMarker(loc);
+ service.insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS);
fail("Expecting IllegalStateException");
} catch (IllegalStateException e) {
// Expected.
@@ -562,11 +564,22 @@ public class TrackRecordingServiceTest
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertTrue(service.isRecording());
- Location loc = new Location("gps");
- assertEquals(1, service.insertStatisticsMarker(loc));
- assertEquals(2, service.insertStatisticsMarker(loc));
+ assertEquals(1, service.insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS));
+ assertEquals(2, service.insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS));
- // TODO: Add more checks.
+ Waypoint wpt = providerUtils.getWaypoint(1);
+ assertEquals(getContext().getString(R.string.stats_icon_url),
+ wpt.getIcon());
+ assertEquals(getContext().getString(R.string.statistics),
+ wpt.getName());
+ assertEquals(Waypoint.TYPE_STATISTICS, wpt.getType());
+ assertEquals(123, wpt.getTrackId());
+ assertEquals(0.0, wpt.getLength());
+ assertNotNull(wpt.getLocation());
+ assertNotNull(wpt.getStatistics());
+ // TODO check the rest of the params.
+
+ // TODO: Check waypoint 2.
}
@MediumTest
@@ -574,29 +587,14 @@ public class TrackRecordingServiceTest
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertFalse(service.isRecording());
- Location loc = new Location("gps");
- Waypoint waypoint = new Waypoint();
- waypoint.setId(1);
- waypoint.setLocation(loc);
try {
- service.insertWaypointMarker(waypoint);
+ service.insertWaypoint(WaypointCreationRequest.DEFAULT_MARKER);
fail("Expecting IllegalStateException");
} catch (IllegalStateException e) {
// Expected.
}
}
- @MediumTest
- public void testInsertWaypointMarker_invalidWaypoint() throws Exception {
- createDummyTrack(123, -1, true);
-
- ITrackRecordingService service = bindAndGetService(createStartIntent());
- assertTrue(service.isRecording());
-
- Waypoint waypoint = new Waypoint();
- assertEquals(-1, service.insertWaypointMarker(waypoint));
- }
-
@MediumTest
public void testInsertWaypointMarker_validWaypoint() throws Exception {
createDummyTrack(123, -1, true);
@@ -604,11 +602,17 @@ public class TrackRecordingServiceTest
ITrackRecordingService service = bindAndGetService(createStartIntent());
assertTrue(service.isRecording());
- Location loc = new Location("gps");
- Waypoint waypoint = new Waypoint();
- waypoint.setId(1);
- waypoint.setLocation(loc);
- assertEquals(1, service.insertWaypointMarker(waypoint));
+ assertEquals(1, service.insertWaypoint(WaypointCreationRequest.DEFAULT_MARKER));
+ Waypoint wpt = providerUtils.getWaypoint(1);
+ assertEquals(getContext().getString(R.string.waypoint_icon_url),
+ wpt.getIcon());
+ assertEquals(getContext().getString(R.string.waypoint),
+ wpt.getName());
+ assertEquals(Waypoint.TYPE_WAYPOINT, wpt.getType());
+ assertEquals(123, wpt.getTrackId());
+ assertEquals(0.0, wpt.getLength());
+ assertNotNull(wpt.getLocation());
+ assertNull(wpt.getStatistics());
}
@MediumTest
@@ -804,11 +808,9 @@ public class TrackRecordingServiceTest
service.recordLocation(loc);
if (i % 10 == 0) {
- service.insertStatisticsMarker(loc);
+ service.insertWaypoint(WaypointCreationRequest.DEFAULT_STATISTICS);
} else if (i % 7 == 0) {
- Waypoint waypoint = new Waypoint();
- waypoint.setLocation(loc);
- service.insertWaypointMarker(waypoint);
+ service.insertWaypoint(WaypointCreationRequest.DEFAULT_MARKER);
}
}
diff --git a/SignalStrengthSampler/.classpath b/SignalStrengthSampler/.classpath
index 57972d993..f9bca44bc 100644
--- a/SignalStrengthSampler/.classpath
+++ b/SignalStrengthSampler/.classpath
@@ -3,7 +3,7 @@
-
+
diff --git a/SignalStrengthSampler/src/com/google/android/apps/mytracks/signalstrength/SignalStrengthService.java b/SignalStrengthSampler/src/com/google/android/apps/mytracks/signalstrength/SignalStrengthService.java
index 7f80c7433..210fefe02 100644
--- a/SignalStrengthSampler/src/com/google/android/apps/mytracks/signalstrength/SignalStrengthService.java
+++ b/SignalStrengthSampler/src/com/google/android/apps/mytracks/signalstrength/SignalStrengthService.java
@@ -17,7 +17,10 @@ package com.google.android.apps.mytracks.signalstrength;
import static com.google.android.apps.mytracks.signalstrength.SignalStrengthConstants.*;
+import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
+import com.google.android.apps.mytracks.content.MyTracksProviderUtilsImpl;
import com.google.android.apps.mytracks.content.Waypoint;
+import com.google.android.apps.mytracks.content.WaypointCreationRequest;
import com.google.android.apps.mytracks.services.ITrackRecordingService;
import com.google.android.apps.mytracks.signalstrength.SignalStrengthListener.SignalStrengthCallback;
@@ -53,6 +56,7 @@ public class SignalStrengthService extends Service
private ITrackRecordingService mytracksService;
private long lastSamplingTime;
private long samplingPeriod;
+ private MyTracksProviderUtils utils;
@Override
public void onCreate() {
@@ -63,6 +67,7 @@ public class SignalStrengthService extends Service
getString(R.string.mytracks_service_class));
preferences = PreferenceManager.getDefaultSharedPreferences(this);
signalListenerFactory = new SignalStrengthListenerFactory();
+ utils = new MyTracksProviderUtilsImpl(this.getContentResolver());
}
@Override
@@ -154,13 +159,6 @@ public class SignalStrengthService extends Service
return;
}
- // We don't set location or track id - My Tracks can fill those
- Waypoint wpt = new Waypoint();
- wpt.setName("Signal Strength");
- wpt.setType(Waypoint.TYPE_WAYPOINT);
- wpt.setIcon(icon);
- wpt.setDescription(description);
-
try {
long waypointId;
synchronized (this) {
@@ -169,7 +167,11 @@ public class SignalStrengthService extends Service
return;
}
- waypointId = mytracksService.insertWaypointMarker(wpt);
+ // Create a waypoint.
+ WaypointCreationRequest request =
+ new WaypointCreationRequest(WaypointCreationRequest.WaypointType.MARKER,
+ "Signal Strength", icon, description);
+ waypointId = mytracksService.insertWaypoint(request);
}
if (waypointId >= 0) {
diff --git a/SignalStrengthSamplerTest/.classpath b/SignalStrengthSamplerTest/.classpath
index bee7810d7..e091a2041 100644
--- a/SignalStrengthSamplerTest/.classpath
+++ b/SignalStrengthSamplerTest/.classpath
@@ -1,9 +1,9 @@
+
-
-
+