merge heads

This commit is contained in:
Jimmy Shih
2011-09-26 10:54:11 -07:00
46 changed files with 708 additions and 294 deletions
+13 -2
View File
@@ -17,8 +17,8 @@ limitations under the License.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.maps.mytracks" package="com.google.android.maps.mytracks"
android:installLocation="auto" android:installLocation="auto"
android:versionCode="31" android:versionCode="32"
android:versionName="1.1.8"> android:versionName="1.1.9">
<application android:icon="@drawable/arrow_icon" <application android:icon="@drawable/arrow_icon"
android:label="@string/app_name" android:label="@string/app_name"
android:backupAgent="com.google.android.apps.mytracks.io.backup.MyTracksBackupAgent"> android:backupAgent="com.google.android.apps.mytracks.io.backup.MyTracksBackupAgent">
@@ -79,6 +79,17 @@ limitations under the License.
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="com.google.android.apps.mytracks.DeleteTrack"
android:label="@string/deletetrack_title"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:noHistory="true">
<intent-filter>
<action android:name="android.intent.action.DELETE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/vnd.google.track" />
</intent-filter>
</activity>
<activity android:name="com.google.android.apps.mytracks.WaypointDetails" <activity android:name="com.google.android.apps.mytracks.WaypointDetails"
android:label="@string/waypointdetails_title"> android:label="@string/waypointdetails_title">
<intent-filter> <intent-filter>
+2 -4
View File
@@ -13,7 +13,5 @@ split.density=false
target=Google Inc.:Google APIs:13 target=Google Inc.:Google APIs:13
android.library.reference.1=../MyTracksLib/ android.library.reference.1=../MyTracksLib/
# ProGuard is turned off while we investigate the removal of code that # Enable proguard.
# isn't actually dead from Fusion Tables. See issue 303 for an example of proguard.config=proguard.cfg
# the result of that removal.
#proguard.config=proguard.cfg
+12
View File
@@ -51,3 +51,15 @@
-keep class * implements android.os.Parcelable { -keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *; public static final android.os.Parcelable$Creator *;
} }
# Needed by google-api-client to keep generic types and @Key annotations accessed via reflection
-keepclassmembers class * {
@com.google.api.client.util.Key <fields>;
}
-keepattributes Signature,RuntimeVisibleAnnotations,AnnotationDefault
# Needed by Guava
-dontwarn sun.misc.Unsafe
+9 -3
View File
@@ -40,7 +40,9 @@ limitations under the License.
android:singleLine="true" android:singleLine="true"
android:autoText="true" android:autoText="true"
android:capitalize="words" android:capitalize="words"
android:selectAllOnFocus="true"/> android:selectAllOnFocus="true"
android:hint="@string/trackdetails_name_hint"
android:imeOptions="actionNext"/>
</LinearLayout> </LinearLayout>
<TextView android:text="@string/trackdetails_category" <TextView android:text="@string/trackdetails_category"
android:layout_width="fill_parent" android:layout_width="fill_parent"
@@ -48,7 +50,9 @@ limitations under the License.
<AutoCompleteTextView android:id="@+id/trackdetails_category" <AutoCompleteTextView android:id="@+id/trackdetails_category"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:singleLine="true"/> android:singleLine="true"
android:hint="@string/trackdetails_category_hint"
android:imeOptions="actionNext"/>
<TextView android:text="@string/trackdetails_description" <TextView android:text="@string/trackdetails_description"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
@@ -61,7 +65,9 @@ limitations under the License.
android:selectAllOnFocus="true" android:selectAllOnFocus="true"
android:maxLines="50" android:maxLines="50"
android:gravity="top" android:gravity="top"
android:layout_weight="1"/> android:layout_weight="1"
android:hint="@string/trackdetails_description_hint"
android:imeOptions="actionDone"/>
<LinearLayout <LinearLayout
android:orientation="horizontal" android:orientation="horizontal"
android:layout_width="fill_parent" android:layout_width="fill_parent"
+13 -15
View File
@@ -127,26 +127,24 @@ limitations under the License.
</TableLayout> </TableLayout>
</ScrollView> </ScrollView>
<LinearLayout <LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/list_bar" android:background="@drawable/list_bar"
android:padding="3dip"> android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="horizontal"
android:paddingLeft="2dip"
android:paddingRight="2dip"
android:paddingTop="4dip">
<!-- left spacer -->
<LinearLayout style="@style/DialogButtonSpacer"/>
<Button android:id="@+id/sendtogoogle_cancel" <Button android:id="@+id/sendtogoogle_cancel"
android:layout_width="wrap_content" android:layout_gravity="left"
android:layout_height="48dip"
android:layout_gravity="right"
android:text="@string/cancel" android:text="@string/cancel"
android:textSize="14dip"/> style="@style/DialogButton"/>
<TextView
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<Button android:id="@+id/sendtogoogle_send_now" <Button android:id="@+id/sendtogoogle_send_now"
android:layout_width="wrap_content"
android:layout_height="48dip"
android:layout_gravity="right" android:layout_gravity="right"
android:text="@string/sendtogoogle_send_now" android:text="@string/sendtogoogle_send_now"
android:textSize="14dip"/> style="@style/DialogButton"/>
<!-- right spacer -->
<LinearLayout style="@style/DialogButtonSpacer"/>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
@@ -50,7 +50,9 @@ limitations under the License.
android:singleLine="true" android:singleLine="true"
android:autoText="true" android:autoText="true"
android:capitalize="words" android:capitalize="words"
android:selectAllOnFocus="true"/> android:selectAllOnFocus="true"
android:hint="@string/waypointdetails_name_hint"
android:imeOptions="actionNext"/>
</LinearLayout> </LinearLayout>
<LinearLayout android:id="@+id/waypointdetails_description_layout" <LinearLayout android:id="@+id/waypointdetails_description_layout"
android:orientation="vertical" android:orientation="vertical"
@@ -65,7 +67,9 @@ limitations under the License.
<AutoCompleteTextView android:id="@+id/waypointdetails_category" <AutoCompleteTextView android:id="@+id/waypointdetails_category"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:singleLine="true"/> android:singleLine="true"
android:hint="@string/waypointdetails_category_hint"
android:imeOptions="actionNext"/>
<TextView android:text="@string/waypointdetails_description" <TextView android:text="@string/waypointdetails_description"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
@@ -79,7 +83,9 @@ limitations under the License.
android:minLines="5" android:minLines="5"
android:maxLines="50" android:maxLines="50"
android:gravity="top" android:gravity="top"
android:layout_weight="1"/> android:layout_weight="1"
android:hint="@string/waypointdetails_description_hint"
android:imeOptions="actionDone"/>
</LinearLayout> </LinearLayout>
<TableLayout android:id="@+id/waypoint_stats" <TableLayout android:id="@+id/waypoint_stats"
+21
View File
@@ -125,6 +125,27 @@ limitations under the License.
android:text="@string/bpm" /> android:text="@string/bpm" />
</TableRow> </TableRow>
<!-- Battery Level -->
<TableRow
android:padding="1dip">
<TextView
android:layout_column="1"
android:layout_span="3"
android:text="@string/battery_level" />
</TableRow>
<TableRow
android:background="@color/stat_label_background">
<TextView
style="@style/StatsRegister.Big"
android:id="@+id/battery_level_register"
android:layout_column="1"
android:layout_span="4" />
<TextView
style="@style/StatsUnitSolo"
android:layout_column="5"
android:text="@string/percent" />
</TableRow>
</TableLayout> </TableLayout>
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>
+6
View File
@@ -152,14 +152,20 @@ limitations under the License.
<!-- MyTracks Details --> <!-- MyTracks Details -->
<string name="trackdetails_title">Detalls de la ruta</string> <string name="trackdetails_title">Detalls de la ruta</string>
<string name="trackdetails_name">Nom de la ruta</string> <string name="trackdetails_name">Nom de la ruta</string>
<string name="trackdetails_name_hint">Nom de la ruta</string>
<string name="trackdetails_description">Descripció de la ruta</string> <string name="trackdetails_description">Descripció de la ruta</string>
<string name="trackdetails_description_hint">Descripció de la ruta</string>
<string name="trackdetails_category">Tipus d\'activitat (p.e. senderisme, bicicleta, còrrer, escalada...)</string> <string name="trackdetails_category">Tipus d\'activitat (p.e. senderisme, bicicleta, còrrer, escalada...)</string>
<string name="trackdetails_category_hint">Tipus d\'activitat</string>
<!-- MyTracks Waypoint Details --> <!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">Detalls del marcador</string> <string name="waypointdetails_title">Detalls del marcador</string>
<string name="waypointdetails_name">Nom del marcador</string> <string name="waypointdetails_name">Nom del marcador</string>
<string name="waypointdetails_name_hint">Nom del marcador</string>
<string name="waypointdetails_description">Descripció del marcador</string> <string name="waypointdetails_description">Descripció del marcador</string>
<string name="waypointdetails_description_hint">Descripció del marcador</string>
<string name="waypointdetails_category">Tipus de marcador (e.g. edifici, sot, vista...)</string> <string name="waypointdetails_category">Tipus de marcador (e.g. edifici, sot, vista...)</string>
<string name="waypointdetails_category_hint">Tipus de marcador</string>
<!-- MyTracks Settings --> <!-- MyTracks Settings -->
<string name="mytracks_settings">Paràmetres de My Tracks</string> <string name="mytracks_settings">Paràmetres de My Tracks</string>
+7
View File
@@ -154,14 +154,20 @@ limitations under the License.
<!-- MyTracks Details --> <!-- MyTracks Details -->
<string name="trackdetails_title">Trackdetails</string> <string name="trackdetails_title">Trackdetails</string>
<string name="trackdetails_name">Name</string> <string name="trackdetails_name">Name</string>
<string name="trackdetails_name_hint">Name</string>
<string name="trackdetails_description">Beschreibung</string> <string name="trackdetails_description">Beschreibung</string>
<string name="trackdetails_description_hint">Beschreibung</string>
<string name="trackdetails_category">Aktivität (z. B. Wandern, Fahrradfahren, Laufen, Klettern…)</string> <string name="trackdetails_category">Aktivität (z. B. Wandern, Fahrradfahren, Laufen, Klettern…)</string>
<string name="trackdetails_category_hint">Aktivität</string>
<!-- MyTracks Waypoint Details --> <!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">Wegpunktdetails</string> <string name="waypointdetails_title">Wegpunktdetails</string>
<string name="waypointdetails_name">Wegpunktname</string> <string name="waypointdetails_name">Wegpunktname</string>
<string name="waypointdetails_name_hint">Wegpunktname</string>
<string name="waypointdetails_description">Wegpunktbeschreibung</string> <string name="waypointdetails_description">Wegpunktbeschreibung</string>
<string name="waypointdetails_description_hint">Wegpunktbeschreibung</string>
<string name="waypointdetails_category">Art des Wegpunktes (z. B. Gebäude, Schlagloch, Sehenswürdigkeit…)</string> <string name="waypointdetails_category">Art des Wegpunktes (z. B. Gebäude, Schlagloch, Sehenswürdigkeit…)</string>
<string name="waypointdetails_category_hint">Art des Wegpunktes</string>
<!-- MyTracks Settings --> <!-- MyTracks Settings -->
<string name="mytracks_settings">Einstellungen für My Tracks</string> <string name="mytracks_settings">Einstellungen für My Tracks</string>
@@ -333,6 +339,7 @@ limitations under the License.
<!--string name="revolutions_per_minute">rpm</string--> <!--string name="revolutions_per_minute">rpm</string-->
<!--string name="bpm">bpm</string--> <!--string name="bpm">bpm</string-->
<string name="battery_level">Akkukapazität</string>
<!-- Stats Labels --> <!-- Stats Labels -->
<string name="moving_time_label">Zeit in Bewegung</string> <string name="moving_time_label">Zeit in Bewegung</string>
+6
View File
@@ -138,14 +138,20 @@ limitations under the License.
<!-- MyTracks Details --> <!-- MyTracks Details -->
<string name="trackdetails_title">Detalles del recorrido</string> <string name="trackdetails_title">Detalles del recorrido</string>
<string name="trackdetails_name">Nombre del recorrido</string> <string name="trackdetails_name">Nombre del recorrido</string>
<string name="trackdetails_name_hint">Nombre del recorrido</string>
<string name="trackdetails_description">Descripción del recorrido</string> <string name="trackdetails_description">Descripción del recorrido</string>
<string name="trackdetails_description_hint">Descripción del recorrido</string>
<string name="trackdetails_category">Tipo de actividad (por ejemplo, ciclismo, alpinismo...)</string> <string name="trackdetails_category">Tipo de actividad (por ejemplo, ciclismo, alpinismo...)</string>
<string name="trackdetails_category_hint">Tipo de actividad</string>
<!-- MyTracks Waypoint Details --> <!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">Detalles de señal</string> <string name="waypointdetails_title">Detalles de señal</string>
<string name="waypointdetails_name">Nombre de señal</string> <string name="waypointdetails_name">Nombre de señal</string>
<string name="waypointdetails_name_hint">Nombre de señal</string>
<string name="waypointdetails_description">Descripción de señal</string> <string name="waypointdetails_description">Descripción de señal</string>
<string name="waypointdetails_description_hint">Descripción de señal</string>
<string name="waypointdetails_category">Tipo de señal (por ejemplo, edificio, bache, atracción...)</string> <string name="waypointdetails_category">Tipo de señal (por ejemplo, edificio, bache, atracción...)</string>
<string name="waypointdetails_category_hint">Tipo de señal</string>
<!-- MyTracks Settings --> <!-- MyTracks Settings -->
<string name="mytracks_settings">Configuraciones de My Tracks</string> <string name="mytracks_settings">Configuraciones de My Tracks</string>
+7 -1
View File
@@ -183,14 +183,20 @@ limitations under the License.
<!-- MyTracks Details --> <!-- MyTracks Details -->
<string name="trackdetails_title">Reitin tiedot</string> <string name="trackdetails_title">Reitin tiedot</string>
<string name="trackdetails_name">Reitin nimi</string> <string name="trackdetails_name">Reitin nimi</string>
<string name="trackdetails_name_hint">Reitin nimi</string>
<string name="trackdetails_description">Reitin kuvaus</string> <string name="trackdetails_description">Reitin kuvaus</string>
<string name="trackdetails_description_hint">Reitin kuvaus</string>
<string name="trackdetails_category">Liikunnan muoto (esim. hölkkä, pyöräily, juoksu...)</string> <string name="trackdetails_category">Liikunnan muoto (esim. hölkkä, pyöräily, juoksu...)</string>
<string name="trackdetails_category_hint">Liikunnan muoto</string>
<!-- MyTracks Waypoint Details --> <!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">Merkinnän tiedot</string> <string name="waypointdetails_title">Merkinnän tiedot</string>
<string name="waypointdetails_name">Merkinnän nimi</string> <string name="waypointdetails_name">Merkinnän nimi</string>
<string name="waypointdetails_name_hint">Merkinnän nimi</string>
<string name="waypointdetails_description">Merkinnän kuvaus</string> <string name="waypointdetails_description">Merkinnän kuvaus</string>
<string name="waypointdetails_description_hint">Merkinnän kuvaus</string>
<string name="waypointdetails_category">Merkinnän tyyppi (esim. rakennus, kuoppa, nähtävyys...)</string> <string name="waypointdetails_category">Merkinnän tyyppi (esim. rakennus, kuoppa, nähtävyys...)</string>
<string name="waypointdetails_category_hint">Merkinnän tyyppi</string>
<!-- MyTracks Settings --> <!-- MyTracks Settings -->
<string name="mytracks_settings">My Tracks Asetukset</string> <string name="mytracks_settings">My Tracks Asetukset</string>
@@ -380,9 +386,9 @@ limitations under the License.
<!-- Sensors --> <!-- Sensors -->
<string name="watts">W</string> <string name="watts">W</string>
<string name="revolutions_per_minute">rpm</string> <string name="revolutions_per_minute">rpm</string>
<string name="bpm">bpm</string> <string name="bpm">bpm</string>
<string name="battery_level">Akku</string>
<!-- Stats Labels --> <!-- Stats Labels -->
<string name="moving_time_label">Liikkumisaika</string> <string name="moving_time_label">Liikkumisaika</string>
+6
View File
@@ -144,14 +144,20 @@ limitations under the License.
<!-- MyTracks Details --> <!-- MyTracks Details -->
<string name="trackdetails_title">Détails parcours</string> <string name="trackdetails_title">Détails parcours</string>
<string name="trackdetails_name">Nom du parcours</string> <string name="trackdetails_name">Nom du parcours</string>
<string name="trackdetails_name_hint">Nom du parcours</string>
<string name="trackdetails_description">Description du parcours</string> <string name="trackdetails_description">Description du parcours</string>
<string name="trackdetails_description_hint">Description du parcours</string>
<string name="trackdetails_category">Type d\'activité (randonnée, cyclisme, jogging, escalade...)</string> <string name="trackdetails_category">Type d\'activité (randonnée, cyclisme, jogging, escalade...)</string>
<string name="trackdetails_category_hint">Type d\'activité</string>
<!-- MyTracks Waypoint Details --> <!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">Details balise</string> <string name="waypointdetails_title">Details balise</string>
<string name="waypointdetails_name">Nom de la balise</string> <string name="waypointdetails_name">Nom de la balise</string>
<string name="waypointdetails_name_hint">Nom de la balise</string>
<string name="waypointdetails_description">Description balise</string> <string name="waypointdetails_description">Description balise</string>
<string name="waypointdetails_description_hint">Description balise</string>
<string name="waypointdetails_category">Nom de balise (par ex.: immeuble, boutique, point de vue...)</string> <string name="waypointdetails_category">Nom de balise (par ex.: immeuble, boutique, point de vue...)</string>
<string name="waypointdetails_category_hint">Nom de balise</string>
<!-- MyTracks Settings --> <!-- MyTracks Settings -->
<string name="mytracks_settings">Paramètres My Tracks</string> <string name="mytracks_settings">Paramètres My Tracks</string>
+6
View File
@@ -147,14 +147,20 @@ limitations under the License.
<!-- MyTracks Details --> <!-- MyTracks Details -->
<string name="trackdetails_title">Dettagli del percorso</string> <string name="trackdetails_title">Dettagli del percorso</string>
<string name="trackdetails_name">Nome del percorso</string> <string name="trackdetails_name">Nome del percorso</string>
<string name="trackdetails_name_hint">Nome del percorso</string>
<string name="trackdetails_description">Descrizione del percorso</string> <string name="trackdetails_description">Descrizione del percorso</string>
<string name="trackdetails_description_hint">Descrizione del percorso</string>
<string name="trackdetails_category">Tipo di attività (ad es. escursionismo, ciclismo, corsa, arrampicata...)</string> <string name="trackdetails_category">Tipo di attività (ad es. escursionismo, ciclismo, corsa, arrampicata...)</string>
<string name="trackdetails_category_hint">Tipo di attività</string>
<!-- MyTracks Waypoint Details --> <!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">Dettagli sul segnaposto</string> <string name="waypointdetails_title">Dettagli sul segnaposto</string>
<string name="waypointdetails_name">Nome del segnaposto</string> <string name="waypointdetails_name">Nome del segnaposto</string>
<string name="waypointdetails_name_hint">Nome del segnaposto</string>
<string name="waypointdetails_description">Descrizione del segnaposto</string> <string name="waypointdetails_description">Descrizione del segnaposto</string>
<string name="waypointdetails_description_hint">Descrizione del segnaposto</string>
<string name="waypointdetails_category">Tipo di segnaposto (ad es. edificio, buca, vista...)</string> <string name="waypointdetails_category">Tipo di segnaposto (ad es. edificio, buca, vista...)</string>
<string name="waypointdetails_category_hint">Tipo di segnaposto</string>
<!-- MyTracks Settings --> <!-- MyTracks Settings -->
<string name="mytracks_settings">Impostazioni di My Tracks</string> <string name="mytracks_settings">Impostazioni di My Tracks</string>
+6
View File
@@ -176,14 +176,20 @@ limitations under the License.
<!-- MyTracks Details --> <!-- MyTracks Details -->
<string name="trackdetails_title">トラック詳細</string> <string name="trackdetails_title">トラック詳細</string>
<string name="trackdetails_name">トラック名</string> <string name="trackdetails_name">トラック名</string>
<string name="trackdetails_name_hint">トラック名</string>
<string name="trackdetails_description">トラック説明</string> <string name="trackdetails_description">トラック説明</string>
<string name="trackdetails_description_hint">トラック説明</string>
<string name="trackdetails_category">活動タイプ(ハイキング, サイクリング、ランニング、登山...)</string> <string name="trackdetails_category">活動タイプ(ハイキング, サイクリング、ランニング、登山...)</string>
<string name="trackdetails_category_hint">活動タイプ</string>
<!-- MyTracks Waypoint Details --> <!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">マーカー詳細</string> <string name="waypointdetails_title">マーカー詳細</string>
<string name="waypointdetails_name">マーカー名</string> <string name="waypointdetails_name">マーカー名</string>
<string name="waypointdetails_name_hint">マーカー名</string>
<string name="waypointdetails_description">マーカー説明</string> <string name="waypointdetails_description">マーカー説明</string>
<string name="waypointdetails_description_hint">マーカー説明</string>
<string name="waypointdetails_category">マーカータイプ(建物、洞穴、名所...)</string> <string name="waypointdetails_category">マーカータイプ(建物、洞穴、名所...)</string>
<string name="waypointdetails_category_hint">マーカータイプ</string>
<!-- MyTracks Settings --> <!-- MyTracks Settings -->
<string name="mytracks_settings">My Tracks設定</string> <string name="mytracks_settings">My Tracks設定</string>
+6
View File
@@ -149,14 +149,20 @@ limitations under the License.
<!-- MyTracks Details --> <!-- MyTracks Details -->
<string name="trackdetails_title">Szczegóły trasy</string> <string name="trackdetails_title">Szczegóły trasy</string>
<string name="trackdetails_name">Nazwa trasy</string> <string name="trackdetails_name">Nazwa trasy</string>
<string name="trackdetails_name_hint">Nazwa trasy</string>
<string name="trackdetails_description">Opis trasy</string> <string name="trackdetails_description">Opis trasy</string>
<string name="trackdetails_description_hint">Opis trasy</string>
<string name="trackdetails_category">Typ aktywności (np. wspinanie, jazda rowerem, bieganie...)</string> <string name="trackdetails_category">Typ aktywności (np. wspinanie, jazda rowerem, bieganie...)</string>
<string name="trackdetails_category_hint">Typ aktywności</string>
<!-- MyTracks Waypoint Details --> <!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">Szczegóły znacznika</string> <string name="waypointdetails_title">Szczegóły znacznika</string>
<string name="waypointdetails_name">Nazwa znacznika</string> <string name="waypointdetails_name">Nazwa znacznika</string>
<string name="waypointdetails_name_hint">Nazwa znacznika</string>
<string name="waypointdetails_description">Opis znacznika</string> <string name="waypointdetails_description">Opis znacznika</string>
<string name="waypointdetails_description_hint">Opis znacznika</string>
<string name="waypointdetails_category">Typ znacznika (np. budynek, jaskinia, punkt widokowy...)</string> <string name="waypointdetails_category">Typ znacznika (np. budynek, jaskinia, punkt widokowy...)</string>
<string name="waypointdetails_category_hint">Typ znacznika</string>
<!-- MyTracks Settings --> <!-- MyTracks Settings -->
<string name="mytracks_settings">Ustawienia My Tracks</string> <string name="mytracks_settings">Ustawienia My Tracks</string>
+6
View File
@@ -144,14 +144,20 @@ limitations under the License.
<!-- MyTracks Details --> <!-- MyTracks Details -->
<string name="trackdetails_title">Detalhes do Caminho</string> <string name="trackdetails_title">Detalhes do Caminho</string>
<string name="trackdetails_name">Nome do Caminho</string> <string name="trackdetails_name">Nome do Caminho</string>
<string name="trackdetails_name_hint">Nome do Caminho</string>
<string name="trackdetails_description">Descrição do Caminho</string> <string name="trackdetails_description">Descrição do Caminho</string>
<string name="trackdetails_description_hint">Descrição do Caminho</string>
<string name="trackdetails_category">Tipo de Atividade (por ex. caminhada, ciclismo, escalada...)</string> <string name="trackdetails_category">Tipo de Atividade (por ex. caminhada, ciclismo, escalada...)</string>
<string name="trackdetails_category_hint">Tipo de Atividade</string>
<!-- MyTracks Waypoint Details --> <!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">Detalhes do Marcador</string> <string name="waypointdetails_title">Detalhes do Marcador</string>
<string name="waypointdetails_name">Nome do Marcador</string> <string name="waypointdetails_name">Nome do Marcador</string>
<string name="waypointdetails_name_hint">Nome do Marcador</string>
<string name="waypointdetails_description">Descrição do Marcador</string> <string name="waypointdetails_description">Descrição do Marcador</string>
<string name="waypointdetails_description_hint">Descrição do Marcador</string>
<string name="waypointdetails_category">Tipo do Marcador (por ex. Prédio, Mirante, Cachoeira...)</string> <string name="waypointdetails_category">Tipo do Marcador (por ex. Prédio, Mirante, Cachoeira...)</string>
<string name="waypointdetails_category_hint">Tipo do Marcador</string>
<!-- MyTracks Settings --> <!-- MyTracks Settings -->
<string name="mytracks_settings">Configurações do My Tracks</string> <string name="mytracks_settings">Configurações do My Tracks</string>
+6
View File
@@ -179,14 +179,20 @@ limitations under the License.
<!-- MyTracks Details --> <!-- MyTracks Details -->
<string name="trackdetails_title">Трек детали</string> <string name="trackdetails_title">Трек детали</string>
<string name="trackdetails_name">Название трека</string> <string name="trackdetails_name">Название трека</string>
<string name="trackdetails_name_hint">Название трека</string>
<string name="trackdetails_description">Описание трека</string> <string name="trackdetails_description">Описание трека</string>
<string name="trackdetails_description_hint">Описание трека</string>
<string name="trackdetails_category">Тип деятельности (например: пешая прогулка, велосипедная прогулка, бег, восхождение...)</string> <string name="trackdetails_category">Тип деятельности (например: пешая прогулка, велосипедная прогулка, бег, восхождение...)</string>
<string name="trackdetails_category_hint">Тип деятельности</string>
<!-- MyTracks Waypoint Details --> <!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">Маркер детали</string> <string name="waypointdetails_title">Маркер детали</string>
<string name="waypointdetails_name">Имя маркера</string> <string name="waypointdetails_name">Имя маркера</string>
<string name="waypointdetails_name_hint">Имя маркера</string>
<string name="waypointdetails_description">Описание маркера</string> <string name="waypointdetails_description">Описание маркера</string>
<string name="waypointdetails_description_hint">Описание маркера</string>
<string name="waypointdetails_category">Тип маркера (например: здание, выбоина, достопримечательность...)</string> <string name="waypointdetails_category">Тип маркера (например: здание, выбоина, достопримечательность...)</string>
<string name="waypointdetails_category_hint">Тип маркера</string>
<!-- MyTracks Settings --> <!-- MyTracks Settings -->
<string name="mytracks_settings">Настройки My Tracks</string> <string name="mytracks_settings">Настройки My Tracks</string>
+6
View File
@@ -149,14 +149,20 @@ limitations under the License.
<!-- MyTracks Details --> <!-- MyTracks Details -->
<string name="trackdetails_title">Spårdetaljer</string> <string name="trackdetails_title">Spårdetaljer</string>
<string name="trackdetails_name">Spårnamn</string> <string name="trackdetails_name">Spårnamn</string>
<string name="trackdetails_name_hint">Spårnamn</string>
<string name="trackdetails_description">Spårbeskrivning</string> <string name="trackdetails_description">Spårbeskrivning</string>
<string name="trackdetails_description_hint">Spårbeskrivning</string>
<string name="trackdetails_category">Aktivitetstyp (t ex vandring, cyckling, löpning, klättring...)</string> <string name="trackdetails_category">Aktivitetstyp (t ex vandring, cyckling, löpning, klättring...)</string>
<string name="trackdetails_category_hint">Aktivitetstyp</string>
<!-- MyTracks Waypoint Details --> <!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">Markördetaljer</string> <string name="waypointdetails_title">Markördetaljer</string>
<string name="waypointdetails_name">Markörnamn</string> <string name="waypointdetails_name">Markörnamn</string>
<string name="waypointdetails_name_hint">Markörnamn</string>
<string name="waypointdetails_description">Markörbeskrivning</string> <string name="waypointdetails_description">Markörbeskrivning</string>
<string name="waypointdetails_description_hint">Markörbeskrivning</string>
<string name="waypointdetails_category">Markörtyp (e.g. byggnad, grop, sevärdhet...)</string> <string name="waypointdetails_category">Markörtyp (e.g. byggnad, grop, sevärdhet...)</string>
<string name="waypointdetails_category_hint">Markörtyp</string>
<!-- MyTracks Settings --> <!-- MyTracks Settings -->
<string name="mytracks_settings">My Tracks inställningar</string> <string name="mytracks_settings">My Tracks inställningar</string>
+6
View File
@@ -180,14 +180,20 @@ limitations under the License.
<!-- MyTracks Details --> <!-- MyTracks Details -->
<string name="trackdetails_title">轨迹详细信息</string> <string name="trackdetails_title">轨迹详细信息</string>
<string name="trackdetails_name">轨迹名称</string> <string name="trackdetails_name">轨迹名称</string>
<string name="trackdetails_name_hint">轨迹名称</string>
<string name="trackdetails_description">轨迹描述</string> <string name="trackdetails_description">轨迹描述</string>
<string name="trackdetails_description_hint">轨迹描述</string>
<string name="trackdetails_category">活动类型 (例如: 徒步, 骑行, 跑步, 攀岩...)</string> <string name="trackdetails_category">活动类型 (例如: 徒步, 骑行, 跑步, 攀岩...)</string>
<string name="trackdetails_category_hint">活动类型</string>
<!-- MyTracks Waypoint Details --> <!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">标记详细信息</string> <string name="waypointdetails_title">标记详细信息</string>
<string name="waypointdetails_name">标记名称</string> <string name="waypointdetails_name">标记名称</string>
<string name="waypointdetails_name_hint">标记名称</string>
<string name="waypointdetails_description">标记描述</string> <string name="waypointdetails_description">标记描述</string>
<string name="waypointdetails_description_hint">标记描述</string>
<string name="waypointdetails_category">标记类型 (例如: 建筑, 陷坑, 景点...)</string> <string name="waypointdetails_category">标记类型 (例如: 建筑, 陷坑, 景点...)</string>
<string name="waypointdetails_category_hint">标记类型</string>
<!-- MyTracks Settings --> <!-- MyTracks Settings -->
<string name="mytracks_settings">My Tracks 设置</string> <string name="mytracks_settings">My Tracks 设置</string>
+4
View File
@@ -44,6 +44,10 @@ limitations under the License.
<!-- ID for Google Analytics --> <!-- ID for Google Analytics -->
<string name="google_analytics_id">UA-7222692-2</string> <string name="google_analytics_id">UA-7222692-2</string>
<!-- Symbols -->
<string name="percent">%</string>
<!-- Intent actions --> <!-- Intent actions -->
<string name="save_intent_action">android.intent.action.SAVE</string> <string name="save_intent_action">android.intent.action.SAVE</string>
<string name="open_settings_screen">android.intent.action.settings.OPEN</string>
</resources> </resources>
+1
View File
@@ -53,4 +53,5 @@ limitations under the License.
<string name="reset_key">resetToDefaults</string> <string name="reset_key">resetToDefaults</string>
<string name="sensor_options_key">sensorOptions</string> <string name="sensor_options_key">sensorOptions</string>
<string name="ant_options_key">antOptions</string> <string name="ant_options_key">antOptions</string>
<string name="display_settings_screen_key">displaySettingsScreen</string>
</resources> </resources>
+9 -1
View File
@@ -83,7 +83,8 @@ limitations under the License.
<string name="write_progress_message">Writing file to SD card. This may take a while.</string> <string name="write_progress_message">Writing file to SD card. This may take a while.</string>
<string name="progress_message_updating_track">Updating track statistics...</string> <string name="progress_message_updating_track">Updating track statistics...</string>
<!-- Used by DeleteAllDataHandler --> <!-- Used by deletion actions -->
<string name="deletetrack_title">Delete track</string>
<string name="are_you_sure_question">Are you sure?</string> <string name="are_you_sure_question">Are you sure?</string>
<string name="all_data_will_be_permanently_deleted">All tracks and markers will be deleted from this phone.</string> <string name="all_data_will_be_permanently_deleted">All tracks and markers will be deleted from this phone.</string>
<string name="track_will_be_permanently_deleted">The track and its markers will be permanently deleted from this phone.</string> <string name="track_will_be_permanently_deleted">The track and its markers will be permanently deleted from this phone.</string>
@@ -183,14 +184,20 @@ limitations under the License.
<!-- MyTracks Details --> <!-- MyTracks Details -->
<string name="trackdetails_title">Track Details</string> <string name="trackdetails_title">Track Details</string>
<string name="trackdetails_name">Track Name</string> <string name="trackdetails_name">Track Name</string>
<string name="trackdetails_name_hint">Track Name</string>
<string name="trackdetails_description">Track Description</string> <string name="trackdetails_description">Track Description</string>
<string name="trackdetails_description_hint">Track Description</string>
<string name="trackdetails_category">Activity Type (e.g. hiking, cycling, running, climbing...)</string> <string name="trackdetails_category">Activity Type (e.g. hiking, cycling, running, climbing...)</string>
<string name="trackdetails_category_hint">Activity Type</string>
<!-- MyTracks Waypoint Details --> <!-- MyTracks Waypoint Details -->
<string name="waypointdetails_title">Marker Details</string> <string name="waypointdetails_title">Marker Details</string>
<string name="waypointdetails_name">Marker Name</string> <string name="waypointdetails_name">Marker Name</string>
<string name="waypointdetails_name_hint">Marker Name</string>
<string name="waypointdetails_description">Marker Description</string> <string name="waypointdetails_description">Marker Description</string>
<string name="waypointdetails_description_hint">Marker Description</string>
<string name="waypointdetails_category">Marker Type (e.g. Building, Pothole, Sight...)</string> <string name="waypointdetails_category">Marker Type (e.g. Building, Pothole, Sight...)</string>
<string name="waypointdetails_category_hint">Marker Type</string>
<!-- MyTracks Settings --> <!-- MyTracks Settings -->
<string name="mytracks_settings">My Tracks Settings</string> <string name="mytracks_settings">My Tracks Settings</string>
@@ -383,6 +390,7 @@ limitations under the License.
<string name="revolutions_per_minute">rpm</string> <string name="revolutions_per_minute">rpm</string>
<string name="bpm">bpm</string> <string name="bpm">bpm</string>
<string name="battery_level">Battery Level</string>
<!-- Stats Labels --> <!-- Stats Labels -->
<string name="moving_time_label">Moving Time</string> <string name="moving_time_label">Moving Time</string>
+18
View File
@@ -85,4 +85,22 @@ limitations under the License.
<style name="WidgetText.Register"> <style name="WidgetText.Register">
<item name="android:width">160px</item> <item name="android:width">160px</item>
</style> </style>
<!-- The style for the buttons on the bottom of a dialog. -->
<style name="DialogButton">
<item name="android:layout_height">48dip</item>
<item name="android:layout_weight">1</item>
<item name="android:layout_width">0dip</item>
<item name="android:maxLines">2</item>
<item name="android:textSize">14dip</item>
</style>
<!-- The style for the spacer on the left and right of the dialog buttons. -->
<style name="DialogButtonSpacer">
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">0.25</item>
<item name="android:layout_width">0dip</item>
<item name="android:orientation">horizontal</item>
<item name="android:visibility">gone</item>
</style>
</resources> </resources>
+2 -1
View File
@@ -18,7 +18,8 @@ limitations under the License.
xmlns:android="http://schemas.android.com/apk/res/android"> xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Display settings --> <!-- Display settings -->
<PreferenceScreen android:title="@string/settings_display"> <PreferenceScreen android:title="@string/settings_display"
android:key="@string/display_settings_screen_key">
<CheckBoxPreference <CheckBoxPreference
android:key="@string/metric_units_key" android:key="@string/metric_units_key"
android:title="@string/settings_metric_units" android:title="@string/settings_metric_units"
@@ -25,6 +25,7 @@ import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import java.util.Locale; import java.util.Locale;
/** /**
@@ -79,6 +80,8 @@ class CheckUnits {
private static void accept(Context context, SharedPreferences preferences) { private static void accept(Context context, SharedPreferences preferences) {
recordCheckPerformed(preferences); recordCheckPerformed(preferences);
Intent startIntent = new Intent(context, SettingsActivity.class); Intent startIntent = new Intent(context, SettingsActivity.class);
startIntent.putExtra(context.getString(R.string.open_settings_screen),
context.getString(R.string.display_settings_screen_key));
context.startActivity(startIntent); context.startActivity(startIntent);
} }
@@ -39,32 +39,21 @@ public abstract class Constants {
public static final int GET_LOGIN = 0; public static final int GET_LOGIN = 0;
public static final int GET_MAP = 1; public static final int GET_MAP = 1;
public static final int CREATE_MAP = 2; public static final int SHOW_TRACK = 2;
public static final int SHOW_TRACK = 3; public static final int AUTHENTICATE_TO_MY_MAPS = 3;
public static final int ADD_LIST = 4; public static final int AUTHENTICATE_TO_FUSION_TABLES = 4;
public static final int FEATURE_DETAILS = 5; public static final int AUTHENTICATE_TO_DOCLIST = 5;
public static final int START_RECORDING = 6; public static final int AUTHENTICATE_TO_TRIX = 6;
public static final int STOP_RECORDING = 7; public static final int SHARE_GPX_FILE = 7;
public static final int AUTHENTICATE_TO_MY_MAPS = 8; public static final int SHARE_KML_FILE = 8;
public static final int AUTHENTICATE_TO_FUSION_TABLES = 9; public static final int SHARE_CSV_FILE = 9;
public static final int AUTHENTICATE_TO_DOCLIST = 10; public static final int SHARE_TCX_FILE = 10;
public static final int AUTHENTICATE_TO_TRIX = 11; public static final int SAVE_GPX_FILE = 11;
public static final int DELETE_TRACK = 13; public static final int SAVE_KML_FILE = 12;
public static final int SEND_TO_GOOGLE = 14; public static final int SAVE_CSV_FILE = 13;
public static final int SHARE_LINK = 15; public static final int SAVE_TCX_FILE = 14;
public static final int SHARE_GPX_FILE = 16; public static final int SHOW_WAYPOINT = 15;
public static final int SHARE_KML_FILE = 17; public static final int WELCOME = 16;
public static final int SHARE_CSV_FILE = 18;
public static final int SHARE_TCX_FILE = 19;
public static final int EDIT_DETAILS = 20;
public static final int SAVE_GPX_FILE = 21;
public static final int SAVE_KML_FILE = 22;
public static final int SAVE_CSV_FILE = 23;
public static final int SAVE_TCX_FILE = 24;
public static final int CLEAR_MAP = 25;
public static final int SHOW_WAYPOINT = 26;
public static final int EDIT_WAYPOINT = 27;
public static final int WELCOME = 28;
/* /*
* Menu ids: * Menu ids:
@@ -189,14 +178,6 @@ public abstract class Constants {
public static int getActionFromMenuId(int menuId) { public static int getActionFromMenuId(int menuId) {
switch (menuId) { switch (menuId) {
case Constants.MENU_SEND_TO_GOOGLE:
return Constants.SEND_TO_GOOGLE;
case Constants.MENU_EDIT:
return Constants.EDIT_DETAILS;
case Constants.MENU_DELETE:
return Constants.DELETE_TRACK;
case Constants.MENU_SHARE_LINK:
return Constants.SHARE_LINK;
case Constants.MENU_SHARE_KML_FILE: case Constants.MENU_SHARE_KML_FILE:
return Constants.SHARE_KML_FILE; return Constants.SHARE_KML_FILE;
case Constants.MENU_SHARE_GPX_FILE: case Constants.MENU_SHARE_GPX_FILE:
@@ -213,15 +194,13 @@ public abstract class Constants {
return Constants.SAVE_CSV_FILE; return Constants.SAVE_CSV_FILE;
case Constants.MENU_SAVE_TCX_FILE: case Constants.MENU_SAVE_TCX_FILE:
return Constants.SAVE_TCX_FILE; return Constants.SAVE_TCX_FILE;
case Constants.MENU_CLEAR_MAP:
return Constants.CLEAR_MAP;
default: default:
return -1; return -1;
} }
} }
public static final String MAPSHOP_BASE_URL = public static final String MAPSHOP_BASE_URL =
"http://maps.google.com/maps/ms"; "https://maps.google.com/maps/ms";
/* /*
* Default values - keep in sync with those in preferences.xml. * Default values - keep in sync with those in preferences.xml.
@@ -0,0 +1,114 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.apps.mytracks.util.UriUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ContentUris;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
/**
* Activity used to delete a track.
*
* @author Rodrigo Damazio
*/
public class DeleteTrack extends Activity
implements DialogInterface.OnClickListener, OnCancelListener {
private static final int CONFIRM_DIALOG = 1;
private MyTracksProviderUtils providerUtils;
private long deleteTrackId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
providerUtils = MyTracksProviderUtils.Factory.get(this);
Intent intent = getIntent();
String action = intent.getAction();
Uri data = intent.getData();
if (!Intent.ACTION_DELETE.equals(action) ||
!UriUtils.matchesContentUri(data, TracksColumns.CONTENT_URI)) {
Log.e(TAG, "Got bad delete intent: " + intent);
finish();
}
deleteTrackId = ContentUris.parseId(data);
showDialog(CONFIRM_DIALOG);
}
@Override
protected Dialog onCreateDialog(int id) {
if (id != CONFIRM_DIALOG) {
Log.e(TAG, "Unknown dialog " + id);
return null;
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(getString(R.string.track_will_be_permanently_deleted));
builder.setTitle(getString(R.string.are_you_sure_question));
builder.setIcon(android.R.drawable.ic_dialog_alert);
builder.setPositiveButton(getString(R.string.yes), this);
builder.setNegativeButton(getString(R.string.no), this);
builder.setOnCancelListener(this);
return builder.create();
}
@Override
public void onClick(DialogInterface dialogInterface, int which) {
dialogInterface.dismiss();
if (which == DialogInterface.BUTTON_POSITIVE) {
deleteTrack();
}
finish();
}
@Override
public void onCancel(DialogInterface dialog) {
onClick(dialog, DialogInterface.BUTTON_NEGATIVE);
}
private void deleteTrack() {
providerUtils.deleteTrack(deleteTrackId);
// If the track we just deleted was selected, unselect it.
String selectedKey = getString(R.string.selected_track_key);
SharedPreferences preferences = getSharedPreferences(Constants.SETTINGS_NAME, 0);
if (preferences.getLong(selectedKey, -1) == deleteTrackId) {
Editor editor = preferences.edit().putLong(selectedKey, -1);
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(editor);
}
}
}
@@ -95,6 +95,15 @@ public class ImportAllTracks {
Log.i(Constants.TAG, "ImportAllTracks: Releasing wake lock."); Log.i(Constants.TAG, "ImportAllTracks: Releasing wake lock.");
} }
activity.runOnUiThread(new Thread() {
@Override
public void run() {
showDoneDialog();
}
});
}
private void showDoneDialog() {
Log.i(Constants.TAG, "ImportAllTracks: Done"); Log.i(Constants.TAG, "ImportAllTracks: Done");
AlertDialog.Builder builder = new AlertDialog.Builder(activity); AlertDialog.Builder builder = new AlertDialog.Builder(activity);
if (gpxFileCount == 0) { if (gpxFileCount == 0) {
@@ -22,6 +22,7 @@ import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.content.TrackDataHub; import com.google.android.apps.mytracks.content.TrackDataHub;
import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType; import com.google.android.apps.mytracks.content.TrackDataHub.ListenerDataType;
import com.google.android.apps.mytracks.content.TrackDataListener; import com.google.android.apps.mytracks.content.TrackDataListener;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.content.Waypoint; import com.google.android.apps.mytracks.content.Waypoint;
import com.google.android.apps.mytracks.io.file.SaveActivity; import com.google.android.apps.mytracks.io.file.SaveActivity;
import com.google.android.apps.mytracks.io.sendtogoogle.SendActivity; import com.google.android.apps.mytracks.io.sendtogoogle.SendActivity;
@@ -35,8 +36,10 @@ import com.google.android.maps.MapController;
import com.google.android.maps.MapView; import com.google.android.maps.MapView;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import android.content.ContentUris;
import android.content.Intent; import android.content.Intent;
import android.location.Location; import android.location.Location;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.provider.Settings; import android.provider.Settings;
import android.util.Log; import android.util.Log;
@@ -412,6 +415,23 @@ public class MapActivity extends com.google.android.maps.MapActivity
SaveActivity.handleExportTrackAction(this, dataHub.getSelectedTrackId(), SaveActivity.handleExportTrackAction(this, dataHub.getSelectedTrackId(),
Constants.getActionFromMenuId(item.getItemId())); Constants.getActionFromMenuId(item.getItemId()));
return true; return true;
case Constants.MENU_EDIT: {
Intent intent = new Intent(this, TrackDetails.class);
// TODO: Pass in a content URI
intent.putExtra("trackid", dataHub.getSelectedTrackId());
startActivity(intent);
return true;
}
case Constants.MENU_DELETE: {
Uri uri = ContentUris.withAppendedId(
TracksColumns.CONTENT_URI, dataHub.getSelectedTrackId());
Intent intent = new Intent(Intent.ACTION_DELETE, uri);
startActivity(intent);
return true;
}
case Constants.MENU_CLEAR_MAP:
dataHub.unloadCurrentTrack();
return true;
default: default:
return super.onMenuItemSelected(featureId, item); return super.onMenuItemSelected(featureId, item);
} }
@@ -86,10 +86,6 @@ class MenuManager {
case R.id.menu_help: { case R.id.menu_help: {
return startActivity(WelcomeActivity.class); return startActivity(WelcomeActivity.class);
} }
case Constants.MENU_CLEAR_MAP: {
activity.clearSelectedTrack();
return true;
}
} }
return false; return false;
} }
@@ -33,10 +33,8 @@ import com.google.android.apps.mytracks.util.UriUtils;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog;
import android.app.TabActivity; import android.app.TabActivity;
import android.content.ContentUris; import android.content.ContentUris;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Resources; import android.content.res.Resources;
@@ -61,6 +59,7 @@ import android.widget.Toast;
* @author Leif Hendrik Wilden * @author Leif Hendrik Wilden
* @author Rodrigo Damazio * @author Rodrigo Damazio
*/ */
@SuppressWarnings("deprecation")
public class MyTracks extends TabActivity implements OnTouchListener { public class MyTracks extends TabActivity implements OnTouchListener {
private TrackDataHub dataHub; private TrackDataHub dataHub;
@@ -314,7 +313,7 @@ public class MyTracks extends TabActivity implements OnTouchListener {
dataHub.loadTrack(trackId); dataHub.loadTrack(trackId);
// The track list passed the requested action as result code. Hand // The track list passed the requested action as result code. Hand
// it off to the onAcitivtyResult for further processing: // it off to the onActivityResult for further processing:
if (resultCode != Constants.SHOW_TRACK) { if (resultCode != Constants.SHOW_TRACK) {
onActivityResult(resultCode, Activity.RESULT_OK, results); onActivityResult(resultCode, Activity.RESULT_OK, results);
} }
@@ -336,24 +335,6 @@ public class MyTracks extends TabActivity implements OnTouchListener {
} }
break; break;
} }
case Constants.DELETE_TRACK: {
if (results != null && resultCode == RESULT_OK) {
deleteTrack(trackId);
}
break;
}
case Constants.EDIT_DETAILS: {
if (results != null && resultCode == RESULT_OK) {
Intent intent = new Intent(this, TrackDetails.class);
intent.putExtra("trackid", trackId);
startActivity(intent);
}
break;
}
case Constants.CLEAR_MAP: {
dataHub.unloadCurrentTrack();
break;
}
case Constants.WELCOME: { case Constants.WELCOME: {
CheckUnits.check(this); CheckUnits.check(this);
break; break;
@@ -373,36 +354,6 @@ public class MyTracks extends TabActivity implements OnTouchListener {
return false; return false;
} }
/**
* Deletes the track with the given id.
* Prompts the user if he want to really delete the track first.
* If the selected track is deleted, the selection will be removed.
*/
public void deleteTrack(final long trackId) {
AlertDialog dialog = null;
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(getString(R.string.track_will_be_permanently_deleted));
builder.setTitle(getString(R.string.are_you_sure_question));
builder.setIcon(android.R.drawable.ic_dialog_alert);
builder.setPositiveButton(getString(R.string.yes),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
providerUtils.deleteTrack(trackId);
if (trackId == dataHub.getSelectedTrackId()) {
dataHub.unloadCurrentTrack();
}
}});
builder.setNegativeButton(getString(R.string.no),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
});
dialog = builder.create();
dialog.show();
}
/** /**
* Inserts a waypoint marker. * Inserts a waypoint marker.
* *
@@ -493,10 +444,6 @@ public class MyTracks extends TabActivity implements OnTouchListener {
} }
} }
void clearSelectedTrack() {
dataHub.unloadCurrentTrack();
}
long getSelectedTrackId() { long getSelectedTrackId() {
return dataHub.getSelectedTrackId(); return dataHub.getSelectedTrackId();
} }
@@ -160,6 +160,7 @@ public class SensorStateActivity extends Activity {
utils.setUnknown(R.id.cadence_state_register); utils.setUnknown(R.id.cadence_state_register);
utils.setUnknown(R.id.power_state_register); utils.setUnknown(R.id.power_state_register);
utils.setUnknown(R.id.heart_rate_register); utils.setUnknown(R.id.heart_rate_register);
utils.setUnknown(R.id.battery_level_register);
return; return;
} }
@@ -206,5 +207,18 @@ public class SensorStateActivity extends Activity {
: Sensor.SensorState.NONE, : Sensor.SensorState.NONE,
this)); this));
} }
if (sds.hasBatteryLevel() && sds.getBatteryLevel().hasValue()
&& sds.getBatteryLevel().getState() == Sensor.SensorState.SENDING) {
utils.setText(R.id.battery_level_register,
Integer.toString(sds.getBatteryLevel().getValue()));
} else {
utils.setText(R.id.battery_level_register,
SensorUtils.getStateAsString(
sds.hasBatteryLevel()
? sds.getBatteryLevel().getState()
: Sensor.SensorState.NONE,
this));
}
} }
} }
@@ -51,6 +51,10 @@ import java.util.Set;
/** /**
* An activity that let's the user see and edit the settings. * An activity that let's the user see and edit the settings.
* *
* This activity has two entry points, "root" and "display" preference screen.
* If bundle.getString("open_settings_screen") is set to "display_settings_screen_key", then
* the "display" preference screen is shown, otherwise, the "root" display preference is shown.
*
* @author Leif Hendrik Wilden * @author Leif Hendrik Wilden
* @author Rodrigo Damazio * @author Rodrigo Damazio
*/ */
@@ -64,6 +68,16 @@ public class SettingsActivity extends PreferenceActivity {
protected void onCreate(Bundle icicle) { protected void onCreate(Bundle icicle) {
super.onCreate(icicle); super.onCreate(icicle);
initActivityCommons();
// If we only need the display setting screen nothing else needs to load.
if (processIntent())
return;
initActivitySpecifics();
}
private void initActivityCommons() {
// The volume we want to control is the Text-To-Speech volume // The volume we want to control is the Text-To-Speech volume
ApiFeatures apiFeatures = ApiFeatures.getInstance(); ApiFeatures apiFeatures = ApiFeatures.getInstance();
int volumeStream = int volumeStream =
@@ -83,6 +97,19 @@ public class SettingsActivity extends PreferenceActivity {
// Load the preferences to be displayed // Load the preferences to be displayed
addPreferencesFromResource(R.xml.preferences); addPreferencesFromResource(R.xml.preferences);
// Disable TTS announcement preference if not available
if (!apiFeatures.hasTextToSpeech()) {
IntegerListPreference announcementFrequency =
(IntegerListPreference) findPreference(
getString(R.string.announcement_frequency_key));
announcementFrequency.setEnabled(false);
announcementFrequency.setValue("-1");
announcementFrequency.setSummary(
R.string.settings_not_available_summary);
}
}
private void initActivitySpecifics() {
// Hook up switching of displayed list entries between metric and imperial // Hook up switching of displayed list entries between metric and imperial
// units // units
CheckBoxPreference metricUnitsPreference = CheckBoxPreference metricUnitsPreference =
@@ -102,17 +129,6 @@ public class SettingsActivity extends PreferenceActivity {
customizeSensorOptionsPreferences(); customizeSensorOptionsPreferences();
// Disable TTS announcement preference if not available
if (!apiFeatures.hasTextToSpeech()) {
IntegerListPreference announcementFrequency =
(IntegerListPreference) findPreference(
getString(R.string.announcement_frequency_key));
announcementFrequency.setEnabled(false);
announcementFrequency.setValue("-1");
announcementFrequency.setSummary(
R.string.settings_not_available_summary);
}
// Hook up action for resetting all settings // Hook up action for resetting all settings
Preference resetPreference = findPreference(getString(R.string.reset_key)); Preference resetPreference = findPreference(getString(R.string.reset_key));
resetPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() { resetPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@@ -124,6 +140,23 @@ public class SettingsActivity extends PreferenceActivity {
}); });
} }
private boolean processIntent() {
boolean showDisplaySettings = false;
Bundle bundle = getIntent().getExtras();
PreferenceScreen preferenceScreen;
String intentString = getString(R.string.open_settings_screen);
if (bundle != null) {
preferenceScreen = (PreferenceScreen) findPreference(bundle.getString(intentString));
if (preferenceScreen != null) {
showDisplaySettings = true;
setPreferenceScreen(preferenceScreen);
}
}
return showDisplaySettings;
}
private void customizeSensorOptionsPreferences() { private void customizeSensorOptionsPreferences() {
ListPreference sensorTypePreference = ListPreference sensorTypePreference =
(ListPreference) findPreference(getString(R.string.sensor_type_key)); (ListPreference) findPreference(getString(R.string.sensor_type_key));
@@ -175,6 +208,10 @@ public class SettingsActivity extends PreferenceActivity {
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
// If we only need the display setting screen nothing else needs to load.
if (processIntent())
return;
configureBluetoothPreferences(); configureBluetoothPreferences();
Preference backupNowPreference = Preference backupNowPreference =
findPreference(getString(R.string.backup_to_sd_key)); findPreference(getString(R.string.backup_to_sd_key));
@@ -15,6 +15,8 @@
*/ */
package com.google.android.apps.mytracks; package com.google.android.apps.mytracks;
import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.content.TracksColumns; import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.apps.mytracks.io.file.SaveActivity; import com.google.android.apps.mytracks.io.file.SaveActivity;
import com.google.android.apps.mytracks.io.sendtogoogle.SendActivity; import com.google.android.apps.mytracks.io.sendtogoogle.SendActivity;
@@ -25,11 +27,14 @@ import com.google.android.apps.mytracks.util.UnitConversions;
import com.google.android.maps.mytracks.R; import com.google.android.maps.mytracks.R;
import android.app.ListActivity; import android.app.ListActivity;
import android.content.ContentUris;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.util.Log;
import android.view.ContextMenu; import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo; import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuItem; import android.view.MenuItem;
@@ -182,14 +187,16 @@ public class TrackList extends ListActivity
SaveActivity.handleExportTrackAction(this, trackId, SaveActivity.handleExportTrackAction(this, trackId,
Constants.getActionFromMenuId(item.getItemId())); Constants.getActionFromMenuId(item.getItemId()));
return true; return true;
default: { case Constants.MENU_DELETE: {
Intent result = new Intent(); Intent intent = new Intent(Intent.ACTION_DELETE);
result.putExtra("trackid", trackId); Uri uri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId);
setResult( intent.setDataAndType(uri, TracksColumns.CONTENT_ITEMTYPE);
Constants.getActionFromMenuId(item.getItemId()), result); startActivity(intent);
finish();
return true; return true;
} }
default:
Log.w(TAG, "Unknown menu item: " + item.getItemId() + "(" + item.getTitle() + ")");
return super.onMenuItemSelected(featureId, item);
} }
} }
@@ -28,6 +28,7 @@ import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView; import android.widget.AutoCompleteTextView;
import android.widget.Button; import android.widget.Button;
@@ -139,6 +140,7 @@ public class WaypointDetails extends Activity
utils.setAllStats(waypointStats); utils.setAllStats(waypointStats);
utils.setAltitude( utils.setAltitude(
R.id.elevation_register, waypoint.getLocation().getAltitude()); R.id.elevation_register, waypoint.getLocation().getAltitude());
name.setImeOptions(EditorInfo.IME_ACTION_DONE);
break; break;
} }
icon.setImageDrawable(getResources().getDrawable(iconId)); icon.setImageDrawable(getResources().getDrawable(iconId));
@@ -96,11 +96,7 @@ public class WaypointsList extends ListActivity
@Override @Override
protected void onListItemClick(ListView l, View v, int position, long id) { protected void onListItemClick(ListView l, View v, int position, long id) {
Intent result = new Intent(); editWaypoint(id);
result.putExtra("trackid", trackId);
result.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, id);
setResult(Constants.EDIT_WAYPOINT, result);
finish();
} }
@Override @Override
@@ -108,14 +104,15 @@ public class WaypointsList extends ListActivity
if (!super.onMenuItemSelected(featureId, item)) { if (!super.onMenuItemSelected(featureId, item)) {
switch (item.getItemId()) { switch (item.getItemId()) {
case Constants.MENU_SHOW: { case Constants.MENU_SHOW: {
onListItemClick(null, null, 0, selectedWaypointId); Intent result = new Intent();
result.putExtra("trackid", trackId);
result.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, selectedWaypointId);
setResult(RESULT_OK, result);
finish();
return true; return true;
} }
case Constants.MENU_EDIT: { case Constants.MENU_EDIT: {
Intent intent = new Intent(this, WaypointDetails.class); editWaypoint(selectedWaypointId);
intent.putExtra("trackid", trackId);
intent.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, selectedWaypointId);
startActivity(intent);
return true; return true;
} }
case Constants.MENU_DELETE: { case Constants.MENU_DELETE: {
@@ -126,6 +123,13 @@ public class WaypointsList extends ListActivity
return false; return false;
} }
private void editWaypoint(long waypointId) {
Intent intent = new Intent(this, WaypointDetails.class);
intent.putExtra("trackid", trackId);
intent.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, waypointId);
startActivity(intent);
}
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@@ -412,10 +412,10 @@ public class TrackDataHub {
return; return;
} }
// Save the selection to memory and flash. // Save the selection to memory and flush.
selectedTrackId = trackId;
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges( ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
preferences.edit().putLong(SELECTED_TRACK_KEY, trackId)); preferences.edit().putLong(SELECTED_TRACK_KEY, trackId));
selectedTrackId = trackId;
// Force it to reload data from the beginning. // Force it to reload data from the beginning.
Log.d(TAG, "Loading track"); Log.d(TAG, "Loading track");
@@ -642,6 +642,9 @@ public class TrackDataHub {
} else if (SPEED_REPORTING_KEY.equals(key)) { } else if (SPEED_REPORTING_KEY.equals(key)) {
reportSpeed = preferences.getBoolean(SPEED_REPORTING_KEY, true); reportSpeed = preferences.getBoolean(SPEED_REPORTING_KEY, true);
notifySpeedReportingChanged(); notifySpeedReportingChanged();
} else if (SELECTED_TRACK_KEY.equals(key)) {
long trackId = preferences.getLong(SELECTED_TRACK_KEY, -1);
loadTrack(trackId);
} }
} }
@@ -16,6 +16,7 @@
package com.google.android.apps.mytracks.io; package com.google.android.apps.mytracks.io;
import static com.google.android.apps.mytracks.Constants.TAG; import static com.google.android.apps.mytracks.Constants.TAG;
import com.google.android.apps.mytracks.Constants; import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.ProgressIndicator; import com.google.android.apps.mytracks.ProgressIndicator;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils; import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
@@ -50,7 +51,6 @@ import android.util.Log;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@@ -76,13 +76,13 @@ public class SendToFusionTables implements Runnable {
/** The path for viewing a map visualization of a table. */ /** The path for viewing a map visualization of a table. */
private static final String FUSIONTABLES_MAP = private static final String FUSIONTABLES_MAP =
"http://www.google.com/fusiontables/embedviz?" + "https://www.google.com/fusiontables/embedviz?" +
"viz=MAP&q=select+col0,+col1,+col2,+col3+from+%s+&h=false&" + "viz=MAP&q=select+col0,+col1,+col2,+col3+from+%s+&h=false&" +
"lat=%f&lng=%f&z=%d&t=1&l=col2"; "lat=%f&lng=%f&z=%d&t=1&l=col2";
/** Standard base feed url for Fusion Tables. */ /** Standard base feed url for Fusion Tables. */
private static final String FUSIONTABLES_BASE_FEED_URL = private static final String FUSIONTABLES_BASE_FEED_URL =
"http://www.google.com/fusiontables/api/query"; "https://www.google.com/fusiontables/api/query";
private static final int MAX_POINTS_PER_UPLOAD = 2048; private static final int MAX_POINTS_PER_UPLOAD = 2048;
@@ -695,7 +695,7 @@ public class SendToFusionTables implements Runnable {
if (success) { if (success) {
byte[] result = new byte[1024]; byte[] result = new byte[1024];
int read = response.getContent().read(result); int read = response.getContent().read(result);
String s = new String(result, 0, read, Charset.forName("UTF8")); String s = new String(result, 0, read, "UTF8");
String[] lines = s.split(Strings.LINE_SEPARATOR); String[] lines = s.split(Strings.LINE_SEPARATOR);
if (lines[0].equals("tableid")) { if (lines[0].equals("tableid")) {
tableId = lines[1]; tableId = lines[1];
@@ -44,6 +44,8 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.text.DateFormat;
import java.util.Date;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
/** /**
@@ -55,15 +57,15 @@ import java.util.concurrent.atomic.AtomicReference;
*/ */
public class DocsHelper { public class DocsHelper {
private static final String DOCS_FEED_URL = private static final String DOCS_FEED_URL =
"http://docs.google.com/feeds/documents/private/full"; "https://docs.google.com/feeds/documents/private/full";
private static final String DOCS_SPREADSHEET_URL = private static final String DOCS_SPREADSHEET_URL =
"http://docs.google.com/feeds/documents/private/full/spreadsheet%3A"; "https://docs.google.com/feeds/documents/private/full/spreadsheet%3A";
private static final String DOCS_WORKSHEETS_URL_FORMAT = private static final String DOCS_WORKSHEETS_URL_FORMAT =
"http://spreadsheets.google.com/feeds/worksheets/%s/private/full"; "https://spreadsheets.google.com/feeds/worksheets/%s/private/full";
private static final String DOCS_MY_SPREADSHEETS_FEED_URL = private static final String DOCS_MY_SPREADSHEETS_FEED_URL =
"http://docs.google.com/feeds/documents/private/full?category=mine,spreadsheet"; "https://docs.google.com/feeds/documents/private/full?category=mine,spreadsheet";
private static final String DOCS_SPREADSHEET_URL_FORMAT = private static final String DOCS_SPREADSHEET_URL_FORMAT =
"http://spreadsheets.google.com/feeds/list/%s/%s/private/full"; "https://spreadsheets.google.com/feeds/list/%s/%s/private/full";
private static final String CONTENT_TYPE_PARAM = "Content-Type"; private static final String CONTENT_TYPE_PARAM = "Content-Type";
private static final String OPENDOCUMENT_SPREADSHEET_MIME_TYPE = private static final String OPENDOCUMENT_SPREADSHEET_MIME_TYPE =
@@ -285,11 +287,13 @@ public class DocsHelper {
String elevationUnit = context.getString(metricUnits ? String elevationUnit = context.getString(metricUnits ?
R.string.meter : R.string.feet); R.string.meter : R.string.feet);
DateFormat trackDateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
// Prepare the Post-Text we are going to send. // Prepare the Post-Text we are going to send.
DocsTagBuilder tagBuilder = new DocsTagBuilder(metricUnits) DocsTagBuilder tagBuilder = new DocsTagBuilder(metricUnits)
.append("name", track.getName()) .append("name", track.getName())
.append("description", track.getDescription()) .append("description", track.getDescription())
.append("date", String.format("%tc", stats.getStartTime())) .append("date", trackDateFormat.format(new Date(stats.getStartTime())))
.append("totaltime", StringUtils.formatTimeAlwaysShowingHours( .append("totaltime", StringUtils.formatTimeAlwaysShowingHours(
stats.getTotalTime())) stats.getTotalTime()))
.append("movingtime", StringUtils.formatTimeAlwaysShowingHours( .append("movingtime", StringUtils.formatTimeAlwaysShowingHours(
@@ -19,7 +19,9 @@ import com.google.android.apps.mytracks.util.StringUtils;
import com.google.android.apps.mytracks.util.UnitConversions; import com.google.android.apps.mytracks.util.UnitConversions;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.Locale;
/** /**
* <p>This class builds a string of XML tags used to talk to Docs using GData. * <p>This class builds a string of XML tags used to talk to Docs using GData.
@@ -43,12 +45,12 @@ import java.text.NumberFormat;
* @author Matthew Simmons * @author Matthew Simmons
*/ */
class DocsTagBuilder { class DocsTagBuilder {
// TODO(simmonmt): These formats aren't I18N-compatible. Not everyone uses private static final DecimalFormatSymbols FORMAT_SYMBOLS =
// commas for thousands and dots for the decimal point. DecimalFormatSymbols.getInstance(Locale.ENGLISH);
private static final NumberFormat LARGE_UNIT_FORMAT = private static final NumberFormat LARGE_UNIT_FORMAT =
new DecimalFormat("#,###,###.00"); new DecimalFormat("#,###,###.00", FORMAT_SYMBOLS);
private static final NumberFormat SMALL_UNIT_FORMAT = private static final NumberFormat SMALL_UNIT_FORMAT =
new DecimalFormat("###,###"); new DecimalFormat("###,###", FORMAT_SYMBOLS);
protected final boolean metricUnits; protected final boolean metricUnits;
protected final StringBuilder stringBuilder; protected final StringBuilder stringBuilder;
@@ -59,7 +61,7 @@ class DocsTagBuilder {
*/ */
DocsTagBuilder(boolean metricUnits) { DocsTagBuilder(boolean metricUnits) {
this.metricUnits = metricUnits; this.metricUnits = metricUnits;
stringBuilder = new StringBuilder(); this.stringBuilder = new StringBuilder();
} }
/** Appends a tag containing a string value */ /** Appends a tag containing a string value */
@@ -44,6 +44,7 @@ import java.util.TimeZone;
* Garmin Training Center 3.5.3. * Garmin Training Center 3.5.3.
* *
* @author Sandor Dornbush * @author Sandor Dornbush
* @author Dominik Ršttsches
*/ */
public class TcxTrackWriter implements TrackFormatWriter { public class TcxTrackWriter implements TrackFormatWriter {
protected static final String TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; protected static final String TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
@@ -64,6 +65,9 @@ public class TcxTrackWriter implements TrackFormatWriter {
private PrintWriter pw = null; private PrintWriter pw = null;
private Track track; private Track track;
// Determines whether to encode cadence value as running or cycling cadence.
private boolean sportIsCycling;
public TcxTrackWriter(Context context) { public TcxTrackWriter(Context context) {
this.context = context; this.context = context;
@@ -76,7 +80,7 @@ public class TcxTrackWriter implements TrackFormatWriter {
public void prepare(Track track, OutputStream out) { public void prepare(Track track, OutputStream out) {
this.track = track; this.track = track;
this.pw = new PrintWriter(out); this.pw = new PrintWriter(out);
this.sportIsCycling = categoryToTcxSport(track.getCategory()).equals(TCX_SPORT_BIKING);
} }
@Override @Override
@@ -174,22 +178,44 @@ public class TcxTrackWriter implements TrackFormatWriter {
pw.print("</Value>"); pw.print("</Value>");
pw.println("</HeartRateBpm>"); pw.println("</HeartRateBpm>");
} }
// TCX Trackpoint_t contains a sequence, <Cadence> needs to be put before <Extensions>
if (sensorData.hasCadence() boolean cadenceAvailable = sensorData.hasCadence()
&& sensorData.getCadence().getState() == Sensor.SensorState.SENDING && sensorData.getCadence().getState() == Sensor.SensorState.SENDING
&& sensorData.getCadence().hasValue()) { && sensorData.getCadence().hasValue();
// TCX Trackpoint_t contains a sequence. Thus, the legacy XML element
// <Cadence> needs to be put before <Extensions>.
// This field should only be used for the case that activity was marked as biking.
// Otherwise cadence is interpreted as running cadence data which
// is written in the <Extensions> as <RunCadence>.
if (sportIsCycling && cadenceAvailable) {
pw.print(" <Cadence>"); pw.print(" <Cadence>");
pw.print(Math.min(254, sensorData.getCadence().getValue())); pw.print(Math.min(254, sensorData.getCadence().getValue()));
pw.println("</Cadence>"); pw.println("</Cadence>");
} }
if (sensorData.hasPower()
&& sensorData.getPower().getState() == Sensor.SensorState.SENDING boolean powerAvailable = sensorData.hasPower()
&& sensorData.getPower().hasValue()) { && sensorData.getPower().getState() == Sensor.SensorState.SENDING
&& sensorData.getPower().hasValue();
if(powerAvailable || (!sportIsCycling && cadenceAvailable)) {
pw.print(" <Extensions>"); pw.print(" <Extensions>");
pw.print("<TPX xmlns=\"http://www.garmin.com/xmlschemas/ActivityExtension/v2\">"); pw.print("<TPX xmlns=\"http://www.garmin.com/xmlschemas/ActivityExtension/v2\">");
pw.print("<Watts>");
pw.print(sensorData.getPower().getValue()); // RunCadence needs to be put before power in order to be understood
pw.print("</Watts>"); // by Garmin Training Center.
if (!sportIsCycling && cadenceAvailable) {
pw.print("<RunCadence>");
pw.print(Math.min(254, sensorData.getCadence().getValue()));
pw.print("</RunCadence>");
}
if (powerAvailable) {
pw.print("<Watts>");
pw.print(sensorData.getPower().getValue());
pw.print("</Watts>");
}
pw.println("</TPX></Extensions>"); pw.println("</TPX></Extensions>");
} }
} }
@@ -7,7 +7,7 @@ package com.google.android.apps.mytracks.io.mymaps;
public class MyMapsConstants { public class MyMapsConstants {
static final String TAG = "MapsApi"; static final String TAG = "MapsApi";
static final String MAPSHOP_BASE_URL = static final String MAPSHOP_BASE_URL =
"http://maps.google.com/maps/ms"; "https://maps.google.com/maps/ms";
public static final String SERVICE_NAME = "local"; public static final String SERVICE_NAME = "local";
/** /**
@@ -153,6 +153,9 @@ public class TrackRecordingService extends Service {
@Override @Override
public void onLocationChanged(final Location location) { public void onLocationChanged(final Location location) {
if (executorService.isShutdown() || executorService.isTerminated()) {
return;
}
executorService.submit( executorService.submit(
new Runnable() { new Runnable() {
@Override @Override
@@ -342,7 +345,6 @@ public class TrackRecordingService extends Service {
timer.purge(); timer.purge();
unregisterLocationListener(); unregisterLocationListener();
shutdownTaskExecutors(); shutdownTaskExecutors();
executorService.shutdown();
if (sensorManager != null) { if (sensorManager != null) {
sensorManager.shutdown(); sensorManager.shutdown();
sensorManager = null; sensorManager = null;
@@ -358,6 +360,8 @@ public class TrackRecordingService extends Service {
// This should be the last operation. // This should be the last operation.
releaseWakeLock(); releaseWakeLock();
// Shutdown the executor service last to avoid sending events to a dead executor.
executorService.shutdown();
super.onDestroy(); super.onDestroy();
} }
@@ -0,0 +1,80 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.services.sensors;
import java.util.LinkedList;
import java.util.List;
/**
* A history of Zephyr stride counter reading.
* These can be used as an alternate method to calculate the correct cadence.
* This is a work around for an issue with some HxM firmware.
*
* @author Dominik Ršttsches
*/
public class StrideReadings {
// visible for testing
protected static final int NUM_READINGS_FOR_AVERAGE = 10;
protected static final int MIN_READINGS_FOR_AVERAGE = 5;
protected static final int CADENCE_NOT_AVAILABLE = -1;
// TODO: Check whether 1Hz assumption is okay for cadence calculation
// otherwise add heart beat timestamp to this list and compute
// cadence from these timestamps.
private final List<Integer> strideReadingsHistory;
public StrideReadings() {
strideReadingsHistory = new LinkedList<Integer>();
}
public void updateStrideReading(int numStrides) {
// HRM/HxM documentation says, transmission frequency is 1 Hz,
// let's keep last NUM_READINGS_FOR_AVERAGE readings.
// TODO: Calibrate this using a reliable footpod / cadence sensor,
// otherwise use heartbeat timestamp for calculation.
strideReadingsHistory.add(0, numStrides);
while (strideReadingsHistory.size() > NUM_READINGS_FOR_AVERAGE) {
strideReadingsHistory.remove(strideReadingsHistory.size()-1);
}
}
public int getCadence() {
if (strideReadingsHistory.size() < MIN_READINGS_FOR_AVERAGE) {
// Bail out if we cannot really get a meaningful average yet.
return CADENCE_NOT_AVAILABLE;
}
// Compute assuming 1 stride reading/second.
int timeSinceOldestReadingSecs = strideReadingsHistory.size() - 1;
int stridesThen = strideReadingsHistory.get(strideReadingsHistory.size()-1);
int stridesNow = strideReadingsHistory.get(0);
// Contrary to documentation stride value seems to roll over at 128.
return Math.round( (float)(mod((stridesNow - stridesThen), 128)) /
timeSinceOldestReadingSecs * 60);
}
/**
* Modulo operation with positive return values, Java's remainder operator doesn't change sign.
*
* @return x mod y
*/
private static int mod(int x, int y)
{
int result = x % y;
return result < 0 ? result + y : result;
}
}
@@ -1,6 +1,5 @@
/* /*
* Copyright 2010 Google Inc. * Copyright 2010 Google Inc.
* Copyright 2011 Dominik Ršttsches <d.roettsches@gmail.com>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * 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 * use this file except in compliance with the License. You may obtain a copy of
@@ -16,17 +15,15 @@
*/ */
package com.google.android.apps.mytracks.services.sensors; package com.google.android.apps.mytracks.services.sensors;
import com.google.android.apps.mytracks.Constants;
import com.google.android.apps.mytracks.content.Sensor; import com.google.android.apps.mytracks.content.Sensor;
import android.util.Log; import java.util.Arrays;
import java.util.LinkedList;
/** /**
* An implementation of a Sensor MessageParser for Zephyr. * An implementation of a Sensor MessageParser for Zephyr.
* *
* @author Sandor Dornbush * @author Sandor Dornbush
* @author Dominik Ršttsches
*/ */
public class ZephyrMessageParser implements MessageParser { public class ZephyrMessageParser implements MessageParser {
@@ -34,109 +31,55 @@ public class ZephyrMessageParser implements MessageParser {
public static final int ZEPHYR_HXM_BYTE_CRC = 58; public static final int ZEPHYR_HXM_BYTE_CRC = 58;
public static final int ZEPHYR_HXM_BYTE_ETX = 59; public static final int ZEPHYR_HXM_BYTE_ETX = 59;
private static final byte[] CADENCE_BUG_FW_ID = {0x1A, 0x00, 0x31, 0x65, 0x50, 0x00, 0x31, 0x62};
private StrideReadings strideReadings; private StrideReadings strideReadings;
public class StrideReadings {
class StrideReading {
public int timeMs;
public int numStrides;
StrideReading(int newTimeMs, int newNumStrides) {
timeMs = newTimeMs;
numStrides = newNumStrides;
}
}
private LinkedList<StrideReading> strideReadingsHistory;
private static final int NUM_READINGS_FOR_AVERAGE = 10;
private static final int MIN_READINGS_FOR_AVERAGE = 5;
public static final int CADENCE_NOT_AVAILABLE = -1;
public StrideReadings() {
strideReadingsHistory = new LinkedList<StrideReading>();
}
public void updateStrideReading(int timeInMs, int numStrides) {
// HRM/HxM docs say, transmission frequency is 1 Hz,
// let's keep last NUM_READINGS_FOR_AVERAGE readings.
// TODO: Calibrate this using a reliable footpod / cadence sensor,
// otherwise perhaps use heartbeat timestamp for calculation.
strideReadingsHistory.addFirst(new StrideReading(timeInMs, numStrides));
while(strideReadingsHistory.size() > NUM_READINGS_FOR_AVERAGE) {
strideReadingsHistory.removeLast();
}
}
public int getCadence() {
if(strideReadingsHistory.size() < MIN_READINGS_FOR_AVERAGE) {
// Bail out if we cannot really get a meaningful average yet.
return CADENCE_NOT_AVAILABLE;
}
// compute assuming 1 stride reading/second
int timeSinceOldestReadingSecs = strideReadingsHistory.size() - 1;
int stridesThen = strideReadingsHistory.getLast().numStrides;
int stridesNow = strideReadingsHistory.getFirst().numStrides;
// Contrary to documentation stride value seems to roll over every 127 strides.
return Math.round( (float)((stridesNow - stridesThen) % 127) /
timeSinceOldestReadingSecs * 60);
}
}
@Override @Override
public Sensor.SensorDataSet parseBuffer(byte[] buffer) { public Sensor.SensorDataSet parseBuffer(byte[] buffer) {
StringBuilder sb = new StringBuilder(); Sensor.SensorDataSet.Builder sds =
for (int i = 0; i < buffer.length; i++) { Sensor.SensorDataSet.newBuilder()
sb.append(String.format("%02X", buffer[i])); .setCreationTime(System.currentTimeMillis());
}
Log.w(Constants.TAG, "Got zephyr data: " + sb);
// Device Firmware ID, Firmware Version, Hardware ID, Hardware Version
// 0x1A00316550003162 produces erroneous values for Cadence and needs
// a workaround based on the stride counter.
String hardwareFirmwareId = sb.substring(6, 22);
boolean needsWorkaround = hardwareFirmwareId.equals("1A00316550003162");
Log.w(Constants.TAG, "FW & HW Ids & Version " + hardwareFirmwareId + " needs workaround: " + needsWorkaround);
Sensor.SensorData.Builder heartrate = Sensor.SensorData.newBuilder() Sensor.SensorData.Builder heartrate = Sensor.SensorData.newBuilder()
.setValue(buffer[12] & 0xFF) .setValue(buffer[12] & 0xFF)
.setState(Sensor.SensorState.SENDING); .setState(Sensor.SensorState.SENDING);
sds.setHeartRate(heartrate);
Sensor.SensorData.Builder batteryLevel = Sensor.SensorData.newBuilder() Sensor.SensorData.Builder batteryLevel = Sensor.SensorData.newBuilder()
.setValue(buffer[11]) .setValue(buffer[11])
.setState(Sensor.SensorState.SENDING); .setState(Sensor.SensorState.SENDING);
sds.setBatteryLevel(batteryLevel);
setCadence(sds, buffer);
return sds.build();
}
private void setCadence(Sensor.SensorDataSet.Builder sds, byte[] buffer) {
// Device Firmware ID, Firmware Version, Hardware ID, Hardware Version
// 0x1A00316550003162 produces erroneous values for Cadence and needs
// a workaround based on the stride counter.
// Firmware values range from field 3 to 10 (inclusive) of the byte buffer.
byte[] hardwareFirmwareId = Arrays.copyOfRange(buffer, 3, 11);
Sensor.SensorData.Builder cadence = Sensor.SensorData.newBuilder(); Sensor.SensorData.Builder cadence = Sensor.SensorData.newBuilder();
if(!needsWorkaround) { if (Arrays.equals(hardwareFirmwareId, CADENCE_BUG_FW_ID)) {
cadence = cadence if (strideReadings == null) {
.setValue(SensorUtils.unsignedShortToIntLittleEndian(buffer, 56) / 16)
.setState(Sensor.SensorState.SENDING);
} else {
if(strideReadings == null) {
strideReadings = new StrideReadings(); strideReadings = new StrideReadings();
} }
strideReadings.updateStrideReading(buffer[54] & 0xFF);
strideReadings.updateStrideReading( if (strideReadings.getCadence() != StrideReadings.CADENCE_NOT_AVAILABLE) {
SensorUtils.unsignedShortToIntLittleEndian(buffer, 14), cadence.setValue(strideReadings.getCadence()).setState(Sensor.SensorState.SENDING);
buffer[54] & 0xFF);
if(strideReadings.getCadence() != StrideReadings.CADENCE_NOT_AVAILABLE) {
cadence = cadence.setValue(strideReadings.getCadence())
.setState(Sensor.SensorState.SENDING);
} else {
cadence = cadence.setValue(0).setState(Sensor.SensorState.NONE);
} }
} else {
cadence
.setValue(SensorUtils.unsignedShortToIntLittleEndian(buffer, 56) / 16)
.setState(Sensor.SensorState.SENDING);
} }
sds.setCadence(cadence);
Sensor.SensorDataSet sds =
Sensor.SensorDataSet.newBuilder()
.setCreationTime(System.currentTimeMillis())
.setBatteryLevel(batteryLevel)
.setHeartRate(heartrate)
.setCadence(cadence)
.build();
return sds;
} }
@Override @Override
@@ -0,0 +1,63 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.services.sensors;
import junit.framework.TestCase;
/**
* @author Dominik Ršttsches
*/
public class StrideReadingsTest extends TestCase {
public void testNoReadingOnStartup() {
StrideReadings strideReadings = new StrideReadings();
assertEquals(StrideReadings.CADENCE_NOT_AVAILABLE, strideReadings.getCadence());
}
public void testAverageCadenceAvailable() {
StrideReadings strideReadings = new StrideReadings();
// 2 steps / second => Cadence is 120 / minute
for (int i = 1; i <= 30; i++) {
strideReadings.updateStrideReading(i*2);
if (i >= StrideReadings.MIN_READINGS_FOR_AVERAGE) {
assertEquals(120, strideReadings.getCadence());
} else {
assertEquals(StrideReadings.CADENCE_NOT_AVAILABLE, strideReadings.getCadence());
}
}
}
/**
* Tests for correct calculation after rolling over at 128 strides,
* just like the HxM seems to do it.
*/
public void testRollover() {
StrideReadings strideReadings = new StrideReadings();
// 1 step per second => Cadence is 60 / minute
// Updating readings counting upwards from initialStrides -
// initialStrides set to a value below 128 to ensure rollover.
int initialStrides = 128 - StrideReadings.NUM_READINGS_FOR_AVERAGE - 5;
for (int i = 1; i <= StrideReadings.NUM_READINGS_FOR_AVERAGE + 10; i++) {
strideReadings.updateStrideReading((initialStrides + i) % 128);
if (i >= StrideReadings.MIN_READINGS_FOR_AVERAGE) {
assertEquals(60, strideReadings.getCadence());
} else {
assertEquals(StrideReadings.CADENCE_NOT_AVAILABLE, strideReadings.getCadence());
}
}
}
}