forked from upstream-mirrors/OpenTracks
merge heads
This commit is contained in:
@@ -17,8 +17,8 @@ limitations under the License.
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.maps.mytracks"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="31"
|
||||
android:versionName="1.1.8">
|
||||
android:versionCode="32"
|
||||
android:versionName="1.1.9">
|
||||
<application android:icon="@drawable/arrow_icon"
|
||||
android:label="@string/app_name"
|
||||
android:backupAgent="com.google.android.apps.mytracks.io.backup.MyTracksBackupAgent">
|
||||
@@ -79,6 +79,17 @@ limitations under the License.
|
||||
</intent-filter>
|
||||
</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"
|
||||
android:label="@string/waypointdetails_title">
|
||||
<intent-filter>
|
||||
|
||||
@@ -13,7 +13,5 @@ split.density=false
|
||||
target=Google Inc.:Google APIs:13
|
||||
android.library.reference.1=../MyTracksLib/
|
||||
|
||||
# ProGuard is turned off while we investigate the removal of code that
|
||||
# isn't actually dead from Fusion Tables. See issue 303 for an example of
|
||||
# the result of that removal.
|
||||
#proguard.config=proguard.cfg
|
||||
# Enable proguard.
|
||||
proguard.config=proguard.cfg
|
||||
|
||||
@@ -51,3 +51,15 @@
|
||||
-keep class * implements android.os.Parcelable {
|
||||
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
|
||||
|
||||
@@ -40,7 +40,9 @@ limitations under the License.
|
||||
android:singleLine="true"
|
||||
android:autoText="true"
|
||||
android:capitalize="words"
|
||||
android:selectAllOnFocus="true"/>
|
||||
android:selectAllOnFocus="true"
|
||||
android:hint="@string/trackdetails_name_hint"
|
||||
android:imeOptions="actionNext"/>
|
||||
</LinearLayout>
|
||||
<TextView android:text="@string/trackdetails_category"
|
||||
android:layout_width="fill_parent"
|
||||
@@ -48,7 +50,9 @@ limitations under the License.
|
||||
<AutoCompleteTextView android:id="@+id/trackdetails_category"
|
||||
android:layout_width="fill_parent"
|
||||
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"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
@@ -61,7 +65,9 @@ limitations under the License.
|
||||
android:selectAllOnFocus="true"
|
||||
android:maxLines="50"
|
||||
android:gravity="top"
|
||||
android:layout_weight="1"/>
|
||||
android:layout_weight="1"
|
||||
android:hint="@string/trackdetails_description_hint"
|
||||
android:imeOptions="actionDone"/>
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
|
||||
@@ -127,26 +127,24 @@ limitations under the License.
|
||||
</TableLayout>
|
||||
</ScrollView>
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
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"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dip"
|
||||
android:layout_gravity="right"
|
||||
android:layout_gravity="left"
|
||||
android:text="@string/cancel"
|
||||
android:textSize="14dip"/>
|
||||
<TextView
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"/>
|
||||
style="@style/DialogButton"/>
|
||||
<Button android:id="@+id/sendtogoogle_send_now"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dip"
|
||||
android:layout_gravity="right"
|
||||
android:text="@string/sendtogoogle_send_now"
|
||||
android:textSize="14dip"/>
|
||||
style="@style/DialogButton"/>
|
||||
<!-- right spacer -->
|
||||
<LinearLayout style="@style/DialogButtonSpacer"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -50,7 +50,9 @@ limitations under the License.
|
||||
android:singleLine="true"
|
||||
android:autoText="true"
|
||||
android:capitalize="words"
|
||||
android:selectAllOnFocus="true"/>
|
||||
android:selectAllOnFocus="true"
|
||||
android:hint="@string/waypointdetails_name_hint"
|
||||
android:imeOptions="actionNext"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout android:id="@+id/waypointdetails_description_layout"
|
||||
android:orientation="vertical"
|
||||
@@ -65,7 +67,9 @@ limitations under the License.
|
||||
<AutoCompleteTextView android:id="@+id/waypointdetails_category"
|
||||
android:layout_width="fill_parent"
|
||||
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"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
@@ -79,7 +83,9 @@ limitations under the License.
|
||||
android:minLines="5"
|
||||
android:maxLines="50"
|
||||
android:gravity="top"
|
||||
android:layout_weight="1"/>
|
||||
android:layout_weight="1"
|
||||
android:hint="@string/waypointdetails_description_hint"
|
||||
android:imeOptions="actionDone"/>
|
||||
</LinearLayout>
|
||||
|
||||
<TableLayout android:id="@+id/waypoint_stats"
|
||||
|
||||
@@ -125,6 +125,27 @@ limitations under the License.
|
||||
android:text="@string/bpm" />
|
||||
</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>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
@@ -152,14 +152,20 @@ limitations under the License.
|
||||
<!-- MyTracks Details -->
|
||||
<string name="trackdetails_title">Detalls 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_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_hint">Tipus d\'activitat</string>
|
||||
|
||||
<!-- MyTracks Waypoint Details -->
|
||||
<string name="waypointdetails_title">Detalls 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_hint">Descripció del marcador</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 -->
|
||||
<string name="mytracks_settings">Paràmetres de My Tracks</string>
|
||||
|
||||
@@ -154,14 +154,20 @@ limitations under the License.
|
||||
<!-- MyTracks Details -->
|
||||
<string name="trackdetails_title">Trackdetails</string>
|
||||
<string name="trackdetails_name">Name</string>
|
||||
<string name="trackdetails_name_hint">Name</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_hint">Aktivität</string>
|
||||
|
||||
<!-- MyTracks Waypoint Details -->
|
||||
<string name="waypointdetails_title">Wegpunktdetails</string>
|
||||
<string name="waypointdetails_name">Wegpunktname</string>
|
||||
<string name="waypointdetails_name_hint">Wegpunktname</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_hint">Art des Wegpunktes</string>
|
||||
|
||||
<!-- MyTracks Settings -->
|
||||
<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="bpm">bpm</string-->
|
||||
<string name="battery_level">Akkukapazität</string>
|
||||
|
||||
<!-- Stats Labels -->
|
||||
<string name="moving_time_label">Zeit in Bewegung</string>
|
||||
|
||||
@@ -138,14 +138,20 @@ limitations under the License.
|
||||
<!-- MyTracks Details -->
|
||||
<string name="trackdetails_title">Detalles 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_hint">Descripción del recorrido</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 -->
|
||||
<string name="waypointdetails_title">Detalles 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_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_hint">Tipo de señal</string>
|
||||
|
||||
<!-- MyTracks Settings -->
|
||||
<string name="mytracks_settings">Configuraciones de My Tracks</string>
|
||||
|
||||
@@ -183,14 +183,20 @@ limitations under the License.
|
||||
<!-- MyTracks Details -->
|
||||
<string name="trackdetails_title">Reitin tiedot</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_hint">Reitin kuvaus</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 -->
|
||||
<string name="waypointdetails_title">Merkinnän tiedot</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_hint">Merkinnän kuvaus</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 -->
|
||||
<string name="mytracks_settings">My Tracks Asetukset</string>
|
||||
@@ -380,9 +386,9 @@ limitations under the License.
|
||||
|
||||
<!-- Sensors -->
|
||||
<string name="watts">W</string>
|
||||
|
||||
<string name="revolutions_per_minute">rpm</string>
|
||||
<string name="bpm">bpm</string>
|
||||
<string name="battery_level">Akku</string>
|
||||
|
||||
<!-- Stats Labels -->
|
||||
<string name="moving_time_label">Liikkumisaika</string>
|
||||
|
||||
@@ -144,14 +144,20 @@ limitations under the License.
|
||||
<!-- MyTracks Details -->
|
||||
<string name="trackdetails_title">Détails 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_hint">Description du parcours</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 -->
|
||||
<string name="waypointdetails_title">Details 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_hint">Description balise</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 -->
|
||||
<string name="mytracks_settings">Paramètres My Tracks</string>
|
||||
|
||||
@@ -147,14 +147,20 @@ limitations under the License.
|
||||
<!-- MyTracks Details -->
|
||||
<string name="trackdetails_title">Dettagli 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_hint">Descrizione del percorso</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 -->
|
||||
<string name="waypointdetails_title">Dettagli sul 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_hint">Descrizione del segnaposto</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 -->
|
||||
<string name="mytracks_settings">Impostazioni di My Tracks</string>
|
||||
|
||||
@@ -176,14 +176,20 @@ limitations under the License.
|
||||
<!-- MyTracks Details -->
|
||||
<string name="trackdetails_title">トラック詳細</string>
|
||||
<string name="trackdetails_name">トラック名</string>
|
||||
<string name="trackdetails_name_hint">トラック名</string>
|
||||
<string name="trackdetails_description">トラック説明</string>
|
||||
<string name="trackdetails_description_hint">トラック説明</string>
|
||||
<string name="trackdetails_category">活動タイプ(ハイキング, サイクリング、ランニング、登山...)</string>
|
||||
<string name="trackdetails_category_hint">活動タイプ</string>
|
||||
|
||||
<!-- MyTracks Waypoint Details -->
|
||||
<string name="waypointdetails_title">マーカー詳細</string>
|
||||
<string name="waypointdetails_name">マーカー名</string>
|
||||
<string name="waypointdetails_name_hint">マーカー名</string>
|
||||
<string name="waypointdetails_description">マーカー説明</string>
|
||||
<string name="waypointdetails_description_hint">マーカー説明</string>
|
||||
<string name="waypointdetails_category">マーカータイプ(建物、洞穴、名所...)</string>
|
||||
<string name="waypointdetails_category_hint">マーカータイプ</string>
|
||||
|
||||
<!-- MyTracks Settings -->
|
||||
<string name="mytracks_settings">My Tracks設定</string>
|
||||
|
||||
@@ -149,14 +149,20 @@ limitations under the License.
|
||||
<!-- MyTracks Details -->
|
||||
<string name="trackdetails_title">Szczegóły 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_hint">Opis trasy</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 -->
|
||||
<string name="waypointdetails_title">Szczegóły 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_hint">Opis znacznika</string>
|
||||
<string name="waypointdetails_category">Typ znacznika (np. budynek, jaskinia, punkt widokowy...)</string>
|
||||
<string name="waypointdetails_category_hint">Typ znacznika</string>
|
||||
|
||||
<!-- MyTracks Settings -->
|
||||
<string name="mytracks_settings">Ustawienia My Tracks</string>
|
||||
|
||||
@@ -144,14 +144,20 @@ limitations under the License.
|
||||
<!-- MyTracks Details -->
|
||||
<string name="trackdetails_title">Detalhes 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_hint">Descrição do Caminho</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 -->
|
||||
<string name="waypointdetails_title">Detalhes 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_hint">Descrição do Marcador</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 -->
|
||||
<string name="mytracks_settings">Configurações do My Tracks</string>
|
||||
|
||||
@@ -179,14 +179,20 @@ limitations under the License.
|
||||
<!-- MyTracks Details -->
|
||||
<string name="trackdetails_title">Трек детали</string>
|
||||
<string name="trackdetails_name">Название трека</string>
|
||||
<string name="trackdetails_name_hint">Название трека</string>
|
||||
<string name="trackdetails_description">Описание трека</string>
|
||||
<string name="trackdetails_description_hint">Описание трека</string>
|
||||
<string name="trackdetails_category">Тип деятельности (например: пешая прогулка, велосипедная прогулка, бег, восхождение...)</string>
|
||||
<string name="trackdetails_category_hint">Тип деятельности</string>
|
||||
|
||||
<!-- MyTracks Waypoint Details -->
|
||||
<string name="waypointdetails_title">Маркер детали</string>
|
||||
<string name="waypointdetails_name">Имя маркера</string>
|
||||
<string name="waypointdetails_name_hint">Имя маркера</string>
|
||||
<string name="waypointdetails_description">Описание маркера</string>
|
||||
<string name="waypointdetails_description_hint">Описание маркера</string>
|
||||
<string name="waypointdetails_category">Тип маркера (например: здание, выбоина, достопримечательность...)</string>
|
||||
<string name="waypointdetails_category_hint">Тип маркера</string>
|
||||
|
||||
<!-- MyTracks Settings -->
|
||||
<string name="mytracks_settings">Настройки My Tracks</string>
|
||||
|
||||
@@ -149,14 +149,20 @@ limitations under the License.
|
||||
<!-- MyTracks Details -->
|
||||
<string name="trackdetails_title">Spårdetaljer</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_hint">Spårbeskrivning</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 -->
|
||||
<string name="waypointdetails_title">Markördetaljer</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_hint">Markörbeskrivning</string>
|
||||
<string name="waypointdetails_category">Markörtyp (e.g. byggnad, grop, sevärdhet...)</string>
|
||||
<string name="waypointdetails_category_hint">Markörtyp</string>
|
||||
|
||||
<!-- MyTracks Settings -->
|
||||
<string name="mytracks_settings">My Tracks inställningar</string>
|
||||
|
||||
@@ -180,14 +180,20 @@ limitations under the License.
|
||||
<!-- MyTracks Details -->
|
||||
<string name="trackdetails_title">轨迹详细信息</string>
|
||||
<string name="trackdetails_name">轨迹名称</string>
|
||||
<string name="trackdetails_name_hint">轨迹名称</string>
|
||||
<string name="trackdetails_description">轨迹描述</string>
|
||||
<string name="trackdetails_description_hint">轨迹描述</string>
|
||||
<string name="trackdetails_category">活动类型 (例如: 徒步, 骑行, 跑步, 攀岩...)</string>
|
||||
<string name="trackdetails_category_hint">活动类型</string>
|
||||
|
||||
<!-- MyTracks Waypoint Details -->
|
||||
<string name="waypointdetails_title">标记详细信息</string>
|
||||
<string name="waypointdetails_name">标记名称</string>
|
||||
<string name="waypointdetails_name_hint">标记名称</string>
|
||||
<string name="waypointdetails_description">标记描述</string>
|
||||
<string name="waypointdetails_description_hint">标记描述</string>
|
||||
<string name="waypointdetails_category">标记类型 (例如: 建筑, 陷坑, 景点...)</string>
|
||||
<string name="waypointdetails_category_hint">标记类型</string>
|
||||
|
||||
<!-- MyTracks Settings -->
|
||||
<string name="mytracks_settings">My Tracks 设置</string>
|
||||
|
||||
@@ -43,7 +43,11 @@ limitations under the License.
|
||||
|
||||
<!-- ID for Google Analytics -->
|
||||
<string name="google_analytics_id">UA-7222692-2</string>
|
||||
|
||||
<!-- Symbols -->
|
||||
<string name="percent">%</string>
|
||||
|
||||
<!-- Intent actions -->
|
||||
<string name="save_intent_action">android.intent.action.SAVE</string>
|
||||
<string name="open_settings_screen">android.intent.action.settings.OPEN</string>
|
||||
</resources>
|
||||
|
||||
@@ -53,4 +53,5 @@ limitations under the License.
|
||||
<string name="reset_key">resetToDefaults</string>
|
||||
<string name="sensor_options_key">sensorOptions</string>
|
||||
<string name="ant_options_key">antOptions</string>
|
||||
<string name="display_settings_screen_key">displaySettingsScreen</string>
|
||||
</resources>
|
||||
|
||||
@@ -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="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="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>
|
||||
@@ -183,14 +184,20 @@ limitations under the License.
|
||||
<!-- MyTracks Details -->
|
||||
<string name="trackdetails_title">Track Details</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_hint">Track Description</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 -->
|
||||
<string name="waypointdetails_title">Marker Details</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_hint">Marker Description</string>
|
||||
<string name="waypointdetails_category">Marker Type (e.g. Building, Pothole, Sight...)</string>
|
||||
<string name="waypointdetails_category_hint">Marker Type</string>
|
||||
|
||||
<!-- MyTracks Settings -->
|
||||
<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="bpm">bpm</string>
|
||||
<string name="battery_level">Battery Level</string>
|
||||
|
||||
<!-- Stats Labels -->
|
||||
<string name="moving_time_label">Moving Time</string>
|
||||
@@ -508,5 +516,5 @@ limitations under the License.
|
||||
<string name="ant_bridge_sensor_option">SRM ANT+ Bridge</string>
|
||||
<string name="polar_bt_sensor_option">Polar Bluetooth</string>
|
||||
<string name="zephyr_bt_sensor_option">Zephyr Bluetooth</string>
|
||||
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -85,4 +85,22 @@ limitations under the License.
|
||||
<style name="WidgetText.Register">
|
||||
<item name="android:width">160px</item>
|
||||
</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>
|
||||
@@ -18,7 +18,8 @@ limitations under the License.
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- Display settings -->
|
||||
<PreferenceScreen android:title="@string/settings_display">
|
||||
<PreferenceScreen android:title="@string/settings_display"
|
||||
android:key="@string/display_settings_screen_key">
|
||||
<CheckBoxPreference
|
||||
android:key="@string/metric_units_key"
|
||||
android:title="@string/settings_metric_units"
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
@@ -79,6 +80,8 @@ class CheckUnits {
|
||||
private static void accept(Context context, SharedPreferences preferences) {
|
||||
recordCheckPerformed(preferences);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2008 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
|
||||
@@ -26,7 +26,7 @@ public abstract class Constants {
|
||||
* Should be used by all log statements
|
||||
*/
|
||||
public static final String TAG = "MyTracks";
|
||||
|
||||
|
||||
/**
|
||||
* Name of the top-level directory inside the SD card where our files will
|
||||
* be read from/written to.
|
||||
@@ -39,32 +39,21 @@ public abstract class Constants {
|
||||
|
||||
public static final int GET_LOGIN = 0;
|
||||
public static final int GET_MAP = 1;
|
||||
public static final int CREATE_MAP = 2;
|
||||
public static final int SHOW_TRACK = 3;
|
||||
public static final int ADD_LIST = 4;
|
||||
public static final int FEATURE_DETAILS = 5;
|
||||
public static final int START_RECORDING = 6;
|
||||
public static final int STOP_RECORDING = 7;
|
||||
public static final int AUTHENTICATE_TO_MY_MAPS = 8;
|
||||
public static final int AUTHENTICATE_TO_FUSION_TABLES = 9;
|
||||
public static final int AUTHENTICATE_TO_DOCLIST = 10;
|
||||
public static final int AUTHENTICATE_TO_TRIX = 11;
|
||||
public static final int DELETE_TRACK = 13;
|
||||
public static final int SEND_TO_GOOGLE = 14;
|
||||
public static final int SHARE_LINK = 15;
|
||||
public static final int SHARE_GPX_FILE = 16;
|
||||
public static final int SHARE_KML_FILE = 17;
|
||||
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;
|
||||
public static final int SHOW_TRACK = 2;
|
||||
public static final int AUTHENTICATE_TO_MY_MAPS = 3;
|
||||
public static final int AUTHENTICATE_TO_FUSION_TABLES = 4;
|
||||
public static final int AUTHENTICATE_TO_DOCLIST = 5;
|
||||
public static final int AUTHENTICATE_TO_TRIX = 6;
|
||||
public static final int SHARE_GPX_FILE = 7;
|
||||
public static final int SHARE_KML_FILE = 8;
|
||||
public static final int SHARE_CSV_FILE = 9;
|
||||
public static final int SHARE_TCX_FILE = 10;
|
||||
public static final int SAVE_GPX_FILE = 11;
|
||||
public static final int SAVE_KML_FILE = 12;
|
||||
public static final int SAVE_CSV_FILE = 13;
|
||||
public static final int SAVE_TCX_FILE = 14;
|
||||
public static final int SHOW_WAYPOINT = 15;
|
||||
public static final int WELCOME = 16;
|
||||
|
||||
/*
|
||||
* Menu ids:
|
||||
@@ -179,7 +168,7 @@ public abstract class Constants {
|
||||
* The type of account that we can use for gdata uploads.
|
||||
*/
|
||||
public static final String ACCOUNT_TYPE = "com.google";
|
||||
|
||||
|
||||
/**
|
||||
* The name of extra intent property to indicate whether we want to resume
|
||||
* a previously recorded track.
|
||||
@@ -189,14 +178,6 @@ public abstract class Constants {
|
||||
|
||||
public static int getActionFromMenuId(int 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:
|
||||
return Constants.SHARE_KML_FILE;
|
||||
case Constants.MENU_SHARE_GPX_FILE:
|
||||
@@ -213,15 +194,13 @@ public abstract class Constants {
|
||||
return Constants.SAVE_CSV_FILE;
|
||||
case Constants.MENU_SAVE_TCX_FILE:
|
||||
return Constants.SAVE_TCX_FILE;
|
||||
case Constants.MENU_CLEAR_MAP:
|
||||
return Constants.CLEAR_MAP;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
activity.runOnUiThread(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
showDoneDialog();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showDoneDialog() {
|
||||
Log.i(Constants.TAG, "ImportAllTracks: Done");
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
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.ListenerDataType;
|
||||
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.io.file.SaveActivity;
|
||||
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.mytracks.R;
|
||||
|
||||
import android.content.ContentUris;
|
||||
import android.content.Intent;
|
||||
import android.location.Location;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
@@ -412,6 +415,23 @@ public class MapActivity extends com.google.android.maps.MapActivity
|
||||
SaveActivity.handleExportTrackAction(this, dataHub.getSelectedTrackId(),
|
||||
Constants.getActionFromMenuId(item.getItemId()));
|
||||
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:
|
||||
return super.onMenuItemSelected(featureId, item);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -24,7 +24,7 @@ import android.view.MenuItem;
|
||||
|
||||
/**
|
||||
* Manage the application menus.
|
||||
*
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
class MenuManager {
|
||||
@@ -34,7 +34,7 @@ class MenuManager {
|
||||
public MenuManager(MyTracks activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
activity.getMenuInflater().inflate(R.menu.main, menu);
|
||||
return true;
|
||||
@@ -52,7 +52,7 @@ class MenuManager {
|
||||
.setEnabled(isRecording)
|
||||
.setVisible(isRecording);
|
||||
}
|
||||
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_start_recording: {
|
||||
@@ -86,10 +86,6 @@ class MenuManager {
|
||||
case R.id.menu_help: {
|
||||
return startActivity(WelcomeActivity.class);
|
||||
}
|
||||
case Constants.MENU_CLEAR_MAP: {
|
||||
activity.clearSelectedTrack();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -33,10 +33,8 @@ 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.TabActivity;
|
||||
import android.content.ContentUris;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
@@ -61,6 +59,7 @@ import android.widget.Toast;
|
||||
* @author Leif Hendrik Wilden
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class MyTracks extends TabActivity implements OnTouchListener {
|
||||
private TrackDataHub dataHub;
|
||||
|
||||
@@ -314,7 +313,7 @@ public class MyTracks extends TabActivity implements OnTouchListener {
|
||||
dataHub.loadTrack(trackId);
|
||||
|
||||
// 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) {
|
||||
onActivityResult(resultCode, Activity.RESULT_OK, results);
|
||||
}
|
||||
@@ -336,24 +335,6 @@ public class MyTracks extends TabActivity implements OnTouchListener {
|
||||
}
|
||||
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: {
|
||||
CheckUnits.check(this);
|
||||
break;
|
||||
@@ -373,36 +354,6 @@ public class MyTracks extends TabActivity implements OnTouchListener {
|
||||
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.
|
||||
*
|
||||
@@ -493,10 +444,6 @@ public class MyTracks extends TabActivity implements OnTouchListener {
|
||||
}
|
||||
}
|
||||
|
||||
void clearSelectedTrack() {
|
||||
dataHub.unloadCurrentTrack();
|
||||
}
|
||||
|
||||
long getSelectedTrackId() {
|
||||
return dataHub.getSelectedTrackId();
|
||||
}
|
||||
|
||||
@@ -160,6 +160,7 @@ public class SensorStateActivity extends Activity {
|
||||
utils.setUnknown(R.id.cadence_state_register);
|
||||
utils.setUnknown(R.id.power_state_register);
|
||||
utils.setUnknown(R.id.heart_rate_register);
|
||||
utils.setUnknown(R.id.battery_level_register);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -206,5 +207,18 @@ public class SensorStateActivity extends Activity {
|
||||
: Sensor.SensorState.NONE,
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,11 @@ import java.util.Set;
|
||||
|
||||
/**
|
||||
* 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 Rodrigo Damazio
|
||||
*/
|
||||
@@ -58,12 +62,22 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
|
||||
private BackupPreferencesListener backupListener;
|
||||
private SharedPreferences preferences;
|
||||
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
protected void onCreate(Bundle 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
|
||||
ApiFeatures apiFeatures = ApiFeatures.getInstance();
|
||||
int volumeStream =
|
||||
@@ -83,6 +97,19 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
// Load the preferences to be displayed
|
||||
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
|
||||
// units
|
||||
CheckBoxPreference metricUnitsPreference =
|
||||
@@ -102,17 +129,6 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
|
||||
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
|
||||
Preference resetPreference = findPreference(getString(R.string.reset_key));
|
||||
resetPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||
@@ -123,6 +139,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() {
|
||||
ListPreference sensorTypePreference =
|
||||
@@ -174,6 +207,10 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// If we only need the display setting screen nothing else needs to load.
|
||||
if (processIntent())
|
||||
return;
|
||||
|
||||
configureBluetoothPreferences();
|
||||
Preference backupNowPreference =
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
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.io.file.SaveActivity;
|
||||
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 android.app.ListActivity;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.MenuItem;
|
||||
@@ -182,14 +187,16 @@ public class TrackList extends ListActivity
|
||||
SaveActivity.handleExportTrackAction(this, trackId,
|
||||
Constants.getActionFromMenuId(item.getItemId()));
|
||||
return true;
|
||||
default: {
|
||||
Intent result = new Intent();
|
||||
result.putExtra("trackid", trackId);
|
||||
setResult(
|
||||
Constants.getActionFromMenuId(item.getItemId()), result);
|
||||
finish();
|
||||
case Constants.MENU_DELETE: {
|
||||
Intent intent = new Intent(Intent.ACTION_DELETE);
|
||||
Uri uri = ContentUris.withAppendedId(TracksColumns.CONTENT_URI, trackId);
|
||||
intent.setDataAndType(uri, TracksColumns.CONTENT_ITEMTYPE);
|
||||
startActivity(intent);
|
||||
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.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.AutoCompleteTextView;
|
||||
import android.widget.Button;
|
||||
@@ -139,6 +140,7 @@ public class WaypointDetails extends Activity
|
||||
utils.setAllStats(waypointStats);
|
||||
utils.setAltitude(
|
||||
R.id.elevation_register, waypoint.getLocation().getAltitude());
|
||||
name.setImeOptions(EditorInfo.IME_ACTION_DONE);
|
||||
break;
|
||||
}
|
||||
icon.setImageDrawable(getResources().getDrawable(iconId));
|
||||
|
||||
@@ -96,11 +96,7 @@ public class WaypointsList extends ListActivity
|
||||
|
||||
@Override
|
||||
protected void onListItemClick(ListView l, View v, int position, long id) {
|
||||
Intent result = new Intent();
|
||||
result.putExtra("trackid", trackId);
|
||||
result.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, id);
|
||||
setResult(Constants.EDIT_WAYPOINT, result);
|
||||
finish();
|
||||
editWaypoint(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -108,14 +104,15 @@ public class WaypointsList extends ListActivity
|
||||
if (!super.onMenuItemSelected(featureId, item)) {
|
||||
switch (item.getItemId()) {
|
||||
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;
|
||||
}
|
||||
case Constants.MENU_EDIT: {
|
||||
Intent intent = new Intent(this, WaypointDetails.class);
|
||||
intent.putExtra("trackid", trackId);
|
||||
intent.putExtra(WaypointDetails.WAYPOINT_ID_EXTRA, selectedWaypointId);
|
||||
startActivity(intent);
|
||||
editWaypoint(selectedWaypointId);
|
||||
return true;
|
||||
}
|
||||
case Constants.MENU_DELETE: {
|
||||
@@ -126,6 +123,13 @@ public class WaypointsList extends ListActivity
|
||||
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
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
@@ -412,10 +412,10 @@ public class TrackDataHub {
|
||||
return;
|
||||
}
|
||||
|
||||
// Save the selection to memory and flash.
|
||||
// Save the selection to memory and flush.
|
||||
selectedTrackId = trackId;
|
||||
ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
|
||||
preferences.edit().putLong(SELECTED_TRACK_KEY, trackId));
|
||||
selectedTrackId = trackId;
|
||||
|
||||
// Force it to reload data from the beginning.
|
||||
Log.d(TAG, "Loading track");
|
||||
@@ -642,6 +642,9 @@ public class TrackDataHub {
|
||||
} else if (SPEED_REPORTING_KEY.equals(key)) {
|
||||
reportSpeed = preferences.getBoolean(SPEED_REPORTING_KEY, true);
|
||||
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;
|
||||
|
||||
import static com.google.android.apps.mytracks.Constants.TAG;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.ProgressIndicator;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
@@ -50,7 +51,6 @@ import android.util.Log;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -76,13 +76,13 @@ public class SendToFusionTables implements Runnable {
|
||||
|
||||
/** The path for viewing a map visualization of a table. */
|
||||
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&" +
|
||||
"lat=%f&lng=%f&z=%d&t=1&l=col2";
|
||||
|
||||
/** Standard base feed url for Fusion Tables. */
|
||||
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;
|
||||
|
||||
@@ -695,7 +695,7 @@ public class SendToFusionTables implements Runnable {
|
||||
if (success) {
|
||||
byte[] result = new byte[1024];
|
||||
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);
|
||||
if (lines[0].equals("tableid")) {
|
||||
tableId = lines[1];
|
||||
|
||||
@@ -44,6 +44,8 @@ import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
@@ -55,15 +57,15 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
*/
|
||||
public class DocsHelper {
|
||||
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 =
|
||||
"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 =
|
||||
"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 =
|
||||
"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 =
|
||||
"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 OPENDOCUMENT_SPREADSHEET_MIME_TYPE =
|
||||
@@ -285,11 +287,13 @@ public class DocsHelper {
|
||||
String elevationUnit = context.getString(metricUnits ?
|
||||
R.string.meter : R.string.feet);
|
||||
|
||||
DateFormat trackDateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
|
||||
|
||||
// Prepare the Post-Text we are going to send.
|
||||
DocsTagBuilder tagBuilder = new DocsTagBuilder(metricUnits)
|
||||
.append("name", track.getName())
|
||||
.append("description", track.getDescription())
|
||||
.append("date", String.format("%tc", stats.getStartTime()))
|
||||
.append("date", trackDateFormat.format(new Date(stats.getStartTime())))
|
||||
.append("totaltime", StringUtils.formatTimeAlwaysShowingHours(
|
||||
stats.getTotalTime()))
|
||||
.append("movingtime", StringUtils.formatTimeAlwaysShowingHours(
|
||||
|
||||
@@ -19,36 +19,38 @@ import com.google.android.apps.mytracks.util.StringUtils;
|
||||
import com.google.android.apps.mytracks.util.UnitConversions;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
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>Sample Usage:
|
||||
*
|
||||
*
|
||||
* <code>
|
||||
* String tags = new DocsTagBuilder(false)
|
||||
* .append("tagName", "tagValue")
|
||||
* .appendLargeUnits("bigTagName", 1.0)
|
||||
* .build();
|
||||
* </code>
|
||||
*
|
||||
*
|
||||
* <p>results in:
|
||||
*
|
||||
*
|
||||
* <code>
|
||||
* <gsx:tagName><![CDATA[tagValue]]></gsx:tagName>
|
||||
* <gsx:bigTagName><![CDATA[1.00]]></gsx:bigTagName>
|
||||
* </code>
|
||||
*
|
||||
*
|
||||
* @author Matthew Simmons
|
||||
*/
|
||||
class DocsTagBuilder {
|
||||
// TODO(simmonmt): These formats aren't I18N-compatible. Not everyone uses
|
||||
// commas for thousands and dots for the decimal point.
|
||||
private static final DecimalFormatSymbols FORMAT_SYMBOLS =
|
||||
DecimalFormatSymbols.getInstance(Locale.ENGLISH);
|
||||
private static final NumberFormat LARGE_UNIT_FORMAT =
|
||||
new DecimalFormat("#,###,###.00");
|
||||
new DecimalFormat("#,###,###.00", FORMAT_SYMBOLS);
|
||||
private static final NumberFormat SMALL_UNIT_FORMAT =
|
||||
new DecimalFormat("###,###");
|
||||
new DecimalFormat("###,###", FORMAT_SYMBOLS);
|
||||
|
||||
protected final boolean metricUnits;
|
||||
protected final StringBuilder stringBuilder;
|
||||
@@ -59,7 +61,7 @@ class DocsTagBuilder {
|
||||
*/
|
||||
DocsTagBuilder(boolean metricUnits) {
|
||||
this.metricUnits = metricUnits;
|
||||
stringBuilder = new StringBuilder();
|
||||
this.stringBuilder = new StringBuilder();
|
||||
}
|
||||
|
||||
/** Appends a tag containing a string value */
|
||||
@@ -68,13 +70,13 @@ class DocsTagBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Appends a tag containing a numeric value. The value will be formatted
|
||||
* according to the large distance of the specified measurement system (i.e.
|
||||
* kilometers or miles).
|
||||
*
|
||||
*
|
||||
* @param name The tag name.
|
||||
* @param d The value to be formatted, in kilometers.
|
||||
* @param d The value to be formatted, in kilometers.
|
||||
*/
|
||||
DocsTagBuilder appendLargeUnits(String name, double d) {
|
||||
double value = metricUnits ? d : (d * UnitConversions.KM_TO_MI);
|
||||
@@ -86,7 +88,7 @@ class DocsTagBuilder {
|
||||
* Appends a tag containing a numeric value. The value will be formatted
|
||||
* according to the small distance of the specified measurement system (i.e.
|
||||
* meters or feet).
|
||||
*
|
||||
*
|
||||
* @param name The tag name.
|
||||
* @param d The value to be formatted, in meters.
|
||||
*/
|
||||
|
||||
@@ -44,6 +44,7 @@ import java.util.TimeZone;
|
||||
* Garmin Training Center 3.5.3.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
* @author Dominik Ršttsches
|
||||
*/
|
||||
public class TcxTrackWriter implements TrackFormatWriter {
|
||||
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 Track track;
|
||||
|
||||
// Determines whether to encode cadence value as running or cycling cadence.
|
||||
private boolean sportIsCycling;
|
||||
|
||||
public TcxTrackWriter(Context context) {
|
||||
this.context = context;
|
||||
|
||||
@@ -76,7 +80,7 @@ public class TcxTrackWriter implements TrackFormatWriter {
|
||||
public void prepare(Track track, OutputStream out) {
|
||||
this.track = track;
|
||||
this.pw = new PrintWriter(out);
|
||||
|
||||
this.sportIsCycling = categoryToTcxSport(track.getCategory()).equals(TCX_SPORT_BIKING);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -174,22 +178,44 @@ public class TcxTrackWriter implements TrackFormatWriter {
|
||||
pw.print("</Value>");
|
||||
pw.println("</HeartRateBpm>");
|
||||
}
|
||||
// TCX Trackpoint_t contains a sequence, <Cadence> needs to be put before <Extensions>
|
||||
if (sensorData.hasCadence()
|
||||
&& sensorData.getCadence().getState() == Sensor.SensorState.SENDING
|
||||
&& sensorData.getCadence().hasValue()) {
|
||||
|
||||
boolean cadenceAvailable = sensorData.hasCadence()
|
||||
&& sensorData.getCadence().getState() == Sensor.SensorState.SENDING
|
||||
&& 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(Math.min(254, sensorData.getCadence().getValue()));
|
||||
pw.println("</Cadence>");
|
||||
}
|
||||
if (sensorData.hasPower()
|
||||
&& sensorData.getPower().getState() == Sensor.SensorState.SENDING
|
||||
&& sensorData.getPower().hasValue()) {
|
||||
|
||||
boolean powerAvailable = sensorData.hasPower()
|
||||
&& sensorData.getPower().getState() == Sensor.SensorState.SENDING
|
||||
&& sensorData.getPower().hasValue();
|
||||
|
||||
if(powerAvailable || (!sportIsCycling && cadenceAvailable)) {
|
||||
pw.print(" <Extensions>");
|
||||
pw.print("<TPX xmlns=\"http://www.garmin.com/xmlschemas/ActivityExtension/v2\">");
|
||||
pw.print("<Watts>");
|
||||
pw.print(sensorData.getPower().getValue());
|
||||
pw.print("</Watts>");
|
||||
|
||||
// RunCadence needs to be put before power in order to be understood
|
||||
// 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>");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ package com.google.android.apps.mytracks.io.mymaps;
|
||||
public class MyMapsConstants {
|
||||
static final String TAG = "MapsApi";
|
||||
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";
|
||||
|
||||
/**
|
||||
|
||||
@@ -153,6 +153,9 @@ public class TrackRecordingService extends Service {
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(final Location location) {
|
||||
if (executorService.isShutdown() || executorService.isTerminated()) {
|
||||
return;
|
||||
}
|
||||
executorService.submit(
|
||||
new Runnable() {
|
||||
@Override
|
||||
@@ -342,7 +345,6 @@ public class TrackRecordingService extends Service {
|
||||
timer.purge();
|
||||
unregisterLocationListener();
|
||||
shutdownTaskExecutors();
|
||||
executorService.shutdown();
|
||||
if (sensorManager != null) {
|
||||
sensorManager.shutdown();
|
||||
sensorManager = null;
|
||||
@@ -358,6 +360,8 @@ public class TrackRecordingService extends Service {
|
||||
// This should be the last operation.
|
||||
releaseWakeLock();
|
||||
|
||||
// Shutdown the executor service last to avoid sending events to a dead executor.
|
||||
executorService.shutdown();
|
||||
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;
|
||||
}
|
||||
}
|
||||
+31
-88
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
* 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
|
||||
* 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;
|
||||
|
||||
import com.google.android.apps.mytracks.Constants;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* An implementation of a Sensor MessageParser for Zephyr.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
* @author Dominik Ršttsches
|
||||
*/
|
||||
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_ETX = 59;
|
||||
|
||||
private StrideReadings strideReadings;
|
||||
private static final byte[] CADENCE_BUG_FW_ID = {0x1A, 0x00, 0x31, 0x65, 0x50, 0x00, 0x31, 0x62};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
private StrideReadings strideReadings;
|
||||
|
||||
@Override
|
||||
public Sensor.SensorDataSet parseBuffer(byte[] buffer) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
sb.append(String.format("%02X", buffer[i]));
|
||||
}
|
||||
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.SensorDataSet.Builder sds =
|
||||
Sensor.SensorDataSet.newBuilder()
|
||||
.setCreationTime(System.currentTimeMillis());
|
||||
|
||||
Sensor.SensorData.Builder heartrate = Sensor.SensorData.newBuilder()
|
||||
.setValue(buffer[12] & 0xFF)
|
||||
.setState(Sensor.SensorState.SENDING);
|
||||
sds.setHeartRate(heartrate);
|
||||
|
||||
Sensor.SensorData.Builder batteryLevel = Sensor.SensorData.newBuilder()
|
||||
.setValue(buffer[11])
|
||||
.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();
|
||||
|
||||
if(!needsWorkaround) {
|
||||
cadence = cadence
|
||||
.setValue(SensorUtils.unsignedShortToIntLittleEndian(buffer, 56) / 16)
|
||||
.setState(Sensor.SensorState.SENDING);
|
||||
} else {
|
||||
if(strideReadings == null) {
|
||||
if (Arrays.equals(hardwareFirmwareId, CADENCE_BUG_FW_ID)) {
|
||||
if (strideReadings == null) {
|
||||
strideReadings = new StrideReadings();
|
||||
}
|
||||
|
||||
strideReadings.updateStrideReading(
|
||||
SensorUtils.unsignedShortToIntLittleEndian(buffer, 14),
|
||||
buffer[54] & 0xFF);
|
||||
strideReadings.updateStrideReading(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);
|
||||
if (strideReadings.getCadence() != StrideReadings.CADENCE_NOT_AVAILABLE) {
|
||||
cadence.setValue(strideReadings.getCadence()).setState(Sensor.SensorState.SENDING);
|
||||
}
|
||||
} else {
|
||||
cadence
|
||||
.setValue(SensorUtils.unsignedShortToIntLittleEndian(buffer, 56) / 16)
|
||||
.setState(Sensor.SensorState.SENDING);
|
||||
}
|
||||
|
||||
Sensor.SensorDataSet sds =
|
||||
Sensor.SensorDataSet.newBuilder()
|
||||
.setCreationTime(System.currentTimeMillis())
|
||||
.setBatteryLevel(batteryLevel)
|
||||
.setHeartRate(heartrate)
|
||||
.setCadence(cadence)
|
||||
.build();
|
||||
|
||||
return sds;
|
||||
sds.setCadence(cadence);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+63
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user