diff --git a/.hgignore b/.hgignore
index 7220e4cb0..3bf9706a8 100644
--- a/.hgignore
+++ b/.hgignore
@@ -2,5 +2,6 @@ syntax:glob
*/bin
*/gen/**
+*/proguard/**
.metadata
MyTracksTest/annotations.log
diff --git a/MyTracks/AndroidManifest.xml b/MyTracks/AndroidManifest.xml
index 5f52f7262..6f3b16692 100755
--- a/MyTracks/AndroidManifest.xml
+++ b/MyTracks/AndroidManifest.xml
@@ -119,6 +119,9 @@ limitations under the License.
+
+
+
@@ -172,6 +175,7 @@ limitations under the License.
- - Off
+ - Aus
- 1 min
- 2 min
- 5 min
@@ -70,8 +70,8 @@ limitations under the License.
- - batterie sparend (adaptiv)
- - hohe genauigkeit (adaptiv)
+ - batteriesparend (adaptiv)
+ - hohe Genauigkeit (adaptiv)
- maximal (empfohlen)
- 2 s
- 3 s
@@ -133,12 +133,12 @@ limitations under the License.
- Nicht zerteilen
- - 100 meilen
- - 50 meilen
- - 25 meilen
- - 10 meilen
- - 5 meilen
- - 1 meile
+ - 100 Meilen
+ - 50 Meilen
+ - 25 Meilen
+ - 10 Meilen
+ - 5 Meilen
+ - 1 Meile
- 60 min
- 30 min
- 15 min
@@ -159,7 +159,7 @@ limitations under the License.
- Laufbahn
- Geländelauf
- Gehen
- - Schnelles Gehen
+ - Gehen (Sport)
- Wandern
- Bergwandern
- Bergsteigen
@@ -181,11 +181,11 @@ limitations under the License.
- Eissegeln
- Segeln
- - Kanadierfahren
- - Kajakfahren
+ - Paddeln
+ - Kajak fahren
- Kanuwandern
- Rudern
- - Motorbootfahren
+ - Motorboot fahren
- Fähre
- Ferngesteuertes Boot
- Surfen
@@ -229,13 +229,14 @@ limitations under the License.
- Bank
- Kneipe
- Grill
+ - Imbiss
- Gebäude
- Bushaltestelle
- Straßenbahnhaltestelle
- Bahnhof
- S-Bahnhof
- Café
- - Lagerfeuer
+ - Feuerstelle
- Campingplatz
- Zeltplatz
- Kirche
@@ -278,6 +279,7 @@ limitations under the License.
- Tunnel
- Baum
- Wasserfall
+ - Springbrunnen
- Wegpunkt
diff --git a/MyTracks/res/values-de/strings.xml b/MyTracks/res/values-de/strings.xml
index 1d53433ba..571094c20 100644
--- a/MyTracks/res/values-de/strings.xml
+++ b/MyTracks/res/values-de/strings.xml
@@ -1,422 +1,399 @@
-
+
+
-
-
-
- Track aufzeichnen
- Aufzeichnung beenden
- Satellitenansicht
- Kartenansicht
- Mein Aufenthaltsort
- Wegpunkte
- Alle Tracks löschen
- Einstellungen
- Höhe
- Bitte wählen Sie einen Track zur Ansicht aus
- Aktueller Track
- Letztes Segment
- Sensor-Status
- Gesamtstatistik
-
-
- Es wurde kein \'Location Manager\' auf diesem Gerät gefunden.
- Konnte keinen GPS-Empfänger auf diesem Gerät finden.
- Beim Senden Ihres Tracks an Google My Maps ist ein Fehler aufgetreten. Bitte versuchen Sie es später nochmal.
- Beim Senden Ihres Tracks an Google Docs ist ein Fehler aufgetreten. Bitte versuchen Sie es später nochmal.
- Aufzeichnen fehlgeschlagen. Bitte versuchen Sie es nochmal.
- Anhalten nicht möglich. Bitte versuchen Sie es nochmal.
- Datei nicht lesbar.
- Datei ist nicht im GPX-Format.
- Ein Fehler ist aufgetreten. Bitte versuchen Sie es nochmal.
- Track existiert nicht.
- Die Datei ist zu groß (max. 500 KB erlaubt). Operation abgebrochen.
- Der Wegpunkt kann nicht einfügt werden. Keine Positionsbestimmung möglich.
-
-
- Warten auf ein besseres GPS-Signal. Bitte stellen Sie sicher, dass der Himmel sichtbar ist.
- Ein neuer Track wird aufgezeichnet.
- Die Aufzeichnung wurde beendet.
- Eine neue Karte wurde auf maps.google.com erstellt.
- Ihr Track wurde auf maps.google.com gespeichert.
- Ihr Track wurde in einer neuen Tabelle bei docs.google.com gespeichert.
- Ihr Track wurde an docs.google.com gesendet.
- Manchmal dauert es ein paar Minuten, bis neue Tracks bei maps.google.com erscheinen.
- Berühren Sie hier um zu den Sicherheits- und Positionseinstellungen zu gelangen. Aktiviere \'GPS-Satelliten\'. Drücken Sie dann den Zurück-Knopf um zurückzukehren.
- Anmerkung: Eine ungefähre Position wird angezeigt, bestimmt mittels Funktürmen und WiFi-Netzwerken.
- Ihre Position kann derzeit nicht bestimmt werden. Aktivieren Sie mehr Positionsquellen (siehe Sicherheits- und Positionseinstellungen) und stellen Sie sicher, dass der Himmel sichtbar ist.
- Ein Wegpunkt wurde eingefügt.
- Ein Statistikwegpunkt wurde eingefügt.
-
-
- Bitte warten…
- Ihr GPS-Track wird an Google gesendet.
- Lese Track…
- Bereite Track vor…
- Anmelden bei Google Maps…
- Anmelden bei Google Docs…
- Track an Google Docs senden…
- Track an Google Maps senden…
- Neue \'Meine Karte\' erstellen…
- Importiere GPS-Track. Das kann einen Moment dauern.
- Schreibe Datei auf SD-Karte. Das kann einen Moment dauern.
- Aktualisiere Trackstatistik…
-
-
- Sind Sie wirklich sicher?
- Alle Tracks und Wegpunkte werden endgültig von diesem Gerät gelöscht.
- Dieser Track und seine Wegpunkte werden endgültig von diesem Gerät gelöscht.
- Dieser Wegpunkt wird endgültig von diesem Gerät gelöscht.
-
-
- Erstellt mit My Tracks auf Android.
- Erstellt mit <a href=\'http://mytracks.appspot.com\'>My Tracks</a> auf Android.
- Neue Karte
-
-
- Punkte
- Aufgezeichnet am
- "Aktivität"
- "Art des Wegpunktes"
- "(Teil %d)"
-
-
- Ihr Track wird aufgezeichnet…
- Track %d
-
-
- Nein
- Ja
- OK
- Fehler
- Erfolgreich
- Wegpunkt
-
-
- (Anfang)
- (Ende)
-
-
- Anzeigen
- An eine Google MyMaps-Karte senden
- An eine neue Google MyMaps-Karte senden
- An Google Docs senden
- An Google senden…
- Vom Gerät löschen…
- Bearbeiten
- Auf SD-Karte speichern…
- Als GPX-Datei exportieren
- Als KML-Datei exportieren
- Als CSV-Datei exportieren
- Als TCX-Datei exportieren
- An Google MyMaps senden
- Alle Tracks löschen
-
- Alle Tracks exportieren
- Export abgeschlossen
- Eine Track auswählen. Lange berühren für mehr Optionen.
- Alle Tracks:
- Dieser Track
- Mit Freunden teilen…
- Ein Link zur Google MyMaps-Karte
- Als GPX-Datei
- Als KML-Datei
- Als CSV-Datei
- Als TCX-Datei
- Karte zurücksetzen
-
-
- Alle Wegpunkte löschen
- Dieser Wegpunkt
- Löschen
- Details bearbeiten
- Auf der Karte zeigen
- Wegpunkt einfügen
- Statistik einfügen
- Wegpunkt auswählen. Lange berühren für mehr Optionen.
-
-
- Trackdetails
- Name
- Beschreibung
- Aktivität (z. B. Wandern, Fahrradfahren, Laufen)
-
-
- Wegpunktdetails
- Wegpunktname
- Wegpunktbeschreibung
- Art des Wegpunktes (z. B. Gebäude, Schlagloch, Sehenswürdigkeit)
-
-
- Einstellungen für My Tracks
- Anzeige
- Aufzeichnen
- Mit Freunden Teilen
-
- Mit Ihrer Version von Android nicht verfügbar
-
- Dauer zwischen Ansagen:
- Kürzeste Zeit zwichen zwei Ansagen
-
- Kleinste Entfernung zwischen Punkten:
- Kleinste Entfernung zwischen zwei Positionsaufzeichnungen
-
- Neues Segment wenn Punkte weiter entfernt als:
- Der Track wird in zwei Segmente geteilt wenn zwei folgende Punkte weiter entfernt sind als hier angegeben.
-
- Aufzeichnungsfrequenz:
- Kürzeste Zeit zwischen zwei Positionsaufzeichnungen.
-
- Aufzeichnung pausieren wenn Genauigkeit kleiner als:
- Die Aufzeichnung wird kurzfristig angehalten, wenn Ihre Position nicht genauer als hier angegeben ermittelt werden kann.
-
- Metrischen Einheiten verwenden
- Alle Entfernungen werden in metrischen Einheiten angezeigt.
- Alle Entfernungen werden in britischen Längeneinheiten angezeigt.
-
- Karten auf maps.google.com veröffentlichen
- Hochgeladene Karten auf maps.google.com sind für alle sichtbar.
- Hochgeladene Karten auf maps.google.com werden nicht öffentlich sichtbar aufgelistet.
-
- Geschwindigkeitsanzeige:
- Geschwindigkeit wird angezeigt.
- Gangart wird angezeigt.
-
- Nur URL als Einladung zum Teilen senden
- Beim teilen mit Freunden wird nur die Karten URL gesendet.
- Beim teilen mit Freunden wird der GPS Track selbst gesendet.
-
- Zerteilungs Frequenz
- Längste Dauer oder Entfernung nach der automatisch ein Marker eingefügt wird.
-
- Maximale Dauer für Fortsetzung nach Neustart
- Maximale Zeit in Minuten nach welcher eine Aufzeichnung nach Neustart des Geräts fortgesetzt wird
-
- Datum und Zeit als Trackname
- Neue Tracks erhalten Startdatum und -zeit als Tracknamen
- Neue Tracks werden durch fortlaufende Nummerierung benannt
-
- Tempo
-
- Nur auf Android 2.0 und höher verfügbar
- Art des Sensors
- Die Art des Sensors, der angeschlossen wird
- Sensor ID
- Kennung, die an Sensoren gesendet wird (Zahl)
- Die ID darf nur aus Ziffern bestehen
- Bluetooth-Sensor
- Der Bluethooth-Sensor, der angeschlossen wird
- Modulare Statistik-Anzeige
- Die Statistiken werden auf mehreren Bildschirmseiten angezeigt
- Alle Statistiken auf einem Bildschirm anzeigen
-
-
- Datensicherung (BETA)
- Datensicherung auf SD-Karte
- Daten jetzt sichern
- Speichert eine Sicherungskopie aller Tracks und Einstellungen auf der SD-Karte
- Sicherung wiederherstellen
- Stellt Tracks und Einstellungen von einer Sicherungskopie auf der SD-Karte wieder her
- Während einer Track-Aufzeichnung können keine Datensicherungen erstellt werden
-
- Sind Sie sicher? Das Wiederherstellen einer Sicherungskopie überschreibt ihre aktuellen Tracks und Einstellungen.
- Wählen Sie die Sicherungskopie, die Sie wiederherstellen möchten.
- Keine Sicherungskopien gefunden
- Erstelle Sicherungskopie von Tracks und Einstellungen. Das kann eine Weile dauern...
- Lese Tracks und Einstellungen aus der Sicherungskopie Das kann eine Weile dauern...
-
-
- GPS-Satelliten
-
-
- Wählen Sie eine Karte von Ihrem Konto aus:
- Neue Karte erstellen…
- An Google My Maps senden
- Karten werden geladen…
- Ihre Karten konnten im Augenblick nicht geladen werden
- Diese Karte auswählen
- Kartendetails bearbeiten
- Karte mit Freunden teilen
- Track mit Freunden teilen
- Karte vom Konto löschen
- Kartentitel:
- Beschreibung:
- Diese Karte und Ihren Inhalt in Suchergebnissen sichtbar machen.
- Diese Karte und Ihren Inhalt nicht in Suchergebnissen sichtbar machen.
- Diese Karte und Ihr Inhalt sind in Suchergebnissen sichtbar.
- Weder diese Karte noch Ihr Inhalt sind in Suchergebnissen sichtbar, allerdings können Sie trotzdem von anderen durch einen direkten Link angezeigt werden.
- Schließen
- Bearbeiten
- Abbrechen
- Sichern
-
-
- Ich möchte eine Karte mit Dir teilen
+-->
+
+
+
+ Track aufzeichnen
+ Aufzeichnung anhalten
+ Satellitenansicht
+ Kartenansicht
+ Mein Aufenthaltsort
+ Wegpunkte
+ Alle Tracks löschen
+ Einstellungen
+ Höhe
+ Bitte wähle einen Track zur Ansicht aus
+ Aktueller Track
+ Letztes Segment
+ Sensorstatus
+ Aggregierte Statistiken
+
+
+ Es wurde kein Dienst zur Positionsermittlung auf diesem Gerät gefunden.
+ Es wurde kein GPS-Empfänger auf diesem Gerät gefunden.
+ Beim Senden des Tracks an Google MyMaps ist ein Fehler aufgetreten. Bitte versuche es später noch einmal.
+ Beim Senden des Tracks an Google Docs ist ein Fehler aufgetreten. Bitte versuche es später noch einmal.
+ Start der Aufzeichnung fehlgeschlagen. Bitte versuche es noch einmal.
+ Anhalten unmöglich. Bitte versuche es noch einmal.
+ Konnte Datei nicht lesen.
+ Datei ist nicht im GPX-Format.
+ Ein Fehler ist aufgetreten. Bitte versuche es noch einmal.
+ Track existiert nicht.
+ Die Datei ist zu groß (maximal 500 KB). Operation abgebrochen.
+ Der Wegpunkt kann nicht einfügt werden. Keine Positionsbestimmung möglich.
+
+
+ Warte auf ein besseres GPS-Signal. Bitte stelle sicher, dass der Himmel sichtbar ist.
+ Ein neuer Track wird aufgezeichnet.
+ Die Aufzeichnung wurde angehalten.
+ Eine neue Karte wurde auf maps.google.com erstellt.
+ Dein Track wurde auf maps.google.com gespeichert.
+ Dein Track wurde in einer neuen Tabelle bei docs.google.com gespeichert.
+ Dein Track wurde an docs.google.com gesendet.
+ Manchmal dauert es ein paar Minuten, bis neue Tracks bei maps.google.com erscheinen.
+ Hier berühren, um zu den Sicherheits- und Positionseinstellungen zu gelangen. Aktiviere \'GPS-Satelliten\'. Drücke dann den Zurück-Knopf, um hierher zurückzukehren.
+ Anmerkung: Eine ungefähre Position wird angezeigt, bestimmt mittels Mobilfunkstationen und WiFi-Netzwerken.
+ Die Position kann derzeit nicht bestimmt werden. Aktiviere mehr Positionsquellen (siehe Sicherheits- und Positionseinstellungen) und stelle sicher, dass der Himmel sichtbar ist.
+ Ein Wegpunkt wurde eingefügt.
+ Ein Statistikwegpunkt wurde eingefügt.
+
+
+ Bitte warten…
+ Dein Track wird an Google gesendet...
+ Lese Track...
+ Bereite Track vor...
+ Anmeldung bei Google Maps...
+ Anmeldung bei Google Docs...
+ Track wird an Google Docs gesendet...
+ Track wird an Google Maps gesendet...
+ Neue \'Meine Karte\' wird erstellt...
+ Importiere GPS-Track. Das kann ein wenig dauern.
+ Schreibe Datei auf SD-Karte. Das kann ein wenig dauern.
+ Aktualisiere Trackstatistik...
+
+
+ Bist Du Dir wirklich sicher?
+ Alle Tracks und Wegpunkte werden endgültig von diesem Gerät gelöscht.
+ Dieser Track und seine Wegpunkte werden endgültig von diesem Gerät gelöscht.
+ Dieser Wegpunkt wird endgültig von diesem Gerät gelöscht.
+
+
+ Erstellt von My Tracks für Android.
+ Erstellt von <a href=\'http://mytracks.appspot.com\'>My Tracks</a> für Android.
+ Neue Karte
+
+
+ Punkte
+ Aufgezeichnet am
+ Aktivität
+ Art des Wegpunktes
+ (Teil %d)
+
+
+ Dein Track wird aufgezeichnet…
+
+
+ Nein
+ Ja
+ Fehler
+ Erfolgreich
+ Wegpunkt
+
+
+ (Beginn)
+ (Ende)
+
+
+ Anzeigen
+ An eine Google MyMaps-Karte senden
+ An eine neue Google MyMaps-Karte senden
+ An Google Docs senden
+ An Google senden…
+ Vom Gerät löschen…
+ Bearbeiten
+ Auf SD-Karte speichern…
+ GPX-Datei exportieren
+ KML-Datei exportieren
+ CSV-Datei exportieren
+ TCX-Datei exportieren
+ An Google MyMaps senden
+ Alle Tracks löschen
+
+ Alle Tracks exportieren
+ Exportieren beendet
+ Einen Track auswählen. Lange berühren für mehr Optionen.
+ Alle Tracks
+ Dieser Track
+ Mit Freunden teilen…
+ Ein Link zur Google MyMaps-Karte
+ Eine GPX-Datei
+ Eine KML-Datei
+ Eine CSV-Datei
+ Eine TCX-Datei
+ Karte zurücksetzen.
+
+
+ Alle Wegpunkte löschen
+ Dieser Wegpunkt
+ Löschen
+ Details bearbeiten
+ Auf der Karte zeigen
+ Wegpunkt einfügen
+ Statistik einfügen
+ Wegpunkt auswählen. Lange berühren für mehr Optionen.
+
+
+ Trackdetails
+ Name
+ Beschreibung
+ Aktivität (z. B. Wandern, Fahrradfahren, Laufen, Klettern…)
+
+
+ Wegpunktdetails
+ Wegpunktname
+ Wegpunktbeschreibung
+ Art des Wegpunktes (z. B. Gebäude, Schlagloch, Sehenswürdigkeit…)
+
+
+ Einstellungen für My Tracks
+ Anzeige
+ Aufzeichnung
+ Mit Freunden teilen
+
+ In dieser Android-Version nicht verfügbar
+
+ Dauer zwischen Ansagen
+ Kürzeste Zeit zwischen zwei Ansagen
+
+ Kleinste Entfernung zwischen Punkten
+ Kleinste Entfernung zwischen zwei Positionsaufzeichnungen
+
+ Neues Segment, wenn Punkte weiter entfernt als
+ Der Track wird in zwei geteilt, wenn zwei folgende Punkte weiter entfernt sind als hier angegeben.
+
+ Aufzeichnungsfrequenz
+ Kürzeste Zeit zwischen zwei Positionsaufzeichnungen
+
+ Aufzeichnung pausieren, wenn Genauigkeit kleiner als
+ Die Aufzeichnung wird kurzfristig angehalten, wenn Deine Position nicht genauer als hier angegeben ermittelt werden kann.
+
+ Entfernungen in metrischen Einheiten anzeigen
+ Alle Entfernungen werden in metrischen Einheiten angezeigt.
+ Alle Entfernungen werden in imperialen Längeneinheiten angezeigt.
+
+ Karten auf maps.google.com veröffentlichen
+ Hochgeladene Karten auf maps.google.com sind für alle sichtbar.
+ Hochgeladene Karten auf maps.google.com werden nicht öffentlich sichtbar aufgelistet.
+
+ Geschwindigkeitsanzeige
+ Geschwindigkeit wird angezeigt.
+ Pace wird angezeigt.
+
+ Nur URL als Einladung zum Teilen senden
+ Beim Teilen mit Freunden wird nur die Karten-URL gesendet.
+ Beim Teilen mit Freunden wird der GPS-Track selbst gesendet.
+
+ Zerteilungsfrequenz
+ Längste Dauer oder Entfernung, nach der automatisch ein Marker eingefügt wird.
+
+ Zeitbegrenzung der Auto-Wiederaufnahme
+ Maximale Zeit in Minuten, nach der eine abgebrochene Aufzeichnung nach einem Telefonneustart wiederaufgenommen wird.
+
+ Zeitstempel als Trackname
+ Der Trackname wird aus Datum und Zeit zum Aufzeichnungsbeginn zusammengesetzt.
+ Tracknamen erhalten eine fortlaufende Nummer.
+
+ Pace
+
+ Wird nur unter Android 2.0 oder höher unterstützt
+ Sensortyp
+ Der Typ des zu verbindenden Sensors
+ Sensor-Id
+ Die zum Sensor zu sendende Id
+ Die Id muss eine Ganzzahl sein.
+ Bluetooth-Sensor
+ Der zu verbindende Bluetoothsensor
+ Art der Datenanzeige
+
+ Datensicherung (BETA)
+ SD-Karten-Sicherung
+ Jetzt sichern
+ Eine Kopie aller Deiner Tracks und Einstellungen auf die SD-Karte schreiben
+ Jetzt wiederherstellen
+ Alle Tracks und Einstellungen von der SD-Karte holen.
+ Während ein Track aufgezeichnet wird, kann nicht mit der Datensicherung gearbeitet werden.
+
+
+ Eine Wiederherstellung von der SD-Karte ÜBERSCHREIBT alle vorhandenen Tracks und Einstellungen. Willst Du das wirklich?
+ Wähle die wiederherzustellende Datensicherung aus
+ Keine Datensicherungen gefunden.
+ Schreibe alle Tracks und Einstellungen auf die SD-Karte. Dies kann eine Weile dauern...
+ Lese alle Tracks und Einstellungen von der SD-Karte. Dies kann eine Weile dauern...
+
+
+ GPS-Satelliten
+
+
+ Wähle eine Karte von Deinem Konto aus
+ Neue Karte erstellen…
+ An Google My Maps senden
+ Karten werden geladen…
+ Deine Karten konnten im Augenblick nicht geladen werden!
+ Diese Karte auswählen
+ Kartendetails bearbeiten
+ Karte mit Freunden teilen
+ Track mit Freunden teilen
+ Karte vom Konto löschen
+ Kartentitel
+ Trackbeschreibung
+ Diese Karte und ihren Inhalt in Suchergebnissen sichtbar machen.
+ Diese Karte und ihren Inhalt nicht in Suchergebnissen sichtbar machen.
+ Diese Karte und ihr Inhalt sind in Suchergebnissen sichtbar.
+ Weder diese Karte noch ihr Inhalt sind in Suchergebnissen sichtbar, allerdings kann sie trotzdem von anderen durch einen direkten Link angezeigt werden.
+ Schließen
+ Bearbeiten
+ Abbrechen
+ Sichern
+
+
+ Ich möchte gerne eine Karte mit Dir teilen.
Vielleicht interessierst Du Dich für diese Karte:
-
- %s
- Ich möchte einen GPS-Track mit Dir teilen
- Vielleicht interessierst Du Dich für diesen GPS-Track. Er kann in Google Earth und anderen Programmen dargestellt werden.
+
+ %s
+ Ich möchte einen GPS-Track mit Dir teilen
+ Vielleicht interessierst Du Dich für diese Track:
+
+ %s.
-
- Öffentlich
- Nicht in Suchergebnissen enthalten.
- Du hast noch keine Karten.
-
-
-
- Durchschnitt in Bew.
- Durchschnitt in Bew.
-
-
- Durchschnittsgeschw.
- Durchschnittstempo
-
- Höhenprofil
- Höhengewinn
- Höhe
- Breitengrad
- Längengrad
-
-
- Niedrigste Höhenlage
- Minimale Steigung
- Schnellstes Tempo
-
-
- Höchste Höhenlage
- Maximale Steigung
- Max. Geschwindigkeit
-
- Lade Track…
-
-
- Diagramm-Einstellungen
-
- X-Achse
- Nach Entfernung
- Nach Zeit
-
-
- Y-Achse
-
-
-
- Stunde
- Stunden
- Std
- Min
- Minute
- Minuten
- Sekunde
- Sekunden
- ms
-
-
- m
- km
- Kilometer
- Fuß
- mi
- Meilen
-
-
- km/h
- Kilometer pro Stunde
- min/km
- pro Kilometer
- mi/h
- Meilen pro Stunde
- min/mi
- pro Meile
-
-
- W
-
- U/Min
- bpm
-
-
- Zeit in Bewegung
- Gesamtzeit
- Zeit
- SD-Karte nicht verfügbar
- Geschwindigkeit
- Sie müssen erst eine Strecke zurücklegen.
- Statistik
- Gesamtentfernung
- Entfernung
- Kraft
- Trittfrequenz
- Puls
- Maximalpuls
- -
- Bitte warten…
-
-
- Lizenzvereinbarung für Endnutzer
- Akzeptieren
- Ablehnen
-
-
- Über
- Hilfe
- Team:
- Version:
- Unterstützung
- Unterstützung:
-
-
- Senden an…
- Google My Maps
- Google Text & Tabellen
- Jetzt senden
- Neue Karte erstellen
- Eine Karte auswählen
- Trackstatistik senden
- Statistik und Punkte senden
-
-
- Kein Konto vorhanden
- Kein Konto gefunden um Tracks zu versenden.
- Wählen Sei ein Konto
-
-
- Keine externes Speichermedium verfügbar. Stellen Sie sicher, dass eine SD-Karte vorhanden ist und nicht bereits von einem Computer darauf zugegriffen wird.
- Die Datei kann nicht geschrieben werden.
- Datei kann nicht gelesen werden.
- Das Verzeichnis auf der SD-Karte kann nicht erstellt werden.
- Der Track wurde auf die SD-Karte geschrieben.
- Lesen der Daten von SD-Karte beendet.
-
-
- Suche nach neuer Version
- Jetzt aktualisieren
- Fortfahren ohne zu aktualisieren
- Ihre Version von %1$s funktioniert möglicherweise nicht mehr richtig und wird nicht mehr unterstützt. Bitte aktualisieren Sie %1$s.
- Ihre Version von %1$s funktioniert möglicherweise nicht mehr richtig. Sie können sie jetzt aktualisieren, oder auf sie auf eigene Gefahr weiterverwenden. Einige Funktionen wie Datenaustausch mit Google-Diensten wird möglicherweise nicht mehr funktionieren, solange Sie die Software nicht aktualisieren.
- Eine neue Version von %1$s ist jetzt verfügbar. Sie können Ihre aktuelle Version ohne Probleme weiterverwenden, aber um die neuesten Funktionen in Anspruch nehmen zu können, müssen sie die Software aktualisieren.
-
-
- Willkommen
- OK
- Über My Tracks
-
-
- My Tracks keine Entfernung
+
+ Öffentlich
+ Nicht in Suchergebnissen enthalten.
+ Du hast noch keine Karten.
+
+
+
+ Durchschnitt in Bew.
+ Pace in Bew.
+
+
+ Durchschnittsgeschw.
+ Durchschnitts-Pace
+
+ Höhenprofil
+ Höhengewinn
+ Höhe
+ Breitengrad
+ Längengrad
+
+
+ Niedrigste Höhenlage
+ Minimale Steigung
+ Minimaler Pace
+
+
+ Höchste Höhenlage
+ Maximale Steigung
+ Max. Geschwindigkeit
+
+ Lade Track…
+
+
+ Diagramm-Einstellungen
+
+ X-Achse
+ Nach Entfernung
+ Nach Zeit
+
+
+ Y-Achse
+
+
+
+ Stunde
+ Stunden
+ Std
+ Minute
+ Minuten
+ Sekunde
+ Sekunden
+
+
+ Fuß
+ Kilometer
+ Meilen
+
+
+ Kilometer pro Stunde
+ pro Kilometer
+ Meilen pro Stunde
+ pro Meile
+
+
+ Zeit in Bewegung
+ Gesamtzeit
+ Zeit
+ SD-Karte nicht verfügbar
+ Geschwindigkeit
+ Du musst erst eine Aufzeichnung beginnen.
+ Statistik
+ Gesamtentfernung
+ Entfernung
+ Energie
+ Kadenz
+ Herzfrequenz
+ Höchste Herzfrequenz
+ Bitte warten…
+
+
+ Lizenzvereinbarung für Endverbraucher
+ Akzeptieren
+ Ablehnen
+
+
+ Über
+ Hilfe
+ Unterstützung
+
+
+ Senden an…
+ Jetzt senden
+ Neue Karte erstellen
+ Eine Karte auswählen
+ Trackstatistik senden
+ Statistik und Punkte senden
+
+
+ Kein Konto vorhanden
+ Kein Konto gefunden, um Tracks zu versenden.
+ Wähle ein Konto
+
+
+ Keine externes Speichermedium verfügbar. Stelle sicher, dass eine SD-Karte vorhanden ist und nicht bereits von einem Computer darauf zugegriffen wird.
+ Die Datei kann nicht geschrieben werden.
+ Die Datei konnte nicht gelesen werden.
+ Das Verzeichnis auf der SD-Karte kann nicht erstellt werden.
+ Der Track wurde auf die SD-Karte geschrieben.
+ Lesen von der SD-Karte beendet.
+
+
+ Suche nach neuer Version
+ Jetzt aktualisieren
+ Fortfahren, ohne zu aktualisieren
+ Deine Version von %1$s funktioniert möglicherweise nicht mehr richtig und wird nicht mehr unterstützt. Bitte aktualisiere %1$s.
+ Deine Version von %1$s funktioniert möglicherweise nicht mehr richtig. Du kannst sie jetzt aktualisieren, oder auf sie auf eigene Gefahr weiterverwenden. Einige Funktionen wie Datenaustausch mit Google-Diensten werden möglicherweise nicht mehr funktionieren, solange Du die Software nicht aktualisierst.
+ Eine neue Version von %1$s ist jetzt verfügbar. Du kannst Deine installierte Version ohne Probleme weiterverwenden, aber um die neuesten Funktionen in Anspruch nehmen zu können, musst Du die Software aktualisieren.
+
+
+ Willkommen
+ Über My Tracks
+
+
+ My Tracks keine Entfernung
- My Tracks %1$s %2$.2f %3$s in %4$s mit %5$s %6$s
-
-
- Hinweis zu Maßeinheiten
- Per Voreinstellung werden metrische Einheiten verwendet. Möchten Sie das ändern?
-
-
- Bluetooth
- Bluetooth-Einstellungen
- Gerätepaarung
- Öffnen Sie die Bluetooth-Paarung der Android-Einstellungen
- bluetoothSensorsEnabled
- Sensor-Einstellungen
-
-
-
- Verbunden mit %s
- Verbinden mit Bluetooth-Sensor...
- Bluetooth-Sensor nicht verbunden
-
-
- Sensor Data Time
- Kraftmesser aktiviert
- Pulsmesser aktiviert
- Kein Sensor-Manager
- Aktiviert
- Verbinde
- Verbunden
- Nicht verbunden
- Kein Sensor-Dienst
- Suche
- Sendet Daten
-
-
- receive track recording notifications
- read recorded track data
- write recorded track data, start/stop recording tracks
- Be notified when a track starts or stops being recorded.
- Be able to read track data, such as points and waypoints.
- Be able to write track data, such as starting recording or adding waypoints.
-
+ -->
+ My Tracks %1$s %2$.2f %3$s in %4$s mit %5$s %6$s
+
+
+ Einheitenbenachrichtigung
+ Voreingestellt sind metrische Einheiten. Willst Du diese Einstellung ändern?
+
+
+ Bluetootheinstellungen
+ Geräteverbindung
+ Öffnet Androids Bluetootheinstellungen, um Geräte zu verbinden.
+ Sensoreinstellungen
+
+
+ Verbunden mit %s
+ Verbinde mit Bluetoothsensor ...
+ Bluetoothsensor nicht verbunden.
+
+
+ Sensor Data Time
+ Energiemessung aktiviert
+ Herzfrequenzmessung aktiviert
+ Keine Sensoren verfügbar
+ Aktiviert
+ Verbinde...
+ Verbunden
+ Getrennt
+ Kein Sensor-Dienst
+ Suche...
+ Sende...
+
+
+ Track-Aufzeichnungs-Benachrichtigungen empfangen
+ Aufgezeichnete Trackdaten lesen
+ Aufgezeichnete Trackdaten schreiben, Starten/Anhalten des Aufzeichnens von Tracks
+ Werde benachrichtigt, wenn die Aufzeichnung eines Tracks beginnt oder anhält.
+ Ermöglicht das Lesen von Trackdaten wie Messpunkten oder Wegpunkten.
+ Ermöglicht das Schreiben von Trackdaten wie beim Starten der Aufzeichnung oder beim Hinzufügen von Wegpunkten.
+
diff --git a/MyTracks/res/values/arrays.xml b/MyTracks/res/values/arrays.xml
index 3eb41e8fe..964befc7d 100644
--- a/MyTracks/res/values/arrays.xml
+++ b/MyTracks/res/values/arrays.xml
@@ -393,12 +393,16 @@ limitations under the License.
- None
+ - ANT+ Sensors
+ - SRM ANT+ Bridge
- Zephyr Bluetooth
- @string/none
+ - @string/ant_sensor_type
+ - @string/srm_ant_bridge_sensor_type
- @string/zephyr_sensor_type
diff --git a/MyTracks/res/values/do_not_translate.xml b/MyTracks/res/values/do_not_translate.xml
new file mode 100644
index 000000000..32095d881
--- /dev/null
+++ b/MyTracks/res/values/do_not_translate.xml
@@ -0,0 +1,36 @@
+
+
+
+
+ My Tracks
+
+
+ mytracks@googlegroups.com
+ mytracks.appspot.com
+ Copyright 2009 Google Inc.
+ Bartlomiej Niechwiej
+ Dylan Casey
+ Leif Hendrik Wilden
+ Rodrigo Damazio Bovendorp
+ Sandor Dornbush
+
+
+ NONE
+ ANT
+ SRM_ANT_BRIDGE
+ ZEPHYR
+
diff --git a/MyTracks/res/values/keys.xml b/MyTracks/res/values/keys.xml
index ebf7cdf07..b8e43f668 100644
--- a/MyTracks/res/values/keys.xml
+++ b/MyTracks/res/values/keys.xml
@@ -17,6 +17,9 @@ limitations under the License.
announcementFrequency
+ antHeartRateSensorId
+ antPowerSensorId
+ antSRMBridgeSensorId
autoResumeTrackTimeout
bluetoothDevice
bluetoothPairing
diff --git a/MyTracks/res/values/strings.xml b/MyTracks/res/values/strings.xml
index a347c8ae7..10a35a347 100644
--- a/MyTracks/res/values/strings.xml
+++ b/MyTracks/res/values/strings.xml
@@ -15,9 +15,6 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
-
- My Tracks
-
Record track
Stop recording
@@ -216,15 +213,15 @@ limitations under the License.
Only supported in Android 2.0 or above
Sensor Type
- The type of sensor to connect to.
- Sensor Id
- The Id sent to sensors.
- The Id must be an integer value.
+ The type of sensor to connect to
+ Clear ANT heart rate sensor pairing
+ Clear ANT power sensor pairing
+ Clear ANT srm bridge sensor pairing
+ ANT sensor not paired
+ ANT sensor paired with: %d
Bluetooth sensor
- The bluetooth sensor to connect to.
+ The bluetooth sensor to connect to
Modular Stats Display
- The stats screen is split in various modes.
- Display all stats on one screen
Backup (BETA)
@@ -384,16 +381,6 @@ limitations under the License.
Support
Support:
-
- mytracks@googlegroups.com
- mytracks.appspot.com
- Copyright 2009 Google Inc.
- Bartlomiej Niechwiej
- Dylan Casey
- Leif Hendrik Wilden
- Rodrigo Damazio Bovendorp
- Sandor Dornbush
-
Send to...
Google My Maps
@@ -454,10 +441,6 @@ limitations under the License.
bluetoothSensorsEnabled
Sensor Options
-
- NONE
- ZEPHYR
-
Connected to %s
Bluetooth sensor connecting ...
diff --git a/MyTracks/res/xml/preferences.xml b/MyTracks/res/xml/preferences.xml
index c0b519386..7e9ec97c9 100644
--- a/MyTracks/res/xml/preferences.xml
+++ b/MyTracks/res/xml/preferences.xml
@@ -122,6 +122,18 @@ limitations under the License.
android:summary="@string/bluetooth_pairing_summary"
android:persistent="false" />
+
+
+
+
+
+
diff --git a/MyTracks/src/com/dsi/ant/AntDefine.java b/MyTracks/src/com/dsi/ant/AntDefine.java
new file mode 100644
index 000000000..4aabb7eb2
--- /dev/null
+++ b/MyTracks/src/com/dsi/ant/AntDefine.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2010 Dynastream Innovations 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.dsi.ant;
+
+
+
+/**
+ * The Android Ant API is not finalized, and *will* change. Use at your
+ * own risk.
+ *
+ * Public API for controlling the Ant Service.
+ * AntDefines contains definitions commonly used in ANT messaging.
+ *
+ * @hide
+ */
+public class AntDefine {
+
+ //////////////////////////////////////////////
+ // Library Version Information
+ //////////////////////////////////////////////
+ public static final int ANT_LIBRARY_VERSION_CODE = 5;
+ public static final int ANT_LIBRARY_VERSION_MAJOR = 1;
+ public static final int ANT_LIBRARY_VERSION_MINOR = 4;
+ public static final String ANT_LIBRARY_VERSION_NAME = String.valueOf(ANT_LIBRARY_VERSION_MAJOR) + "." + String.valueOf(ANT_LIBRARY_VERSION_MINOR);
+
+ //////////////////////////////////////////////
+ // Valid Configuration Values
+ //////////////////////////////////////////////
+ public static final byte MIN_BIN = 0;
+ public static final byte MAX_BIN = 10;
+
+ public static final short MIN_DEVICE_ID = 0;
+ public static final short MAX_DEVICE_ID = (short)65535;
+
+ public static final short MIN_BUFFER_THRESHOLD = 0;
+ public static final short MAX_BUFFER_THRESHOLD = 996;
+
+ //////////////////////////////////////////////
+ // ANT Message Payload Size
+ //////////////////////////////////////////////
+ public static final byte ANT_STANDARD_DATA_PAYLOAD_SIZE =((byte)8);
+
+ //////////////////////////////////////////////
+ // ANT LIBRARY Extended Data Message Fields
+ // NOTE: You must check the extended message
+ // bitfield first to find out which fields
+ // are present before accessing them!
+ //////////////////////////////////////////////
+ public static final byte ANT_EXT_MESG_DEVICE_ID_FIELD_SIZE =((byte)4);
+ //public static final byte ANT_EXT_STRING_SIZE =((byte)19); // this is the additional buffer space required required for setting USB Descriptor strings
+ public static final byte ANT_EXT_STRING_SIZE =((byte)0); // changed to 0 as we will not be dealing with ANT USB parts.
+
+ //////////////////////////////////////////////
+ // ANT Extended Data Message Bifield Definitions
+ //////////////////////////////////////////////
+ public static final byte ANT_EXT_MESG_BITFIELD_DEVICE_ID =((byte)0x80); // first field after bitfield
+ public static final byte ANT_EXT_MESG_BITFIELD_RSSI =((byte)0x40); // next field after ID, if there is one
+ public static final byte ANT_EXT_MESG_BITFIELD_TIME_STAMP =((byte)0x20); // next field after RSSI, if there is one
+
+ // 4 bits free reserved set to 0
+ public static final byte ANT_EXT_MESG_BIFIELD_EXTENSION =((byte)0x01);
+
+ // extended message input bitfield defines
+ public static final byte ANT_EXT_MESG_BITFIELD_OVERWRITE_SHARED_ADR =((byte)0x10);
+ public static final byte ANT_EXT_MESG_BITFIELD_TRANSMISSION_TYPE =((byte)0x08);
+
+ //////////////////////////////////////////////
+ // ID Definitions
+ //////////////////////////////////////////////
+ public static final byte ANT_ID_SIZE =((byte)4);
+ public static final byte ANT_ID_TRANS_TYPE_OFFSET =((byte)3);
+ public static final byte ANT_ID_DEVICE_TYPE_OFFSET =((byte)2);
+ public static final byte ANT_ID_DEVICE_NUMBER_HIGH_OFFSET =((byte)1);
+ public static final byte ANT_ID_DEVICE_NUMBER_LOW_OFFSET =((byte)0);
+ public static final byte ANT_ID_DEVICE_TYPE_PAIRING_FLAG =((byte)0x80);
+
+ public static final byte ANT_TRANS_TYPE_SHARED_ADDR_MASK =((byte)0x03);
+ public static final byte ANT_TRANS_TYPE_1_BYTE_SHARED_ADDRESS =((byte)0x02);
+ public static final byte ANT_TRANS_TYPE_2_BYTE_SHARED_ADDRESS =((byte)0x03);
+
+ //////////////////////////////////////////////
+ // Assign Channel Parameters
+ //////////////////////////////////////////////
+ public static final byte PARAMETER_RX_NOT_TX =((byte)0x00);
+ public static final byte PARAMETER_TX_NOT_RX =((byte)0x10);
+ public static final byte PARAMETER_SHARED_CHANNEL =((byte)0x20);
+ public static final byte PARAMETER_NO_TX_GUARD_BAND =((byte)0x40);
+ public static final byte PARAMETER_ALWAYS_RX_WILD_CARD_SEARCH_ID =((byte)0x40); //Pre-AP2
+ public static final byte PARAMETER_RX_ONLY =((byte)0x40);
+
+ //////////////////////////////////////////////
+ // Ext. Assign Channel Parameters
+ //////////////////////////////////////////////
+ public static final byte EXT_PARAM_ALWAYS_SEARCH =((byte)0x01);
+ public static final byte EXT_PARAM_FREQUENCY_AGILITY =((byte)0x04);
+
+ //////////////////////////////////////////////
+ // Radio TX Power Definitions
+ //////////////////////////////////////////////
+ public static final byte RADIO_TX_POWER_LVL_MASK =((byte)0x03);
+
+ public static final byte RADIO_TX_POWER_LVL_0 =((byte)0x00); //(formerly: RADIO_TX_POWER_MINUS20DB); lowest
+ public static final byte RADIO_TX_POWER_LVL_1 =((byte)0x01); //(formerly: RADIO_TX_POWER_MINUS10DB);
+ public static final byte RADIO_TX_POWER_LVL_2 =((byte)0x02); //(formerly: RADIO_TX_POWER_MINUS5DB);
+ public static final byte RADIO_TX_POWER_LVL_3 =((byte)0x03); //(formerly: RADIO_TX_POWER_0DB); highest
+
+ //////////////////////////////////////////////
+ // Channel Status
+ //////////////////////////////////////////////
+ public static final byte STATUS_CHANNEL_STATE_MASK =((byte)0x03);
+ public static final byte STATUS_UNASSIGNED_CHANNEL =((byte)0x00);
+ public static final byte STATUS_ASSIGNED_CHANNEL =((byte)0x01);
+ public static final byte STATUS_SEARCHING_CHANNEL =((byte)0x02);
+ public static final byte STATUS_TRACKING_CHANNEL =((byte)0x03);
+
+ //////////////////////////////////////////////
+ // Standard capabilities defines
+ //////////////////////////////////////////////
+ public static final byte CAPABILITIES_NO_RX_CHANNELS =((byte)0x01);
+ public static final byte CAPABILITIES_NO_TX_CHANNELS =((byte)0x02);
+ public static final byte CAPABILITIES_NO_RX_MESSAGES =((byte)0x04);
+ public static final byte CAPABILITIES_NO_TX_MESSAGES =((byte)0x08);
+ public static final byte CAPABILITIES_NO_ACKD_MESSAGES =((byte)0x10);
+ public static final byte CAPABILITIES_NO_BURST_TRANSFER =((byte)0x20);
+
+ //////////////////////////////////////////////
+ // Advanced capabilities defines
+ //////////////////////////////////////////////
+ public static final byte CAPABILITIES_OVERUN_UNDERRUN =((byte)0x01); // Support for this functionality has been dropped
+ public static final byte CAPABILITIES_NETWORK_ENABLED =((byte)0x02);
+ public static final byte CAPABILITIES_AP1_VERSION_2 =((byte)0x04); // This Version of the AP1 does not support transmit and only had a limited release
+ public static final byte CAPABILITIES_SERIAL_NUMBER_ENABLED =((byte)0x08);
+ public static final byte CAPABILITIES_PER_CHANNEL_TX_POWER_ENABLED =((byte)0x10);
+ public static final byte CAPABILITIES_LOW_PRIORITY_SEARCH_ENABLED =((byte)0x20);
+ public static final byte CAPABILITIES_SCRIPT_ENABLED =((byte)0x40);
+ public static final byte CAPABILITIES_SEARCH_LIST_ENABLED =((byte)0x80);
+
+ //////////////////////////////////////////////
+ // Advanced capabilities 2 defines
+ //////////////////////////////////////////////
+ public static final byte CAPABILITIES_LED_ENABLED =((byte)0x01);
+ public static final byte CAPABILITIES_EXT_MESSAGE_ENABLED =((byte)0x02);
+ public static final byte CAPABILITIES_SCAN_MODE_ENABLED =((byte)0x04);
+ public static final byte CAPABILITIES_RESERVED =((byte)0x08);
+ public static final byte CAPABILITIES_PROX_SEARCH_ENABLED =((byte)0x10);
+ public static final byte CAPABILITIES_EXT_ASSIGN_ENABLED =((byte)0x20);
+ public static final byte CAPABILITIES_FREE_1 =((byte)0x40);
+ public static final byte CAPABILITIES_FIT1_ENABLED =((byte)0x80);
+
+ //////////////////////////////////////////////
+ // Advanced capabilities 3 defines
+ //////////////////////////////////////////////
+ public static final byte CAPABILITIES_SENSRCORE_ENABLED =((byte)0x01);
+ public static final byte CAPABILITIES_RESERVED_1 =((byte)0x02);
+ public static final byte CAPABILITIES_RESERVED_2 =((byte)0x04);
+ public static final byte CAPABILITIES_RESERVED_3 =((byte)0x08);
+
+
+ //////////////////////////////////////////////
+ // Burst Message Sequence
+ //////////////////////////////////////////////
+ public static final byte CHANNEL_NUMBER_MASK =((byte)0x1F);
+ public static final byte SEQUENCE_NUMBER_MASK =((byte)0xE0);
+ public static final byte SEQUENCE_NUMBER_ROLLOVER =((byte)0x60);
+ public static final byte SEQUENCE_FIRST_MESSAGE =((byte)0x00);
+ public static final byte SEQUENCE_LAST_MESSAGE =((byte)0x80);
+ public static final byte SEQUENCE_NUMBER_INC =((byte)0x20);
+
+ //////////////////////////////////////////////
+ // Control Message Flags
+ //////////////////////////////////////////////
+ public static final byte BROADCAST_CONTROL_BYTE =((byte)0x00);
+ public static final byte ACKNOWLEDGED_CONTROL_BYTE =((byte)0xA0);
+
+ //////////////////////////////////////////////
+ // Response / Event Codes
+ //////////////////////////////////////////////
+ public static final byte RESPONSE_NO_ERROR =((byte)0x00);
+ public static final byte NO_EVENT =((byte)0x00);
+
+ public static final byte EVENT_RX_SEARCH_TIMEOUT =((byte)0x01);
+ public static final byte EVENT_RX_FAIL =((byte)0x02);
+ public static final byte EVENT_TX =((byte)0x03);
+ public static final byte EVENT_TRANSFER_RX_FAILED =((byte)0x04);
+ public static final byte EVENT_TRANSFER_TX_COMPLETED =((byte)0x05);
+ public static final byte EVENT_TRANSFER_TX_FAILED =((byte)0x06);
+ public static final byte EVENT_CHANNEL_CLOSED =((byte)0x07);
+ public static final byte EVENT_RX_FAIL_GO_TO_SEARCH =((byte)0x08);
+ public static final byte EVENT_CHANNEL_COLLISION =((byte)0x09);
+ public static final byte EVENT_TRANSFER_TX_START =((byte)0x0A); // a pending transmit transfer has begun
+
+ public static final byte EVENT_CHANNEL_ACTIVE =((byte)0x0F);
+
+ public static final byte EVENT_TRANSFER_TX_NEXT_MESSAGE =((byte)0x11); // only enabled in FIT1
+
+ public static final byte CHANNEL_IN_WRONG_STATE =((byte)0x15); // returned on attempt to perform an action from the wrong channel state
+ public static final byte CHANNEL_NOT_OPENED =((byte)0x16); // returned on attempt to communicate on a channel that is not open
+ public static final byte CHANNEL_ID_NOT_SET =((byte)0x18); // returned on attempt to open a channel without setting the channel ID
+ public static final byte CLOSE_ALL_CHANNELS =((byte)0x19); // returned when attempting to start scanning mode, when channels are still open
+
+ public static final byte TRANSFER_IN_PROGRESS =((byte)0x1F); // returned on attempt to communicate on a channel with a TX transfer in progress
+ public static final byte TRANSFER_SEQUENCE_NUMBER_ERROR =((byte)0x20); // returned when sequence number is out of order on a Burst transfer
+ public static final byte TRANSFER_IN_ERROR =((byte)0x21);
+ public static final byte TRANSFER_BUSY =((byte)0x22);
+
+ public static final byte INVALID_MESSAGE_CRC =((byte)0x26); // returned if there is a framing error on an incomming message
+ public static final byte MESSAGE_SIZE_EXCEEDS_LIMIT =((byte)0x27); // returned if a data message is provided that is too large
+ public static final byte INVALID_MESSAGE =((byte)0x28); // returned when the message has an invalid parameter
+ public static final byte INVALID_NETWORK_NUMBER =((byte)0x29); // returned when an invalid network number is provided
+ public static final byte INVALID_LIST_ID =((byte)0x30); // returned when the provided list ID or size exceeds the limit
+ public static final byte INVALID_SCAN_TX_CHANNEL =((byte)0x31); // returned when attempting to transmit on channel 0 when in scan mode
+
+ public static final byte INVALID_PARAMETER_PROVIDED =((byte)0x33); // returned when an invalid parameter is specified in a configuration message
+
+ public static final byte EVENT_SERIAL_QUE_OVERFLOW =((byte)0x34);
+ public static final byte EVENT_QUE_OVERFLOW =((byte)0x35); // ANT event que has overflowed and lost 1 or more events
+
+ public static final byte EVENT_CLK_ERROR =((byte)0x36); // debug event for XOSC16M on LE1
+
+ public static final byte SCRIPT_FULL_ERROR =((byte)0x40); // error writing to script, memory is full
+ public static final byte SCRIPT_WRITE_ERROR =((byte)0x41); // error writing to script, bytes not written correctly
+ public static final byte SCRIPT_INVALID_PAGE_ERROR =((byte)0x42); // error accessing script page
+ public static final byte SCRIPT_LOCKED_ERROR =((byte)0x43); // the scripts are locked and can't be dumped
+
+ public static final byte NO_RESPONSE_MESSAGE =((byte)0x50); // returned to the Command_SerialMessageProcess function, so no reply message is generated
+ public static final byte RETURN_TO_MFG =((byte)0x51); // default return to any mesg when the module determines that the mfg procedure has not been fully completed
+
+ public static final byte FIT_ACTIVE_SEARCH_TIMEOUT =((byte)0x60); // Fit1 only event added for timeout of the pairing state after the Fit module becomes active
+ public static final byte FIT_WATCH_PAIR =((byte)0x61); // Fit1 only
+ public static final byte FIT_WATCH_UNPAIR =((byte)0x62); // Fit1 only
+
+ public static final byte USB_STRING_WRITE_FAIL =((byte)0x70);
+
+ // Internal only events below this point
+ public static final byte INTERNAL_ONLY_EVENTS =((byte)0x80);
+ public static final byte EVENT_RX =((byte)0x80); // INTERNAL: Event for a receive message
+ public static final byte EVENT_NEW_CHANNEL =((byte)0x81); // INTERNAL: EVENT for a new active channel
+ public static final byte EVENT_PASS_THRU =((byte)0x82); // INTERNAL: Event to allow an upper stack events to pass through lower stacks
+
+ public static final byte EVENT_BLOCKED =((byte)0xFF); // INTERNAL: Event to replace any event we do not wish to go out, will also zero the size of the Tx message
+
+ ///////////////////////////////////////////////////////
+ // Script Command Codes
+ ///////////////////////////////////////////////////////
+ public static final byte SCRIPT_CMD_FORMAT =((byte)0x00);
+ public static final byte SCRIPT_CMD_DUMP =((byte)0x01);
+ public static final byte SCRIPT_CMD_SET_DEFAULT_SECTOR =((byte)0x02);
+ public static final byte SCRIPT_CMD_END_SECTOR =((byte)0x03);
+ public static final byte SCRIPT_CMD_END_DUMP =((byte)0x04);
+ public static final byte SCRIPT_CMD_LOCK =((byte)0x05);
+
+ ///////////////////////////////////////////////////////
+ // Reset Mesg Codes
+ ///////////////////////////////////////////////////////
+ public static final byte RESET_FLAGS_MASK =((byte)0xE0);
+ public static final byte RESET_SUSPEND =((byte)0x80); // this must follow bitfield def
+ public static final byte RESET_SYNC =((byte)0x40); // this must follow bitfield def
+ public static final byte RESET_CMD =((byte)0x20); // this must follow bitfield def
+ public static final byte RESET_WDT =((byte)0x02);
+ public static final byte RESET_RST =((byte)0x01);
+ public static final byte RESET_POR =((byte)0x00);
+
+}
\ No newline at end of file
diff --git a/MyTracks/src/com/dsi/ant/AntInterface.java b/MyTracks/src/com/dsi/ant/AntInterface.java
new file mode 100644
index 000000000..20d30349a
--- /dev/null
+++ b/MyTracks/src/com/dsi/ant/AntInterface.java
@@ -0,0 +1,1134 @@
+/*
+ * Copyright 2010 Dynastream Innovations 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.dsi.ant;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+
+// TODO: Auto-generated Javadoc
+
+/**
+ * Public API for controlling the Ant Service. AntInterface is a proxy
+ * object for controlling the Ant Service via IPC. Creating a AntInterface
+ * object will create a binding with the Ant service.
+ *
+ * @hide
+ */
+public class AntInterface {
+
+ /** The Log Tag. */
+ public static final String TAG = "ANTInterface";
+
+ /** Enable debug logging. */
+ public static boolean DEBUG = false;
+
+ /** Search string to find ANT Radio Proxy Service in the Android Marketplace */
+ private static final String MARKET_SEARCH_TEXT_DEFAULT = "ANT Radio Service Dynastream Innovations Inc";
+
+ /** Inter-process communication with the ANT Radio Proxy Service. */
+ public static IAnt sAntReceiver = null;
+ public static IServiceSettings sServiceSettingsReceiver = null;
+
+ /** Singleton instance of this class. */
+ private static AntInterface INSTANCE;
+
+ /** Used when obtaining a reference to the singleton instance. */
+ private static Object INSTANCE_LOCK = new Object();
+
+ /** The context to use. */
+ private static Context sContext = null;
+
+ /** Listens to changes to service connection status. */
+ private static ServiceListener sServiceListener;
+
+ /** Is the ANT Radio Proxy Service connected. */
+ private static boolean sServiceConnected = false;
+ private static boolean sServiceSettingsConnected = false;
+
+ private static int mServiceLibraryVersionCode = 0;
+
+ /**
+ * An interface for notifying AntInterface IPC clients when they have
+ * been connected to the ANT service.
+ *
+ * @see ServiceEvent
+ */
+ public interface ServiceListener
+ {
+ /**
+ * Called to notify the client when this proxy object has been
+ * connected to the ANT service. Clients must wait for
+ * this callback before making IPC calls on the ANT
+ * service.
+ */
+ public void onServiceConnected();
+
+ /**
+ * Called to notify the client that this proxy object has been
+ * disconnected from the ANT service. Clients must not
+ * make IPC calls on the ANT service after this callback.
+ * This callback will currently only occur if the application hosting
+ * the BluetoothAg service, but may be called more often in future.
+ */
+ public void onServiceDisconnected();
+ }
+
+
+ //Constructor
+ /**
+ * Instantiates a new ant interface.
+ *
+ * @param context the context
+ * @param listener the listener
+ * @since 1.0
+ */
+ private AntInterface(Context context, ServiceListener listener)
+ {
+ // This will be around as long as this process is
+ sContext = context;
+ sServiceListener = listener;
+ }
+
+ /**
+ * Gets the single instance of AntInterface, creating it if it doesn't exist.
+ *
+ * @param context the context.
+ * @param listener the listener to be notified of status changes.
+ * @return the AntInterface instance.
+ * @since 1.0
+ */
+ public static AntInterface getInstance(Context context,ServiceListener listener)
+ {
+ if(DEBUG) Log.d(TAG, "getInstance");
+
+ synchronized (INSTANCE_LOCK)
+ {
+ if (INSTANCE == null)
+ {
+ if(DEBUG) Log.d(TAG, "getInstance: Creating new instance");
+
+ // TODO: rohan: bug, each new request for an instance will not have context and listener set to the requested objects
+ INSTANCE = new AntInterface(context,listener);
+ }
+ else
+ {
+ if(DEBUG) Log.d(TAG, "getInstance: Using existing instance");
+ }
+
+ if(!sServiceConnected)
+ {
+ if(DEBUG) Log.d(TAG, "getInstance: No connection to proxy service, attempting connection");
+
+ if(!INSTANCE.initService())
+ {
+ Log.e(TAG, "getInstance: No connection to proxy service");
+
+ INSTANCE.destroy();
+ INSTANCE = null;
+ }
+ }
+
+ return INSTANCE;
+ }
+ }
+
+ /**
+ * Go to market.
+ *
+ * @param pContext the context
+ * @param pSearchText the search text
+ * @since 1.2
+ */
+ public static void goToMarket(Context pContext, String pSearchText)
+ {
+ if(null == pSearchText)
+ {
+ goToMarket(pContext);
+ }
+ else
+ {
+ if(DEBUG) Log.i(TAG, "goToMarket: Search text = "+ pSearchText);
+
+ Intent goToMarket = null;
+ goToMarket = new Intent(Intent.ACTION_VIEW,Uri.parse("http://market.android.com/search?q=" + pSearchText));
+ goToMarket.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ pContext.startActivity(goToMarket);
+ }
+ }
+
+ /**
+ * Go to market.
+ *
+ * @param pContext the context
+ * @since 1.2
+ */
+ public static void goToMarket(Context pContext)
+ {
+ if(DEBUG) Log.d(TAG, "goToMarket");
+
+ goToMarket(pContext, MARKET_SEARCH_TEXT_DEFAULT);
+ }
+
+ /**
+ * Class for interacting with the ANT interface.
+ */
+ private static ServiceConnection sIAntConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName pClassName, IBinder pService) {
+ // This is called when the connection with the service has been
+ // established, giving us the service object we can use to
+ // interact with the service. We are communicating with our
+ // service through an IDL interface, so get a client-side
+ // representation of that from the raw service object.
+ if(DEBUG) Log.d(TAG, "sIAntConnection onServiceConnected()");
+ sAntReceiver = IAnt.Stub.asInterface(pService);
+
+ sServiceConnected = true;
+
+ try
+ {
+ mServiceLibraryVersionCode = sAntReceiver.getServiceLibraryVersionCode();
+ }
+ catch(RemoteException e)
+ {
+ Log.e(TAG, "sIAntConnection onServiceConnected: Could not get service library version");
+ }
+
+ switch(mServiceLibraryVersionCode)
+ {
+ // Fall through from newer versions
+ case 5:
+ {
+ if(!sServiceSettingsConnected)
+ {
+ boolean boundServiceSettings = sContext.bindService(new Intent(IServiceSettings.class.getName()), sIServiceSettingsConnection, Context.BIND_AUTO_CREATE);
+ Log.i(TAG, "sIAntConnection onServiceConnected: Bound with ANT Service Settings: " + boundServiceSettings);
+ }
+ else
+ {
+ if(DEBUG) Log.d(TAG, "sIAntConnection onServiceConnected: Already initialised Service Settings connection");
+ }
+ }
+ }
+
+ // Notify the attached application if it is registered
+ if (sServiceListener != null)
+ {
+ sServiceListener.onServiceConnected();
+ }
+ else
+ {
+ if(DEBUG) Log.d(TAG, "sIAntConnection onServiceConnected: No service listener registered");
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName pClassName) {
+ // This is called when the connection with the service has been
+ // unexpectedly disconnected -- that is, its process crashed.
+ if(DEBUG) Log.d(TAG, "sIAntConnection onServiceDisconnected()");
+ sAntReceiver = null;
+
+ sServiceConnected = false;
+
+ // Notify the attached application if it is registered
+ if (sServiceListener != null)
+ {
+ sServiceListener.onServiceDisconnected();
+ }
+ else
+ {
+ if(DEBUG) Log.d(TAG, "sIAntConnection onServiceDisconnected: No service listener registered");
+ }
+
+ // Try and rebind to the service
+ INSTANCE.releaseService();
+ INSTANCE.initService();
+ }
+ };
+
+ /**
+ * Class for interacting with the ANT interface through the ANTLib version 5 functions.
+ */
+ private static ServiceConnection sIServiceSettingsConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName pClassName, IBinder pService) {
+ // This is called when the connection with the service has been
+ // established, giving us the service object we can use to
+ // interact with the service. We are communicating with our
+ // service through an IDL interface, so get a client-side
+ // representation of that from the raw service object.
+ if(DEBUG) Log.d(TAG, "sIServiceSettingsConnection onServiceConnected()");
+ sServiceSettingsReceiver = IServiceSettings.Stub.asInterface(pService);
+
+ sServiceSettingsConnected = true;
+ }
+
+ public void onServiceDisconnected(ComponentName pClassName) {
+ // This is called when the connection with the service has been
+ // unexpectedly disconnected -- that is, its process crashed.
+ if(DEBUG) Log.d(TAG, "sIServiceSettingsConnection onServiceDisconnected()");
+ sServiceSettingsReceiver = null;
+
+ sServiceSettingsConnected = false;
+
+ // Try and rebind to the service
+ INSTANCE.releaseService();
+ INSTANCE.initService();
+ }
+ };
+
+
+ /**
+ * Binds this activity to the ANT service.
+ *
+ * @return true, if successful
+ */
+ private boolean initService() {
+ if(DEBUG) Log.d(TAG, "initService() entered");
+
+ boolean ret = false;
+
+ if(!sServiceConnected)
+ {
+ ret = sContext.bindService(new Intent(IAnt.class.getName()), sIAntConnection, Context.BIND_AUTO_CREATE);
+ Log.i(TAG, "initService(): Bound with ANT service: " + ret);
+ }
+ else
+ {
+ if(DEBUG) Log.d(TAG, "initService: already initialised service");
+ ret = true;
+ }
+
+ return ret;
+ }
+
+ /** Unbinds this activity from the ANT service. */
+ private void releaseService() {
+ if(DEBUG) Log.d(TAG, "releaseService() entered");
+
+ if(sServiceConnected)
+ {
+ sContext.unbindService(sIAntConnection);
+ sServiceConnected = false;
+ }
+
+ if(sServiceSettingsConnected)
+ {
+ sContext.unbindService(sIServiceSettingsConnection);
+ sServiceSettingsConnected = false;
+ }
+
+ if(DEBUG) Log.d(TAG, "releaseService() unbound.");
+ }
+
+ /**
+ * True if this activity can communicate with the ANT service.
+ *
+ * @return true, if is service connected
+ * @since 1.2
+ */
+ public boolean isServiceConnected()
+ {
+ return sServiceConnected;
+ }
+
+ /**
+ * Destroy.
+ *
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean destroy()
+ {
+ if(DEBUG) Log.d(TAG, "destroy");
+
+ releaseService();
+
+ INSTANCE = null;
+
+ return true;
+ }
+
+
+ /**
+ * Ant service connection lost.
+ */
+ private void antServiceConnectionLost()
+ {
+ Log.e(TAG, "Connection to ANT service lost");
+ }
+
+ /**
+ * Ant service connection to settings binder lost.
+ */
+ private void antServiceSettingsConnectionLost()
+ {
+ Log.e(TAG, "Connection to ANT service settings lost");
+ }
+
+
+ ////-------------------------------------------------
+
+ /**
+ * Enable.
+ *
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean enable()
+ {
+ if(DEBUG) Log.d(TAG, "enable");
+
+ if(!sServiceConnected)
+ {
+ // Haven't received 'onConnected' notification yet
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.enable();
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * Disable.
+ *
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean disable()
+ {
+ if(DEBUG) Log.d(TAG, "disable");
+
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.disable();
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * Checks if is enabled.
+ *
+ * @return true, if is enabled
+ * @since 1.0
+ */
+ public boolean isEnabled()
+ {
+ if(DEBUG) Log.d(TAG, "isEnabled");
+
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.isEnabled();
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT tx message.
+ *
+ * @param message the message
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTTxMessage(byte[] message)
+ {
+ if(DEBUG) Log.d(TAG, "ANTTxMessage");
+
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTTxMessage(message);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT reset system.
+ *
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTResetSystem()
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTResetSystem();
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT unassign channel.
+ *
+ * @param channelNumber the channel number
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTUnassignChannel(byte channelNumber)
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTUnassignChannel(channelNumber);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT assign channel.
+ *
+ * @param channelNumber the channel number
+ * @param channelType the channel type
+ * @param networkNumber the network number
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTAssignChannel(byte channelNumber, byte channelType, byte networkNumber)
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTAssignChannel(channelNumber, channelType, networkNumber);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT set channel id.
+ *
+ * @param channelNumber the channel number
+ * @param deviceNumber the device number
+ * @param deviceType the device type
+ * @param txType the tx type
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTSetChannelId(byte channelNumber, short deviceNumber, byte deviceType, byte txType)
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTSetChannelId(channelNumber, deviceNumber, deviceType, txType);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT set channel period.
+ *
+ * @param channelNumber the channel number
+ * @param channelPeriod the channel period
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTSetChannelPeriod(byte channelNumber, short channelPeriod)
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTSetChannelPeriod(channelNumber, channelPeriod);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT set channel rf freq.
+ *
+ * @param channelNumber the channel number
+ * @param radioFrequency the radio frequency
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTSetChannelRFFreq(byte channelNumber, byte radioFrequency)
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTSetChannelRFFreq(channelNumber, radioFrequency);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT set channel search timeout.
+ *
+ * @param channelNumber the channel number
+ * @param searchTimeout the search timeout
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTSetChannelSearchTimeout(byte channelNumber, byte searchTimeout)
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTSetChannelSearchTimeout(channelNumber, searchTimeout);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT set low priority channel search timeout.
+ *
+ * @param channelNumber the channel number
+ * @param searchTimeout the search timeout
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTSetLowPriorityChannelSearchTimeout(byte channelNumber, byte searchTimeout)
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTSetLowPriorityChannelSearchTimeout(channelNumber, searchTimeout);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT set proximity search.
+ *
+ * @param channelNumber the channel number
+ * @param searchThreshold the search threshold
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTSetProximitySearch(byte channelNumber, byte searchThreshold)
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTSetProximitySearch(channelNumber, searchThreshold);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT set channel transmit power
+ * @param channelNumber the channel number
+ * @param txPower the transmit power level
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTSetChannelTxPower(byte channelNumber, byte txPower)
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTSetChannelTxPower(channelNumber, txPower);
+ } catch (RemoteException ex)
+ {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+
+ /**
+ * ANT add channel id.
+ *
+ * @param channelNumber the channel number
+ * @param deviceNumber the device number
+ * @param deviceType the device type
+ * @param txType the tx type
+ * @param listIndex the list index
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTAddChannelId(byte channelNumber, short deviceNumber, byte deviceType, byte txType, byte listIndex)
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTAddChannelId(channelNumber, deviceNumber, deviceType, txType, listIndex);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT config list.
+ *
+ * @param channelNumber the channel number
+ * @param listSize the list size
+ * @param exclude the exclude
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTConfigList(byte channelNumber, byte listSize, byte exclude)
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTConfigList(channelNumber, listSize, exclude);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT config event buffering.
+ *
+ * @param screenOnFlushTimerInterval the screen on flush timer interval
+ * @param screenOnFlushBufferThreshold the screen on flush buffer threshold
+ * @param screenOffFlushTimerInterval the screen off flush timer interval
+ * @param screenOffFlushBufferThreshold the screen off flush buffer threshold
+ * @return true, if successful
+ * @since 1.3
+ */
+ public boolean ANTConfigEventBuffering(short screenOnFlushTimerInterval, short screenOnFlushBufferThreshold, short screenOffFlushTimerInterval, short screenOffFlushBufferThreshold)
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTConfigEventBuffering((int)screenOnFlushTimerInterval, (int)screenOnFlushBufferThreshold, (int)screenOffFlushTimerInterval, (int)screenOffFlushBufferThreshold);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT disable event buffering.
+ *
+ * @return true, if successful
+ * @since 1.1
+ */
+ public boolean ANTDisableEventBuffering()
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTDisableEventBuffering();
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT open channel.
+ *
+ * @param channelNumber the channel number
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTOpenChannel(byte channelNumber)
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTOpenChannel(channelNumber);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT close channel.
+ *
+ * @param channelNumber the channel number
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTCloseChannel(byte channelNumber)
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTCloseChannel(channelNumber);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT request message.
+ *
+ * @param channelNumber the channel number
+ * @param messageID the message id
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTRequestMessage(byte channelNumber, byte messageID)
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTRequestMessage(channelNumber, messageID);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT send broadcast data.
+ *
+ * @param channelNumber the channel number
+ * @param txBuffer the tx buffer
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTSendBroadcastData(byte channelNumber, byte[] txBuffer)
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTSendBroadcastData(channelNumber, txBuffer);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT send acknowledged data.
+ *
+ * @param channelNumber the channel number
+ * @param txBuffer the tx buffer
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTSendAcknowledgedData(byte channelNumber, byte[] txBuffer)
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTSendAcknowledgedData(channelNumber, txBuffer);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * ANT send burst transfer packet.
+ *
+ * @param control the control
+ * @param txBuffer the tx buffer
+ * @return true, if successful
+ * @since 1.0
+ */
+ public boolean ANTSendBurstTransferPacket(byte control, byte[] txBuffer)
+ {
+ if(!sServiceConnected)
+ {
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ result = sAntReceiver.ANTSendBurstTransferPacket(control, txBuffer);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * Transmits the given data on channelNumber as part of a burst message.
+ *
+ * @param channelNumber Which channel to transmit on.
+ * @param txBuffer The data to send.
+ * @param initialPacket Which packet in the burst sequence does the data begin in, 1 is the first.
+ * @param containsEndOfBurst Is this the last of the data to be sent in burst.
+ * @return The number of bytes still to be sent (approximately). 0 if success.
+ */
+ public int ANTSendBurstTransfer(byte channelNumber, byte[] txBuffer)
+ {
+ int result = txBuffer.length;
+
+ if(sServiceConnected)
+ {
+ try {
+ result = sAntReceiver.ANTSendBurstTransfer(channelNumber, txBuffer);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * ANT send partial burst.
+ *
+ * @param channelNumber the channel number
+ * @param txBuffer the tx buffer
+ * @param initialPacket the initial packet
+ * @param containsEndOfBurst the contains end of burst
+ * @return the int
+ * @since 1.0
+ */
+ public int ANTSendPartialBurst(byte channelNumber, byte[] txBuffer, int initialPacket, boolean containsEndOfBurst)
+ {
+ int result = txBuffer.length;
+
+ if(sServiceConnected)
+ {
+ try {
+ result = sAntReceiver.ANTTransmitBurst(channelNumber, txBuffer, initialPacket, containsEndOfBurst);
+ } catch (RemoteException ex) {
+ antServiceConnectionLost();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the version code (eg. 1) of ANTLib used by the ANT application service
+ *
+ * @return the service library version code
+ * @throws RemoteException the remote exception
+ * @since 1.2
+ */
+ public int getServiceLibraryVersionCode() throws RemoteException
+ {
+ if(mServiceLibraryVersionCode == 0)
+ {
+ mServiceLibraryVersionCode = sAntReceiver.getServiceLibraryVersionCode();
+ }
+
+ return mServiceLibraryVersionCode;
+ }
+
+ /**
+ * Returns the version name (eg "1.0") of ANTLib used by the ANT application service
+ *
+ * @return the service library version name
+ * @throws RemoteException the remote exception
+ * @since 1.2
+ */
+ public String getServiceLibraryVersionName() throws RemoteException
+ {
+ return sAntReceiver.getServiceLibraryVersionName();
+ }
+
+
+ //
+ // ------------------- The below functions are for debugging/development and will likely disappear.
+ //
+
+ /**
+ * Turn verbose logging on or off in the service.
+ *
+ * @param debug Whether debug logging should be enabled.
+ * @return true, if successful
+ * @since 1.4
+ */
+ public boolean debugLogging(boolean debug)
+ {
+ if(DEBUG) Log.d(TAG, "debugLogging");
+
+ if(!sServiceSettingsConnected)
+ {
+ // Haven't received 'onConnected' notification yet
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ sServiceSettingsReceiver.debugLogging(debug);
+ result = true;
+ } catch (RemoteException ex) {
+ antServiceSettingsConnectionLost();
+ }
+ return result;
+ }
+
+ /**
+ * Set how many ANT packets should be combined in one request to the hardware during a burst transfer.
+ *
+ * @param numPackets Combined packet count.
+ * @return true, if successful
+ * @since 1.4
+ */
+ boolean setNumCombinedBurstPackets(int numPackets)
+ {
+ if(DEBUG) Log.d(TAG, "setNumCombinedBurstPackets");
+
+ if(!sServiceSettingsConnected)
+ {
+ // Haven't received 'onConnected' notification yet
+ return false;
+ }
+
+ boolean result = false;
+ try {
+ sServiceSettingsReceiver.setNumCombinedBurstPackets(numPackets);
+ result = true;
+ } catch (RemoteException ex) {
+ antServiceSettingsConnectionLost();
+ }
+
+ return result;
+ }
+
+ /**
+ * Get the maximum number of ANT packets which will be combined in one request to the hardware during a burst transfer.
+ *
+ * @return The number of combined packets, or -1 on failure.
+ * @since 1.4
+ */
+ int getNumCombinedBurstPackets()
+ {
+ if(DEBUG) Log.d(TAG, "getNumCombinedBurstPackets");
+
+ if(!sServiceSettingsConnected)
+ {
+ // Haven't received 'onConnected' notification yet
+ return -1;
+ }
+
+ int result = -1;
+ try {
+ result = sServiceSettingsReceiver.getNumCombinedBurstPackets();
+ } catch (RemoteException ex) {
+ antServiceSettingsConnectionLost();
+ }
+
+ return result;
+ }
+}
diff --git a/MyTracks/src/com/dsi/ant/AntInterfaceIntent.java b/MyTracks/src/com/dsi/ant/AntInterfaceIntent.java
new file mode 100644
index 000000000..1b0b7f7e7
--- /dev/null
+++ b/MyTracks/src/com/dsi/ant/AntInterfaceIntent.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2010 Dynastream Innovations 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.dsi.ant;
+
+/**
+ * Manages the ANT Interface
+ *
+ * @hide
+ */
+public interface AntInterfaceIntent {
+
+ public static final String STATUS = "com.dsi.ant.rx.intent.STATUS";
+ public static final String ANT_MESSAGE = "com.dsi.ant.intent.ANT_MESSAGE";
+
+ public static final String ANT_ENABLED_ACTION = "com.dsi.ant.intent.action.ANT_ENABLED";
+ public static final String ANT_DISABLED_ACTION = "com.dsi.ant.intent.action.ANT_DISABLED";
+ public static final String ANT_RESET_ACTION = "com.dsi.ant.intent.action.ANT_RESET";
+
+ public static final String ANT_RX_MESSAGE_ACTION = "com.dsi.ant.intent.action.ANT_RX_MESSAGE_ACTION";
+
+}
diff --git a/MyTracks/src/com/dsi/ant/AntMesg.java b/MyTracks/src/com/dsi/ant/AntMesg.java
new file mode 100644
index 000000000..cf2ae70d9
--- /dev/null
+++ b/MyTracks/src/com/dsi/ant/AntMesg.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2010 Dynastream Innovations 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.dsi.ant;
+
+/**
+ * Public API for controlling the Ant Service.
+ * AntMesg contains definitions for ANT message IDs
+ *
+ * @hide
+ */
+public class AntMesg {
+
+ /////////////////////////////////////////////////////////////////////////////
+ // HCI VS Message Format
+ // Messages are in the format:
+ //
+ // Outgoing ANT messages (host -> ANT chip)
+ // 01 D1 FD XX YY YY II JJ ------
+ // ^ ^ ^ ^
+ // | HCI framing | | ANT Mesg |
+ //
+ // where: 01 is the 1 byte HCI packet Identifier (HCI Command packet)
+ // D1 FD is the 2 byte HCI op code (0xFDD1 stored in little endian)
+ // XX is the 1 byte Length of all parameters in bytes (number of bytes in the HCI packet after this byte)
+ // YY YY is the 2 byte Parameter describing the length of the entire ANT message (II JJ ------) stored in little endian
+ // II is the 1 byte size of the ANT message (0-249)
+ // JJ is the 1 byte ID of the ANT message (1-255, 0 is invalid)
+ // ------ is the data of the ANT message (0-249 bytes of data)
+ //
+ // Incoming HCI Command Complete for ANT message command (host <- ANT chip)
+ // 04 0E 04 01 D1 FD ZZ
+ //
+ // where: 04 is the 1 byte HCI packet Identifier (HCI Event packet)
+ // 0E is the 1 byte HCI event (Command Complete)
+ // 04 is the 1 byte Length of all parameters in bytes (there are 4 bytes)
+ // 01 is the 1 byte Number of parameters in the packet (there is 1 parameter)
+ // D1 FD is the 2 byte HCI Op code of the command (0xFDD1 stored in little endian)
+ // ZZ is the 1 byte response to the command (0x00 - Command Successful
+ // 0x1F - Returned if the receive message queue of the ANT chip is full, the command should be retried
+ // Other - Any other non-zero response code indicates an error)
+ //
+ // Incoming ANT messages (host <- ANT chip)
+ // 04 FF XX 00 05 YY YY II JJ ------
+ // ^ ^ ^ ^
+ // | HCI framing | | ANT Mesg |
+ //
+ // where: 04 is the 1 byte HCI packet Identifier (HCI Event packet)
+ // FF is the 1 byte HCI event code (0xFF Vendor Specific event)
+ // XX is the 1 byte Length of all parameters in bytes (number of bytes in the HCI packet after this byte)
+ // 00 05 is the 2 byte vendor specific event code for ANT messages (0x0500 stored in little endian)
+ // YY YY is the 2 byte Parameter describing the length of the entire ANT message (II JJ ------) stored in little endian
+ // II is the 1 byte size of the ANT message (0-249)
+ // JJ is the 1 byte ID of the ANT message (1-255, 0 is invalid)
+ // ------ is the data of the ANT message (0-249 bytes of data)
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ public static final byte MESG_SYNC_SIZE =((byte)0); // Ant messages are embedded in HCI messages we do not include a sync byte
+ public static final byte MESG_SIZE_SIZE =((byte)1);
+ public static final byte MESG_ID_SIZE =((byte)1);
+ public static final byte MESG_CHANNEL_NUM_SIZE =((byte)1);
+ public static final byte MESG_EXT_MESG_BF_SIZE =((byte)1); // NOTE: this could increase in the future
+ public static final byte MESG_CHECKSUM_SIZE =((byte)0); // Ant messages are embedded in HCI messages we do not include a checksum
+ public static final byte MESG_DATA_SIZE =((byte)9);
+
+ // The largest serial message is an ANT data message with all of the extended fields
+ public static final byte MESG_ANT_MAX_PAYLOAD_SIZE =AntDefine.ANT_STANDARD_DATA_PAYLOAD_SIZE;
+
+ public static final byte MESG_MAX_EXT_DATA_SIZE =(AntDefine.ANT_EXT_MESG_DEVICE_ID_FIELD_SIZE + AntDefine.ANT_EXT_STRING_SIZE); // ANT device ID (4 bytes) + Padding for ANT EXT string size(19 bytes)
+
+ public static final byte MESG_MAX_DATA_SIZE =(MESG_ANT_MAX_PAYLOAD_SIZE + MESG_EXT_MESG_BF_SIZE + MESG_MAX_EXT_DATA_SIZE); // ANT data payload (8 bytes) + extended bitfield (1 byte) + extended data (10 bytes)
+ public static final byte MESG_MAX_SIZE_VALUE =(MESG_MAX_DATA_SIZE + MESG_CHANNEL_NUM_SIZE); // this is the maximum value that the serial message size value is allowed to be
+ public static final byte MESG_BUFFER_SIZE =(MESG_SIZE_SIZE + MESG_ID_SIZE + MESG_CHANNEL_NUM_SIZE + MESG_MAX_DATA_SIZE + MESG_CHECKSUM_SIZE);
+ public static final byte MESG_FRAMED_SIZE =(MESG_ID_SIZE + MESG_CHANNEL_NUM_SIZE + MESG_MAX_DATA_SIZE);
+ public static final byte MESG_HEADER_SIZE =(MESG_SYNC_SIZE + MESG_SIZE_SIZE + MESG_ID_SIZE);
+ public static final byte MESG_FRAME_SIZE =(MESG_HEADER_SIZE + MESG_CHECKSUM_SIZE);
+ public static final byte MESG_MAX_SIZE =(MESG_MAX_DATA_SIZE + MESG_FRAME_SIZE);
+
+ public static final byte MESG_SIZE_OFFSET =(MESG_SYNC_SIZE);
+ public static final byte MESG_ID_OFFSET =(MESG_SYNC_SIZE + MESG_SIZE_SIZE);
+ public static final byte MESG_DATA_OFFSET =(MESG_HEADER_SIZE);
+ public static final byte MESG_RECOMMENDED_BUFFER_SIZE =((byte) 64); // This is the recommended size for serial message buffers if there are no RAM restrictions on the system
+
+ //////////////////////////////////////////////
+ // Message ID's
+ //////////////////////////////////////////////
+ public static final byte MESG_INVALID_ID =((byte)0x00);
+ public static final byte MESG_EVENT_ID =((byte)0x01);
+
+ public static final byte MESG_VERSION_ID =((byte)0x3E);
+ public static final byte MESG_RESPONSE_EVENT_ID =((byte)0x40);
+
+ public static final byte MESG_UNASSIGN_CHANNEL_ID =((byte)0x41);
+ public static final byte MESG_ASSIGN_CHANNEL_ID =((byte)0x42);
+ public static final byte MESG_CHANNEL_MESG_PERIOD_ID =((byte)0x43);
+ public static final byte MESG_CHANNEL_SEARCH_TIMEOUT_ID =((byte)0x44);
+ public static final byte MESG_CHANNEL_RADIO_FREQ_ID =((byte)0x45);
+ public static final byte MESG_NETWORK_KEY_ID =((byte)0x46);
+ public static final byte MESG_RADIO_TX_POWER_ID =((byte)0x47);
+ public static final byte MESG_RADIO_CW_MODE_ID =((byte)0x48);
+
+ public static final byte MESG_SYSTEM_RESET_ID =((byte)0x4A);
+ public static final byte MESG_OPEN_CHANNEL_ID =((byte)0x4B);
+ public static final byte MESG_CLOSE_CHANNEL_ID =((byte)0x4C);
+ public static final byte MESG_REQUEST_ID =((byte)0x4D);
+
+ public static final byte MESG_BROADCAST_DATA_ID =((byte)0x4E);
+ public static final byte MESG_ACKNOWLEDGED_DATA_ID =((byte)0x4F);
+ public static final byte MESG_BURST_DATA_ID =((byte)0x50);
+
+ public static final byte MESG_CHANNEL_ID_ID =((byte)0x51);
+ public static final byte MESG_CHANNEL_STATUS_ID =((byte)0x52);
+ public static final byte MESG_RADIO_CW_INIT_ID =((byte)0x53);
+ public static final byte MESG_CAPABILITIES_ID =((byte)0x54);
+
+ public static final byte MESG_STACKLIMIT_ID =((byte)0x55);
+
+ public static final byte MESG_SCRIPT_DATA_ID =((byte)0x56);
+ public static final byte MESG_SCRIPT_CMD_ID =((byte)0x57);
+
+ public static final byte MESG_ID_LIST_ADD_ID =((byte)0x59);
+ public static final byte MESG_ID_LIST_CONFIG_ID =((byte)0x5A);
+ public static final byte MESG_OPEN_RX_SCAN_ID =((byte)0x5B);
+
+ public static final byte MESG_EXT_CHANNEL_RADIO_FREQ_ID =((byte)0x5C); // OBSOLETE: (for 905 radio)
+ public static final byte MESG_EXT_BROADCAST_DATA_ID =((byte)0x5D);
+ public static final byte MESG_EXT_ACKNOWLEDGED_DATA_ID =((byte)0x5E);
+ public static final byte MESG_EXT_BURST_DATA_ID =((byte)0x5F);
+
+ public static final byte MESG_CHANNEL_RADIO_TX_POWER_ID =((byte)0x60);
+ public static final byte MESG_GET_SERIAL_NUM_ID =((byte)0x61);
+ public static final byte MESG_GET_TEMP_CAL_ID =((byte)0x62);
+ public static final byte MESG_SET_LP_SEARCH_TIMEOUT_ID =((byte)0x63);
+ public static final byte MESG_SET_TX_SEARCH_ON_NEXT_ID =((byte)0x64);
+ public static final byte MESG_SERIAL_NUM_SET_CHANNEL_ID_ID =((byte)0x65);
+ public static final byte MESG_RX_EXT_MESGS_ENABLE_ID =((byte)0x66);
+ public static final byte MESG_RADIO_CONFIG_ALWAYS_ID =((byte)0x67);
+ public static final byte MESG_ENABLE_LED_FLASH_ID =((byte)0x68);
+
+ public static final byte MESG_XTAL_ENABLE_ID =((byte)0x6D);
+
+ public static final byte MESG_STARTUP_MESG_ID =((byte)0x6F);
+ public static final byte MESG_AUTO_FREQ_CONFIG_ID =((byte)0x70);
+ public static final byte MESG_PROX_SEARCH_CONFIG_ID =((byte)0x71);
+ public static final byte MESG_EVENT_BUFFERING_CONFIG_ID =((byte)0x74);
+
+
+ public static final byte MESG_CUBE_CMD_ID =((byte)0x80);
+
+ public static final byte MESG_GET_PIN_DIODE_CONTROL_ID =((byte)0x8D);
+ public static final byte MESG_PIN_DIODE_CONTROL_ID =((byte)0x8E);
+ public static final byte MESG_FIT1_SET_AGC_ID =((byte)0x8F);
+
+ public static final byte MESG_FIT1_SET_EQUIP_STATE_ID =((byte)0x91); // *** CONFLICT: w/ Sensrcore, Fit1 will never have sensrcore enabled
+
+ // Sensrcore Messages
+ public static final byte MESG_SET_CHANNEL_INPUT_MASK_ID =((byte)0x90);
+ public static final byte MESG_SET_CHANNEL_DATA_TYPE_ID =((byte)0x91);
+ public static final byte MESG_READ_PINS_FOR_SECT_ID =((byte)0x92);
+ public static final byte MESG_TIMER_SELECT_ID =((byte)0x93);
+ public static final byte MESG_ATOD_SETTINGS_ID =((byte)0x94);
+ public static final byte MESG_SET_SHARED_ADDRESS_ID =((byte)0x95);
+ public static final byte MESG_ATOD_EXTERNAL_ENABLE_ID =((byte)0x96);
+ public static final byte MESG_ATOD_PIN_SETUP_ID =((byte)0x97);
+ public static final byte MESG_SETUP_ALARM_ID =((byte)0x98);
+ public static final byte MESG_ALARM_VARIABLE_MODIFY_TEST_ID =((byte)0x99);
+ public static final byte MESG_PARTIAL_RESET_ID =((byte)0x9A);
+ public static final byte MESG_OVERWRITE_TEMP_CAL_ID =((byte)0x9B);
+ public static final byte MESG_SERIAL_PASSTHRU_SETTINGS_ID =((byte)0x9C);
+
+ public static final byte MESG_BIST_ID =((byte)0xAA);
+
+ public static final byte MESG_UNLOCK_INTERFACE_ID =((byte)0xAD);
+ public static final byte MESG_SERIAL_ERROR_ID =((byte)0xAE);
+ public static final byte MESG_SET_ID_STRING_ID =((byte)0xAF);
+
+ public static final byte MESG_PORT_GET_IO_STATE_ID =((byte)0xB4);
+ public static final byte MESG_PORT_SET_IO_STATE_ID =((byte)0xB5);
+
+ public static final byte MESG_SLEEP_ID =((byte)0xC5);
+ public static final byte MESG_GET_GRMN_ESN_ID =((byte)0xC6);
+ public static final byte MESG_SET_USB_INFO_ID =((byte)0xC7);
+
+ public static final byte MESG_COMMAND_COMPLETE_RESPONSE_ID =((byte)0xC8);
+
+ //////////////////////////////////////////////
+ // Command complete results
+ //////////////////////////////////////////////
+ public static final byte MESG_COMMAND_COMPLETE_SUCCESS =((byte)0x00);
+ public static final byte MESG_COMMAND_COMPLETE_RETRY =((byte)0x1F);
+
+ //////////////////////////////////////////////
+ // Message Sizes
+ //////////////////////////////////////////////
+ public static final byte MESG_INVALID_SIZE =((byte)0);
+
+ public static final byte MESG_VERSION_SIZE =((byte)13);
+ public static final byte MESG_RESPONSE_EVENT_SIZE =((byte)3);
+ public static final byte MESG_CHANNEL_STATUS_SIZE =((byte)2);
+
+ public static final byte MESG_UNASSIGN_CHANNEL_SIZE =((byte)1);
+ public static final byte MESG_ASSIGN_CHANNEL_SIZE =((byte)3);
+ public static final byte MESG_CHANNEL_ID_SIZE =((byte)5);
+ public static final byte MESG_CHANNEL_MESG_PERIOD_SIZE =((byte)3);
+ public static final byte MESG_CHANNEL_SEARCH_TIMEOUT_SIZE =((byte)2);
+ public static final byte MESG_CHANNEL_RADIO_FREQ_SIZE =((byte)2);
+ public static final byte MESG_CHANNEL_RADIO_TX_POWER_SIZE =((byte)2);
+ public static final byte MESG_NETWORK_KEY_SIZE =((byte)9);
+ public static final byte MESG_RADIO_TX_POWER_SIZE =((byte)2);
+ public static final byte MESG_RADIO_CW_MODE_SIZE =((byte)3);
+ public static final byte MESG_RADIO_CW_INIT_SIZE =((byte)1);
+
+ public static final byte MESG_SYSTEM_RESET_SIZE =((byte)1);
+ public static final byte MESG_OPEN_CHANNEL_SIZE =((byte)1);
+ public static final byte MESG_CLOSE_CHANNEL_SIZE =((byte)1);
+ public static final byte MESG_REQUEST_SIZE =((byte)2);
+
+ public static final byte MESG_CAPABILITIES_SIZE =((byte)6);
+ public static final byte MESG_STACKLIMIT_SIZE =((byte)2);
+
+ public static final byte MESG_SCRIPT_DATA_SIZE =((byte)10);
+ public static final byte MESG_SCRIPT_CMD_SIZE =((byte)3);
+
+ public static final byte MESG_ID_LIST_ADD_SIZE =((byte)6);
+ public static final byte MESG_ID_LIST_CONFIG_SIZE =((byte)3);
+ public static final byte MESG_OPEN_RX_SCAN_SIZE =((byte)1);
+ public static final byte MESG_EXT_CHANNEL_RADIO_FREQ_SIZE =((byte)3);
+
+ public static final byte MESG_RADIO_CONFIG_ALWAYS_SIZE =((byte)2);
+ public static final byte MESG_RX_EXT_MESGS_ENABLE_SIZE =((byte)2);
+ public static final byte MESG_SET_TX_SEARCH_ON_NEXT_SIZE =((byte)2);
+ public static final byte MESG_SET_LP_SEARCH_TIMEOUT_SIZE =((byte)2);
+
+ public static final byte MESG_SERIAL_NUM_SET_CHANNEL_ID_SIZE =((byte)3);
+ public static final byte MESG_ENABLE_LED_FLASH_SIZE =((byte)2);
+ public static final byte MESG_GET_SERIAL_NUM_SIZE =((byte)4);
+ public static final byte MESG_GET_TEMP_CAL_SIZE =((byte)4);
+
+ public static final byte MESG_XTAL_ENABLE_SIZE =((byte)1);
+ public static final byte MESG_STARTUP_MESG_SIZE =((byte)1);
+ public static final byte MESG_AUTO_FREQ_CONFIG_SIZE =((byte)4);
+ public static final byte MESG_PROX_SEARCH_CONFIG_SIZE =((byte)2);
+
+ public static final byte MESG_GET_PIN_DIODE_CONTROL_SIZE =((byte)1);
+ public static final byte MESG_PIN_DIODE_CONTROL_ID_SIZE =((byte)2);
+ public static final byte MESG_FIT1_SET_EQUIP_STATE_SIZE =((byte)2);
+ public static final byte MESG_FIT1_SET_AGC_SIZE =((byte)3);
+
+ public static final byte MESG_BIST_SIZE =((byte)6);
+ public static final byte MESG_UNLOCK_INTERFACE_SIZE =((byte)1);
+ public static final byte MESG_SET_SHARED_ADDRESS_SIZE =((byte)3);
+
+ public static final byte MESG_GET_GRMN_ESN_SIZE =((byte)5);
+
+ public static final byte MESG_PORT_SET_IO_STATE_SIZE =((byte)5);
+
+ public static final byte MESG_EVENT_BUFFERING_CONFIG_SIZE =((byte)6);
+
+ public static final byte MESG_SLEEP_SIZE =((byte)1);
+
+
+ public static final byte MESG_EXT_DATA_SIZE =((byte)13);
+
+ protected AntMesg()
+ { }
+}
diff --git a/MyTracks/src/com/dsi/ant/IAnt.aidl b/MyTracks/src/com/dsi/ant/IAnt.aidl
new file mode 100644
index 000000000..8ee999070
--- /dev/null
+++ b/MyTracks/src/com/dsi/ant/IAnt.aidl
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2010 Dynastream Innovations 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.dsi.ant;
+
+/**
+ * The Android Ant API is not finalized, and *will* be updated and expanded.
+ * This is the base level ANT messaging API and gives any application full
+ * control over the ANT radio HW. Caution should be exercised when using
+ * this interface.
+ *
+ * Public API for controlling the Ant Service.
+ *
+ * {@hide}
+ */
+interface IAnt {
+// Since version 1 (1.0):
+ boolean enable();
+ boolean disable();
+ boolean isEnabled();
+
+ boolean ANTTxMessage(in byte[] message);
+
+ boolean ANTResetSystem();
+ boolean ANTUnassignChannel(byte channelNumber);
+ boolean ANTAssignChannel(byte channelNumber, byte channelType, byte networkNumber);
+ boolean ANTSetChannelId(byte channelNumber, int deviceNumber, byte deviceType, byte txType);
+ boolean ANTSetChannelPeriod(byte channelNumber, int channelPeriod);
+ boolean ANTSetChannelRFFreq(byte channelNumber, byte radioFrequency);
+ boolean ANTSetChannelSearchTimeout(byte channelNumber, byte searchTimeout);
+ boolean ANTSetLowPriorityChannelSearchTimeout(byte channelNumber, byte searchTimeout);
+ boolean ANTSetProximitySearch(byte channelNumber, byte searchThreshold);
+ boolean ANTSetChannelTxPower(byte channelNumber, byte txPower);
+ boolean ANTAddChannelId(byte channelNumber, int deviceNumber, byte deviceType, byte txType, byte listIndex);
+ boolean ANTConfigList(byte channelNumber, byte listSize, byte exclude);
+
+ boolean ANTOpenChannel(byte channelNumber);
+ boolean ANTCloseChannel(byte channelNumber);
+
+ boolean ANTRequestMessage(byte channelNumber, byte messageID);
+ boolean ANTSendBroadcastData(byte channelNumber, in byte[] txBuffer);
+ boolean ANTSendAcknowledgedData(byte channelNumber, in byte[] txBuffer);
+
+ boolean ANTSendBurstTransferPacket(byte control, in byte[] txBuffer);
+
+ int ANTSendBurstTransfer(byte channelNumber, in byte[] txBuffer);
+ int ANTTransmitBurst(byte channelNumber, in byte[] txBuffer, int initialPacket, boolean containsEndOfBurst);
+
+// Since version 4 (1.3):
+ boolean ANTConfigEventBuffering(int screenOnFlushTimerInterval, int screenOnFlushBufferThreshold, int screenOffFlushTimerInterval, int screenOffFlushBufferThreshold);
+
+// Since version 2 (1.1):
+ boolean ANTDisableEventBuffering();
+
+// Since version 3 (1.2):
+ int getServiceLibraryVersionCode();
+ String getServiceLibraryVersionName();
+}
diff --git a/MyTracks/src/com/dsi/ant/IServiceSettings.aidl b/MyTracks/src/com/dsi/ant/IServiceSettings.aidl
new file mode 100644
index 000000000..3d0cf61c8
--- /dev/null
+++ b/MyTracks/src/com/dsi/ant/IServiceSettings.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2010 Dynastream Innovations 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.dsi.ant;
+
+/**
+ *
+ * API for configuring the non-ANT components of the ANT Service.
+ *
+ * {@hide}
+ */
+interface IServiceSettings {
+ void debugLogging(boolean debug);
+
+ boolean setNumCombinedBurstPackets(int numPackets);
+ int getNumCombinedBurstPackets();
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/AntPreference.java b/MyTracks/src/com/google/android/apps/mytracks/AntPreference.java
new file mode 100644
index 000000000..6d6a4b853
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/AntPreference.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.android.apps.mytracks;
+
+import com.google.android.maps.mytracks.R;
+
+import android.content.Context;
+import android.preference.Preference;
+import android.util.AttributeSet;
+
+/**
+ * A preference for an ANT device pairing.
+ * Currently this shows the ID and lets the user clear that ID for future pairing.
+ * TODO: Support pairing from this preference.
+ *
+ * @author Sandor Dornbush
+ */
+public class AntPreference extends Preference {
+
+ public AntPreference(Context context) {
+ super(context);
+ init();
+ }
+
+ public AntPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ private void init() {
+ int sensorId = getPersistedInt(0);
+ if (sensorId == 0) {
+ setSummary(R.string.settings_ant_not_paired);
+ } else {
+ setSummary(String.format(getContext().getString(R.string.settings_ant_paired), sensorId));
+ }
+
+ // Add actions to allow repairing.
+ setOnPreferenceClickListener(
+ new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ AntPreference.this.persistInt(0);
+ setSummary(R.string.settings_ant_not_paired);
+ return true;
+ }
+ });
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/CheckUnits.java b/MyTracks/src/com/google/android/apps/mytracks/CheckUnits.java
index 5947f8900..d1fc56029 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/CheckUnits.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/CheckUnits.java
@@ -16,6 +16,7 @@
package com.google.android.apps.mytracks;
+import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
@@ -82,7 +83,8 @@ class CheckUnits {
}
private static void recordCheckPerformed(SharedPreferences preferences) {
- preferences.edit().putBoolean(PREFERENCE_UNITS_CHECKED, true).commit();
+ ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
+ preferences.edit().putBoolean(PREFERENCE_UNITS_CHECKED, true));
}
private CheckUnits() {
diff --git a/MyTracks/src/com/google/android/apps/mytracks/Eula.java b/MyTracks/src/com/google/android/apps/mytracks/Eula.java
index f070e310a..4471d93fc 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/Eula.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/Eula.java
@@ -15,6 +15,7 @@
*/
package com.google.android.apps.mytracks;
+import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.apps.mytracks.util.ResourceUtils;
import com.google.android.maps.mytracks.R;
@@ -77,7 +78,8 @@ class Eula {
}
private static void accept(Activity activity, SharedPreferences preferences) {
- preferences.edit().putBoolean(PREFERENCE_EULA_ACCEPTED, true).commit();
+ ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
+ preferences.edit().putBoolean(PREFERENCE_EULA_ACCEPTED, true));
Intent startIntent = new Intent(activity, WelcomeActivity.class);
activity.startActivityForResult(startIntent, MyTracksConstants.WELCOME);
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java b/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java
index ddf9306eb..c4ed31c11 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/MyTracks.java
@@ -41,6 +41,7 @@ import com.google.android.apps.mytracks.services.StatusAnnouncerFactory;
import com.google.android.apps.mytracks.services.TrackRecordingService;
import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.apps.mytracks.util.FileUtils;
+import com.google.android.apps.mytracks.util.MyTracksUtils;
import com.google.android.maps.mytracks.R;
import android.app.Activity;
@@ -251,6 +252,11 @@ public class MyTracks extends TabActivity implements OnTouchListener,
Log.d(MyTracksConstants.TAG, "MyTracks.onCreate");
super.onCreate(savedInstanceState);
instance = this;
+ ApiFeatures apiFeatures = ApiFeatures.getInstance();
+ if (!MyTracksUtils.isRelease(this)) {
+ apiFeatures.getApiPlatformAdapter().enableStrictMode();
+ }
+
providerUtils = MyTracksProviderUtils.Factory.get(this);
menuManager = new MenuManager(this);
sharedPreferences = getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
@@ -258,7 +264,7 @@ public class MyTracks extends TabActivity implements OnTouchListener,
// The volume we want to control is the Text-To-Speech volume
int volumeStream =
- new StatusAnnouncerFactory(ApiFeatures.getInstance()).getVolumeStream();
+ new StatusAnnouncerFactory(apiFeatures).getVolumeStream();
setVolumeControlStream(volumeStream);
// We don't need a window title bar:
@@ -1058,10 +1064,10 @@ public class MyTracks extends TabActivity implements OnTouchListener,
* @param trackId the id of the track
*/
public void setSelectedTrackId(final long trackId) {
- sharedPreferences
- .edit()
- .putLong(getString(R.string.selected_track_key), trackId)
- .commit();
+ ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(
+ sharedPreferences
+ .edit()
+ .putLong(getString(R.string.selected_track_key), trackId));
}
long getSelectedTrackId() {
diff --git a/MyTracks/src/com/google/android/apps/mytracks/MyTracksDeleteAllTracks.java b/MyTracks/src/com/google/android/apps/mytracks/MyTracksDeleteAllTracks.java
index 8a5f255f1..1e939b144 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/MyTracksDeleteAllTracks.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/MyTracksDeleteAllTracks.java
@@ -16,6 +16,7 @@
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
+import com.google.android.apps.mytracks.util.ApiFeatures;
import com.google.android.maps.mytracks.R;
import android.app.AlertDialog;
@@ -63,7 +64,7 @@ public class MyTracksDeleteAllTracks extends Handler {
context.getSharedPreferences(MyTracksSettings.SETTINGS_NAME, 0);
SharedPreferences.Editor editor = prefs.edit();
editor.putLong(context.getString(R.string.selected_track_key), -1);
- editor.commit();
+ ApiFeatures.getInstance().getApiPlatformAdapter().applyPreferenceChanges(editor);
if (done != null) {
Handler h = new Handler();
h.post(done);
diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java b/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java
index 55147ebd3..f44823bce 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/services/TrackRecordingService.java
@@ -644,7 +644,6 @@ public class TrackRecordingService extends Service implements LocationListener {
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
splitManager = new SplitManager(this);
- sensorManager = SensorManagerFactory.getSensorManager(this);
prefManager = new PreferenceManager(this);
registerLocationListener();
@@ -731,7 +730,7 @@ public class TrackRecordingService extends Service implements LocationListener {
splitManager.shutdown();
splitManager = null;
if (sensorManager != null) {
- sensorManager.onDestroy();
+ sensorManager.shutdown();
sensorManager = null;
}
@@ -1080,6 +1079,7 @@ public class TrackRecordingService extends Service implements LocationListener {
showNotification();
registerLocationListener();
splitManager.restore();
+ sensorManager = SensorManagerFactory.getSensorManager(this);
if (sensorManager != null) {
sensorManager.onStartTrack();
}
@@ -1128,6 +1128,7 @@ public class TrackRecordingService extends Service implements LocationListener {
if (sensorManager != null) {
sensorManager.shutdown();
+ sensorManager = null;
}
releaseWakeLock();
diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/AntDirectSensorManager.java b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/AntDirectSensorManager.java
new file mode 100644
index 000000000..a26d0e8cd
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/AntDirectSensorManager.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2009 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 static com.google.android.apps.mytracks.MyTracksConstants.TAG;
+import com.google.android.apps.mytracks.MyTracksSettings;
+import com.google.android.apps.mytracks.content.Sensor;
+import com.google.android.maps.mytracks.R;
+
+import com.dsi.ant.AntDefine;
+import com.dsi.ant.AntMesg;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.util.Log;
+
+/**
+ * A sensor manager to connect ANT+ sensors.
+ * This can include heart rate monitors.
+ *
+ * @author Sandor Dornbush
+ */
+public class AntDirectSensorManager extends AntSensorManager {
+
+ /*
+ * These constants are defined by the ANT+ heart rate monitor spec.
+ */
+ public static final byte HRM_CHANNEL = 0;
+ public static final byte NETWORK_NUMBER = 1;
+ public static final byte HEART_RATE_DEVICE_TYPE = 120;
+ public static final byte POWER_DEVICE_TYPE = 11;
+ public static final byte MANUFACTURER_ID = 1;
+ public static final short CHANNEL_PERIOD = 8070;
+ public static final byte RF_FREQUENCY = 57;
+
+ private short deviceNumberHRM;
+
+ public AntDirectSensorManager(Context context) {
+ super(context);
+
+ deviceNumberHRM = WILDCARD;
+
+ // First read the the device id that we will be pairing with.
+ SharedPreferences prefs = context.getSharedPreferences(
+ MyTracksSettings.SETTINGS_NAME, 0);
+ if (prefs != null) {
+ deviceNumberHRM =
+ (short) prefs.getInt(context.getString(R.string.ant_heart_rate_sensor_id_key), 0);
+ }
+ Log.i(TAG, "Pairing with heart rate monitor: " + deviceNumberHRM);
+ }
+
+ @Override
+ public void handleMessage(byte[] antMessage) {
+ int channel =
+ antMessage[AntMesg.MESG_DATA_OFFSET] & AntDefine.CHANNEL_NUMBER_MASK;
+ switch (channel) {
+ case HRM_CHANNEL:
+ antDecodeHRM(antMessage);
+ break;
+ default:
+ Log.d(TAG, "Unhandled message: " + channel);
+ }
+ }
+
+ /**
+ * Decode an ant heart rate monitor message.
+ * @param antMessage The byte array received from the heart rate monitor.
+ */
+ private void antDecodeHRM(byte[] antMessage) {
+ // message ID == broadcast
+ switch (antMessage[AntMesg.MESG_ID_OFFSET]) {
+ case AntMesg.MESG_BROADCAST_DATA_ID:
+ handleBroadcastData(antMessage);
+ break;
+ case AntMesg.MESG_RESPONSE_EVENT_ID:
+ handleMessageResponse(antMessage);
+ break;
+ case AntMesg.MESG_CHANNEL_ID_ID:
+ handleChannelId(antMessage);
+ break;
+ default:
+ Log.e(TAG, "Unexpected message id: " + antMessage[3]);
+ }
+ }
+
+ private void handleBroadcastData(byte[] antMessage) {
+ if (deviceNumberHRM == WILDCARD) {
+ getAntReceiver().ANTRequestMessage(HRM_CHANNEL,
+ AntMesg.MESG_CHANNEL_ID_ID);
+ Log.d(TAG, "Requesting channel id id.");
+ }
+
+ setSensorState(Sensor.SensorState.CONNECTED);
+ int bpm = (int) antMessage[10] & 0xFF;
+ Sensor.SensorData.Builder b = Sensor.SensorData.newBuilder()
+ .setValue(bpm)
+ .setState(Sensor.SensorState.SENDING);
+ sensorData =
+ Sensor.SensorDataSet.newBuilder()
+ .setCreationTime(System.currentTimeMillis())
+ .setHeartRate(b)
+ .build();
+ }
+
+ void handleChannelId(byte[] antMessage) {
+ // Store the device id.
+ deviceNumberHRM =
+ (short) (((int) antMessage[3] & 0xFF |
+ ((int) (antMessage[4] & 0xFF) << 8)) & 0xFFFF);
+ Log.i(TAG, "Found device id: " + deviceNumberHRM);
+
+ SharedPreferences prefs = context.getSharedPreferences(
+ MyTracksSettings.SETTINGS_NAME, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putInt(context.getString(R.string.ant_heart_rate_sensor_id_key), deviceNumberHRM);
+ editor.commit();
+ }
+
+ private void handleMessageResponse(byte[] antMessage) {
+ if (antMessage[3] == AntMesg.MESG_EVENT_ID &&
+ antMessage[4] == AntDefine.EVENT_RX_SEARCH_TIMEOUT) {
+ // Search timeout
+ Log.w(TAG, "Search timed out. Unassigning channel.");
+ getAntReceiver().ANTUnassignChannel((byte) 0);
+ setSensorState(Sensor.SensorState.DISCONNECTED);
+ } else if (antMessage[3] == AntMesg.MESG_UNASSIGN_CHANNEL_ID) {
+ setSensorState(Sensor.SensorState.DISCONNECTED);
+ Log.i(TAG, "Disconnected from the sensor: " + getSensorState());
+ }
+ }
+
+ /**
+ * Open a channel to the SRM head unit.
+ */
+ @Override
+ public void setupChannel() {
+ super.setupChannel();
+ antChannelSetup(NETWORK_NUMBER,
+ HRM_CHANNEL,
+ deviceNumberHRM,
+ HEART_RATE_DEVICE_TYPE,
+ (byte) 0x01,
+ CHANNEL_PERIOD,
+ RF_FREQUENCY,
+ (byte) 0);
+ setSensorState(Sensor.SensorState.CONNECTING);
+ }
+
+ public short getDeviceNumberHRM() {
+ return deviceNumberHRM;
+ }
+
+ void setDeviceNumberHRM(short deviceNumberHRM) {
+ this.deviceNumberHRM = deviceNumberHRM;
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/AntSRMSensorManager.java b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/AntSRMSensorManager.java
new file mode 100644
index 000000000..3d038a922
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/AntSRMSensorManager.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2009 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 com.google.android.apps.mytracks.MyTracksConstants;
+import com.google.android.apps.mytracks.MyTracksSettings;
+import com.google.android.apps.mytracks.content.Sensor;
+import com.google.android.maps.mytracks.R;
+
+import com.dsi.ant.AntDefine;
+import com.dsi.ant.AntMesg;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.util.Log;
+
+/**
+ * A sensor manager that can connect to an SRM Power Control 7 head unit.
+ *
+ * @author Sandor Dornbush
+ */
+public class AntSRMSensorManager extends AntSensorManager {
+
+ /*
+ * These constants are defined by the SRM Headunit spec.
+ */
+ public static final byte NETWORK_NUMBER = (byte) 0;
+ public static final byte DEVICE_TYPE = (byte) 12;
+ public static final byte MANUFACTURER_ID = (byte) 1;
+ public static final short CHANNEL_PERIOD = (short) 8192;
+ public static final byte RF_FREQUENCY = (byte) 50;
+
+ public static final int MESSAGE_TYPE_INDEX = 3;
+ public static final int INITIALS_MESSAGE_TYPE = 5;
+ public static final int SENSOR_DATA_MESSAGE_TYPE = 6;
+
+ public static final int MESSAGE_ID_INDEX = 4;
+
+ /**
+ * This can be any value between 0..8
+ */
+ private byte channel = (byte) 5;
+
+ /**
+ * This is the id of this device.
+ * The head unit must be programmed to expect this number.
+ */
+ private byte deviceId;
+
+ /**
+ * The id of the last message received from the SRM head unit.
+ */
+ private int lastMessageId;
+
+ public AntSRMSensorManager(Context context) {
+ super(context);
+
+ // First read the the device id that we will be announcing.
+ SharedPreferences prefs = context.getSharedPreferences(
+ MyTracksSettings.SETTINGS_NAME, 0);
+ if (prefs != null) {
+ deviceId = (byte) prefs.getInt(
+ context.getString(R.string.ant_srm_bridge_sensor_id_key),
+ WILDCARD);
+ }
+ }
+
+ @Override
+ public void handleMessage(byte[] antMessage) {
+ // Parse channel number
+ byte recievedChannel = (byte) (antMessage[AntMesg.MESG_DATA_OFFSET]
+ & AntDefine.CHANNEL_NUMBER_MASK);
+ if (recievedChannel != channel) {
+ Log.d(MyTracksConstants.TAG, "Unexpected channel: " + recievedChannel);
+ return;
+ }
+ switch (antMessage[AntMesg.MESG_ID_OFFSET]) {
+ case AntMesg.MESG_BROADCAST_DATA_ID:
+ handleBroadcastData(antMessage);
+ break;
+ case AntMesg.MESG_RESPONSE_EVENT_ID:
+ handleMessageResponse(antMessage);
+ break;
+ case AntMesg.MESG_CHANNEL_ID_ID:
+ handleChannelId(antMessage);
+ break;
+ default:
+ Log.e(MyTracksConstants.TAG,
+ "Unexpected message id: " + antMessage[3]);
+ }
+ }
+
+ private void handleBroadcastData(byte[] antMessage) {
+ if (deviceId == WILDCARD) {
+ getAntReceiver().ANTRequestMessage(channel, AntMesg.MESG_CHANNEL_ID_ID);
+ Log.d(MyTracksConstants.TAG, "Requesting channel id id.");
+ }
+ setSensorState(Sensor.SensorState.CONNECTED);
+ switch(antMessage[MESSAGE_TYPE_INDEX]) {
+ case INITIALS_MESSAGE_TYPE:
+ // TODO handle initials message.
+ break;
+ case SENSOR_DATA_MESSAGE_TYPE:
+ parseSensorData(antMessage);
+ break;
+ default:
+ Log.e(MyTracksConstants.TAG,
+ "Unexpected message type: " + antMessage[MESSAGE_TYPE_INDEX]);
+ }
+ }
+
+ private void handleChannelId(byte[] antMessage) {
+ // Store the device id.
+ deviceId = antMessage[3];
+ Log.i(MyTracksConstants.TAG, "Found device id: " + deviceId);
+
+ SharedPreferences prefs = context.getSharedPreferences(
+ MyTracksSettings.SETTINGS_NAME, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putInt(context.getString(R.string.ant_srm_bridge_sensor_id_key), deviceId);
+ editor.commit();
+ }
+
+ private void handleMessageResponse(byte[] antMessage) {
+ if (antMessage[3] == AntMesg.MESG_EVENT_ID
+ && antMessage[4] == AntDefine.EVENT_RX_SEARCH_TIMEOUT) {
+ // Search timeout
+ Log.w(MyTracksConstants.TAG, "Search timed out. Unassigning channel.");
+ getAntReceiver().ANTUnassignChannel(channel);
+ setSensorState(Sensor.SensorState.DISCONNECTED);
+ } else if (antMessage[3] == AntMesg.MESG_UNASSIGN_CHANNEL_ID) {
+ setSensorState(Sensor.SensorState.DISCONNECTED);
+ Log.i(MyTracksConstants.TAG,
+ "Disconnected from the sensor: " + getSensorState());
+ }
+ }
+
+ private void parseSensorData(byte[] antMessage) {
+ if (antMessage.length != 11) {
+ Log.e(MyTracksConstants.TAG,
+ "Unexpected ant message length: " + antMessage.length);
+ return;
+ }
+
+ int newMessageId = antMessage[MESSAGE_ID_INDEX] & 0xFF;
+ if (lastMessageId == newMessageId) {
+ // Repeated message.
+ Log.i(MyTracksConstants.TAG,
+ String.format("SRM ignoring repeat: 0x%X", newMessageId));
+ return;
+ }
+ if (newMessageId < lastMessageId) {
+ if (!(newMessageId < 20 && lastMessageId > 200)) {
+ Log.i(MyTracksConstants.TAG,
+ String.format("SRM ignoring repeat: 0x%X", newMessageId));
+ return;
+ } // else assume the byte overflowed to 0.
+ }
+ lastMessageId = newMessageId;
+
+ Sensor.SensorDataSet.Builder builder = Sensor.SensorDataSet.newBuilder()
+ .setCreationTime(System.currentTimeMillis());
+
+ int power = SensorUtils.unsignedShortToInt(antMessage, 5);
+ if (power >= 0) {
+ Sensor.SensorData.Builder b = Sensor.SensorData.newBuilder()
+ .setValue(power)
+ .setState(Sensor.SensorState.SENDING);
+ builder.setPower(b);
+ }
+
+ int speed = SensorUtils.unsignedShortToInt(antMessage, 7);
+ if (speed >= 0) {
+ // The speed from srm is in 1/10 km/hr.
+ // Sensor data expects the speed as m/s.
+ // TODO finish this.
+ //sensorData.setWheelSpeed(UnitConversions.TENTH_KMH_TO_MPS * speed);
+ }
+
+ int cadence = antMessage[9] & 0xFF;
+ if (cadence >= 0) {
+ Sensor.SensorData.Builder b = Sensor.SensorData.newBuilder()
+ .setValue(cadence)
+ .setState(Sensor.SensorState.SENDING);
+ builder.setCadence(b);
+ }
+
+ int bpm = antMessage[10] & 0xFF;
+ if (bpm > 0) {
+ Sensor.SensorData.Builder b = Sensor.SensorData.newBuilder()
+ .setValue(bpm)
+ .setState(Sensor.SensorState.SENDING);
+ builder.setHeartRate(b);
+ }
+ sensorData = builder.build();
+ }
+
+ /**
+ * Open a channel to the SRM head unit.
+ */
+ @Override
+ public void setupChannel() {
+ antChannelSetup(NETWORK_NUMBER,
+ channel,
+ deviceId,
+ DEVICE_TYPE,
+ MANUFACTURER_ID,
+ CHANNEL_PERIOD,
+ RF_FREQUENCY,
+ (byte) 0);
+ lastMessageId = 0;
+ setSensorState(Sensor.SensorState.CONNECTING);
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/AntSensorManager.java b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/AntSensorManager.java
new file mode 100644
index 000000000..eb2230f10
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/AntSensorManager.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2009 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 com.google.android.apps.mytracks.MyTracksConstants;
+import com.google.android.apps.mytracks.content.Sensor.SensorDataSet;
+
+import com.dsi.ant.AntDefine;
+import com.dsi.ant.AntInterface;
+import com.dsi.ant.AntInterfaceIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+/**
+ * An abstract class for ANT+ based sensors.
+ *
+ * @author Sandor Dornbush
+ */
+public abstract class AntSensorManager extends SensorManager {
+
+ // ANT Service
+ public static final int EVENT_ANT_ENABLED = 1;
+ public static final int EVENT_ANT_DISABLED = 2;
+
+ // Pairing
+ protected static final short WILDCARD = 0;
+
+ private AntInterface antReceiver;
+
+ private boolean status;
+
+ // Flag to know if the ANT App was interrupted
+ // TODO: This code path is not used but probably should be.
+ private boolean antInterrupted;
+
+ /**
+ * The data from the sensors.
+ */
+ protected SensorDataSet sensorData;
+
+ protected Context context;
+
+ private static final boolean DEBUGGING = false;
+
+ /**
+ * Receives all of the ANT intents and dispatches to the proper handler.
+ */
+ private final BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String antAction = intent.getAction();
+
+ Log.i(MyTracksConstants.TAG, "enter onReceive" + antAction);
+ if (antAction.equals(AntInterfaceIntent.ANT_ENABLED_ACTION)) {
+ Log.i(MyTracksConstants.TAG, "enter onReceive ANT_ENABLED_ACTION "
+ + antAction);
+ handler.sendMessage(handler.obtainMessage(EVENT_ANT_ENABLED, 0));
+ }
+ if (antAction.equals(AntInterfaceIntent.ANT_DISABLED_ACTION)) {
+ Log.i(MyTracksConstants.TAG, "enter onReceive ANT_DISABLED_ACTION "
+ + antAction);
+ handler.sendMessage(handler.obtainMessage(EVENT_ANT_DISABLED, 0));
+ }
+
+ if (antAction.equals(AntInterfaceIntent.ANT_RX_MESSAGE_ACTION)) {
+ byte[] antMessage =
+ intent.getByteArrayExtra(AntInterfaceIntent.ANT_MESSAGE);
+ if (DEBUGGING) {
+ StringBuilder sb =
+ new StringBuilder("ANT_RX_MESSAGE_ACTION Rx:");
+
+ for (int i = 0; i < antMessage.length; i++)
+ sb.append(String.format("[%X]]", (antMessage[i] & 0xFF)));
+
+ Log.d(MyTracksConstants.TAG, sb.toString());
+ }
+
+ handleMessage(antMessage);
+ }
+ }
+ };
+
+ /**
+ * Handler for all the ANT related events. The events will be handled only
+ * when we are in the ANT application main menu
+ **/
+ private Handler handler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_ANT_ENABLED:
+ Log.i(MyTracksConstants.TAG,
+ "enter handleMessage ----EVENT_ANT_ENABLED");
+ break;
+ case EVENT_ANT_DISABLED:
+ Log.i(MyTracksConstants.TAG,
+ "enter handleMessage ----EVENT_ANT_DISABLED");
+ break;
+ }
+ }
+ };
+
+ public AntSensorManager(Context context) {
+ this.context = context;
+
+ // Need to enable the ANT if it is not enabled earlier
+ antReceiver = AntInterface.getInstance(context, null);
+ if (antReceiver == null) {
+ return;
+ }
+
+ status = antReceiver.isEnabled();
+ if (!status) {
+ // Make sure not to call AntInterface.enable() again, if it has been
+ // already called before
+ if (antInterrupted == false) {
+ status = antReceiver.enable();
+ if (!status) {
+ Log.e(MyTracksConstants.TAG, "Can not enable ANT interface");
+ } else {
+ Log.i(MyTracksConstants.TAG, "Powering on Radio");
+ }
+ } else {
+ Log.i(MyTracksConstants.TAG, "Radio already enabled");
+ }
+ }
+ }
+
+ @Override
+ public void setupChannel() {
+ Log.i(MyTracksConstants.TAG, "Registering for ant intents.");
+ // Register for ANT intent broadcasts.
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(AntInterfaceIntent.ANT_ENABLED_ACTION);
+ intentFilter.addAction(AntInterfaceIntent.ANT_DISABLED_ACTION);
+ intentFilter.addAction(AntInterfaceIntent.ANT_RX_MESSAGE_ACTION);
+ context.registerReceiver(receiver, intentFilter);
+ }
+
+ @Override
+ public SensorDataSet getSensorDataSet() {
+ return sensorData;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+
+ public abstract void handleMessage(byte[] antMessage);
+
+ @Override
+ public void onDestroy() {
+ Log.i(MyTracksConstants.TAG, "Unregistering for ant intents.");
+ context.unregisterReceiver(receiver);
+ }
+
+ /**
+ * Set up an ANT+ channel.
+ *
+ * @return True on success.
+ */
+ protected boolean antChannelSetup(byte networkNumber, byte channelNumber,
+ short deviceNumber, byte deviceType, byte txType, short channelPeriod,
+ byte radioFreq, byte proxSearch) {
+
+ // Assign as slave channel on selected network (0 = public, 1 = ANT+, 2 =
+ // ANTFS)
+ if (!antReceiver.ANTAssignChannel(channelNumber,
+ AntDefine.PARAMETER_RX_NOT_TX, networkNumber)) {
+ return false;
+ }
+
+ if (!antReceiver.ANTSetChannelId(channelNumber, deviceNumber, deviceType,
+ txType)) {
+ return false;
+ }
+
+ if (!antReceiver.ANTSetChannelPeriod(channelNumber, channelPeriod)) {
+ return false;
+ }
+
+ if (!antReceiver.ANTSetChannelRFFreq(channelNumber, radioFreq)) {
+ return false;
+ }
+
+ // Disable high priority search
+ if (!antReceiver.ANTSetChannelSearchTimeout(channelNumber, (byte) 0)) {
+ return false;
+ }
+
+ // Set search timeout to 30 seconds (low priority search))
+ if (!antReceiver.ANTSetLowPriorityChannelSearchTimeout(channelNumber, (byte) 12)) {
+ return false;
+ }
+
+ if (deviceNumber == WILDCARD) {
+ // Configure proximity search, if using wild card search
+ if (!antReceiver.ANTSetProximitySearch(channelNumber, proxSearch)) {
+ return false;
+ }
+ }
+
+ return !antReceiver.ANTOpenChannel(channelNumber);
+ }
+
+ public AntInterface getAntReceiver() {
+ return antReceiver;
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/SensorManagerFactory.java b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/SensorManagerFactory.java
index 01a8d8bf5..cad3e707b 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/SensorManagerFactory.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/SensorManagerFactory.java
@@ -13,7 +13,6 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-
package com.google.android.apps.mytracks.services.sensors;
import com.google.android.apps.mytracks.MyTracksConstants;
@@ -46,15 +45,19 @@ public class SensorManagerFactory {
return null;
}
- String sensor = prefs.getString(context.getString(R.string.sensor_type_key),
- null);
+ String sensor = prefs.getString(context.getString(R.string.sensor_type_key), null);
Log.i(MyTracksConstants.TAG, "Creating sensor of type: " + sensor);
if (sensor == null) {
return null;
+ } else if (sensor.equals(context.getString(R.string.ant_sensor_type))) {
+ return new AntDirectSensorManager(context);
+ } else if (sensor.equals(context.getString(R.string.srm_ant_bridge_sensor_type))) {
+ return new AntSRMSensorManager(context);
} else if (sensor.equals(context.getString(R.string.zephyr_sensor_type))) {
return new ZephyrSensorManager(context);
} else {
+ Log.w(MyTracksConstants.TAG, "Unable to find sensor type: " + sensor);
return null;
}
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ZephyrMessageParser.java b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ZephyrMessageParser.java
index 8cf8f951f..3a2fbf9e4 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ZephyrMessageParser.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/services/sensors/ZephyrMessageParser.java
@@ -35,8 +35,9 @@ public class ZephyrMessageParser implements MessageParser {
}
Log.w(MyTracksConstants.TAG, "Got zephyr data: " + sb);
// The provided units are 1/16 strides per minute.
- int cadence = SensorUtils.unsignedShortToInt(buffer, 56);
- // Heart Rate
+ // TODO: Fix the cadence calculation.
+ // int cadence = SensorUtils.unsignedShortToInt(buffer, 56);
+ // Heart Rate
Sensor.SensorData.Builder b = Sensor.SensorData.newBuilder()
.setValue(buffer[12] & 0xFF)
.setState(Sensor.SensorState.SENDING);
diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/ApiFeatures.java b/MyTracks/src/com/google/android/apps/mytracks/util/ApiFeatures.java
index 06727cd2d..7f1016856 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/util/ApiFeatures.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/util/ApiFeatures.java
@@ -62,24 +62,18 @@ public class ApiFeatures {
* Allow subclasses for mocking, but no direct instantiation.
*/
protected ApiFeatures() {
- if (getApiLevel() >= 5) {
- try {
- Class> clazz = Class.forName(
- "com.google.android.apps.mytracks.util.EclairPlatformAdapter");
- apiPlatformAdapter = (ApiPlatformAdapter) clazz.newInstance();
- } catch (Exception e) {
- Log.i(MyTracksConstants.TAG, "ApiFeatures: Unable to instantiate Eclair"
- + " platform adapter", e);
- }
- }
- if (apiPlatformAdapter == null) {
+ if (getApiLevel() >= 9) {
+ apiPlatformAdapter = new GingerbreadPlatformAdapter();
+ } else if (getApiLevel() >= 5) {
+ apiPlatformAdapter = new EclairPlatformAdapter();
+ } else {
Log.i(MyTracksConstants.TAG,
"ApiFeatures: Using default platform adapter");
// Cupcake adapter is always supported, so it's safe to do static linkage.
apiPlatformAdapter = new CupcakePlatformAdapter();
}
}
-
+
public ApiPlatformAdapter getApiPlatformAdapter() {
return apiPlatformAdapter;
}
@@ -107,7 +101,11 @@ public class ApiFeatures {
return true;
}
-
+
+ public boolean hasStrictMode() {
+ return getApiLevel() >= 9;
+ }
+
// Visible for testing.
protected int getApiLevel() {
return ANDROID_API_LEVEL;
diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/ApiPlatformAdapter.java b/MyTracks/src/com/google/android/apps/mytracks/util/ApiPlatformAdapter.java
index 1e2a5210a..c68832735 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/util/ApiPlatformAdapter.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/util/ApiPlatformAdapter.java
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks.util;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
+import android.content.SharedPreferences;
import android.os.HandlerThread;
/**
@@ -57,4 +58,15 @@ public interface ApiPlatformAdapter {
* @return true whether the handler has been stopped or not.
*/
boolean stopHandlerThread(HandlerThread handlerThread);
+
+ /**
+ * Applies all changes done to the given preferences editor.
+ * Changes may or may not be applied immediately.
+ */
+ void applyPreferenceChanges(SharedPreferences.Editor editor);
+
+ /**
+ * Enables strict mode where supported, only if this is a development build.
+ */
+ void enableStrictMode();
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/CupcakePlatformAdapter.java b/MyTracks/src/com/google/android/apps/mytracks/util/CupcakePlatformAdapter.java
index 272b47218..354f0a307 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/util/CupcakePlatformAdapter.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/util/CupcakePlatformAdapter.java
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks.util;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
+import android.content.SharedPreferences.Editor;
import android.os.HandlerThread;
/**
@@ -50,4 +51,14 @@ public class CupcakePlatformAdapter implements ApiPlatformAdapter {
// Do nothing, as Cupcake doesn't provide quit().
return false;
}
+
+ @Override
+ public void applyPreferenceChanges(Editor editor) {
+ editor.commit();
+ }
+
+ @Override
+ public void enableStrictMode() {
+ // Not supported
+ }
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/EclairPlatformAdapter.java b/MyTracks/src/com/google/android/apps/mytracks/util/EclairPlatformAdapter.java
index 9c32946d3..91c1ea1d3 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/util/EclairPlatformAdapter.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/util/EclairPlatformAdapter.java
@@ -18,6 +18,7 @@ package com.google.android.apps.mytracks.util;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
+import android.content.SharedPreferences.Editor;
import android.os.HandlerThread;
/**
@@ -45,4 +46,14 @@ public class EclairPlatformAdapter implements ApiPlatformAdapter {
public boolean stopHandlerThread(HandlerThread handlerThread) {
return handlerThread.quit();
}
+
+ @Override
+ public void applyPreferenceChanges(Editor editor) {
+ editor.commit();
+ }
+
+ @Override
+ public void enableStrictMode() {
+ // Not supported
+ }
}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/GingerbreadPlatformAdapter.java b/MyTracks/src/com/google/android/apps/mytracks/util/GingerbreadPlatformAdapter.java
new file mode 100644
index 000000000..caa73a170
--- /dev/null
+++ b/MyTracks/src/com/google/android/apps/mytracks/util/GingerbreadPlatformAdapter.java
@@ -0,0 +1,36 @@
+package com.google.android.apps.mytracks.util;
+
+import com.google.android.apps.mytracks.MyTracksConstants;
+
+import android.content.SharedPreferences.Editor;
+import android.os.StrictMode;
+import android.util.Log;
+
+/**
+ * The Gingerbread (API level 9) specific implememntation of the
+ * {@link ApiPlatformAdapter}.
+ *
+ * @author Rodrigo Damazio
+ */
+public class GingerbreadPlatformAdapter extends EclairPlatformAdapter {
+ @Override
+ public void applyPreferenceChanges(Editor editor) {
+ // Apply asynchronously
+ editor.apply();
+ }
+
+ @Override
+ public void enableStrictMode() {
+ Log.d(MyTracksConstants.TAG, "Enabling strict mode");
+ StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
+ .detectDiskWrites()
+ .detectNetwork()
+ .penaltyLog()
+ .build());
+ StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
+ .detectAll()
+ .penaltyLog()
+ .penaltyDeath()
+ .build());
+ }
+}
diff --git a/MyTracks/src/com/google/android/apps/mytracks/util/MyTracksUtils.java b/MyTracks/src/com/google/android/apps/mytracks/util/MyTracksUtils.java
index 71caa003c..52f5dee72 100644
--- a/MyTracks/src/com/google/android/apps/mytracks/util/MyTracksUtils.java
+++ b/MyTracks/src/com/google/android/apps/mytracks/util/MyTracksUtils.java
@@ -21,7 +21,12 @@ import com.google.android.apps.mytracks.stats.TripStatistics;
import com.google.android.maps.GeoPoint;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.Signature;
import android.location.Location;
+import android.os.StrictMode;
import android.util.Log;
import java.util.ArrayList;
@@ -34,6 +39,7 @@ import java.util.Stack;
* @author Leif Hendrik Wilden
*/
public class MyTracksUtils {
+ private static final int RELEASE_SIGNATURE_HASHCODE = -1855564782;
/**
* Computes the distance on the two sphere between the point c0 and the line
@@ -246,6 +252,25 @@ public class MyTracksUtils {
(int) (location.getLongitude() * 1E6));
}
+ /**
+ * Returns whether or not this is a release build.
+ */
+ public static boolean isRelease(Context context) {
+ try {
+ Signature [] sigs = context.getPackageManager().getPackageInfo(
+ context.getPackageName(), PackageManager.GET_SIGNATURES).signatures;
+ for (Signature sig : sigs) {
+ if (sig.hashCode() == RELEASE_SIGNATURE_HASHCODE) {
+ return true;
+ }
+ }
+ } catch (NameNotFoundException e) {
+ Log.e(MyTracksConstants.TAG, "Unable to get signatures", e);
+ }
+
+ return false;
+ }
+
/**
* This is a utility class w/ only static memebers.
*/
diff --git a/MyTracksLib/default.properties b/MyTracksLib/default.properties
index 948be06ed..1694c805b 100644
--- a/MyTracksLib/default.properties
+++ b/MyTracksLib/default.properties
@@ -8,5 +8,5 @@
# project structure.
# Project target.
-target=android-8
+target=android-9
android.library=true
diff --git a/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImpl.java b/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImpl.java
index 5d134effb..4e90d7227 100644
--- a/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImpl.java
+++ b/MyTracksLib/src/com/google/android/apps/mytracks/content/MyTracksProviderUtilsImpl.java
@@ -861,18 +861,22 @@ public class MyTracksProviderUtilsImpl implements MyTracksProviderUtils {
String select = TracksColumns._ID + "=" + id;
return findTrackBy(select);
}
-
+
@Override
public List