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 @@ + - - +