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"
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>
+2 -4
View File
@@ -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
+12
View File
@@ -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
+9 -3
View File
@@ -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"
+13 -15
View File
@@ -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"
+21
View File
@@ -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>
+6
View File
@@ -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>
+7
View File
@@ -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>
+6
View File
@@ -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>
+7 -1
View File
@@ -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>
+6
View File
@@ -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>
+6
View File
@@ -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>
+6
View File
@@ -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>
+6
View File
@@ -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>
+6
View File
@@ -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>
+6
View File
@@ -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>
+6
View File
@@ -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>
+6
View File
@@ -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>
+4
View File
@@ -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>
+1
View File
@@ -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>
+10 -2
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="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>
+18
View File
@@ -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>
+2 -1
View File
@@ -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;
}
}
@@ -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
@@ -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());
}
}
}
}