Buddy-Tracker (Technik)

Ein paar Anmerkungen zur Umsetzung der Funktionalitäten im Buddy-Tracker wie ich sie im Gespräch von Entwickler zu Entwickler machen würde.

Target API ist im Moment die 25 (Nougat 7.1) und die Minimum API ist 9. Anfänglich habe ich bis Level 8 unterstützt (da ich noch so ein uraltes Testgerät habe), aber die Gerätebasis ist jetzt zu klein geworden und die nötigen Klimmzüge für API-Levels unter 9 werden zu groß. Unterhalb von API 9 wird auch die Unterstützung seitens Google recht spärlich.

Nach einer umfangreichen Überarbeitung des Codes habe ich den Buddy-Tracker nun mit einer 1.x-Version geadelt. ;-) Hier hat fast der komplette Code eine Frischzellenkur bekommen. Dabei habe ich evaluiert wie sich die Location-Services der Google Play Services verhalten. Da die internen Aufrufe dieser Library hochgradig asynchron sind ist das auch ein gutes Feld um Erfahrungen mit reaktiver Programmierung zu sammeln. Ich habe also mit RxJava einen reaktiven Wrapper um diese Library geschrieben. Funktioniert so weit ganz gut, aber leider mußte ich das Ganze wieder deaktivieren, denn die Qualität der gelieferten Positionsdaten ist grottenschlecht. Man kann auch nicht nur GPS als Quelle der Positionsdaten auswählen, sondern muß immer auch den Netzwerk-Provider mitnutzen. Einige sehen das ja kritisch, weil dabei auch immer die eigenen Bewegungsdaten an Google gesendet werden. Aber dessenungeachtet ist die KI, die Google da verwendet offenbar noch verbesserungsfähig, denn auch wenn man Positionen mit hoher Genauigkeit anfordert, liefern die Location Services teilweise Positionen mit einer Genauigkeit von 1000m zurück - und das auch weit ab vom jeweiligen Track.
Da ich das Ganze - Dependency-Injection sei Dank - konfigurierbar machen konnte, konnte ich jeweils den Gegencheck machen und dieselbe Strecke statt mit den Google Services mit den Android-Location Services abgehen. Hier sind die Positionsdaten erheblich besser und die Genauigkeit war (auf derselben Strecke!) immer besser als 20m - was man bei GPS unter freiem Himmel ja auch erwarten kann.

Inzwischen hatte es Google gefallen, die Aufrufbedingungen für die SyncAdapter zu ändern. Damit hatte ich die Synchronisation der eMails realisiert. Nun war die minimale Synchronisationsperiode von 10 Minuten auf eine Stunde hoch gesetzt worden. Viel zu hoch für meine Bedürfnisse. Also mußte eine andere Lösung gefunden werden. Ich hab dann den Firebase-JobScheduler eingesetzt der zwar noch Beta ist, aber den GCM-Networkmanager ablösen soll. Da im Moment alles funktioniert ...

Beim Refactoring hat es sich angeboten, die bestehenden Unit- und Instrumentation-Tests zu erweitern. Gibt einem einfach viel mehr Sicherheit wenn man am Code rum schraubt. Der Buddy-Tracker ist inzwischen so komplex geworden, daß man nicht mehr immer alles gleichzeitig im Blick haben kann. Ist schon spannend, beobachten zu können wie sich der eigene Blickwinkel auf den Code über die Zeit langsam verändert hat.

Mir gefiel die ganze Zeit eigentlich noch nicht, wie die Daten geteilt werden konnten. Wegen den flexiblen Übertragungsmöglichkeiten konnte ich keinen Standard-Share Prozess nehmen, sondern mußte etwas eigenes bauen. Das hatte aber zur Folge, daß die ganzen Kontakte immer erst einmal im Buddy-Tracker eingetragen werden mussten. Schnell mal was an einen bestehenden Kontakt senden war so nicht möglich.
ich habe dann den ShareActionProvider eingesetzt um die Information auch über andere bereits auf dem Smartphone installierte Apps teilen zu können. Aber die Art und Weise wie man den Share-Intent kontinuierlich aktuell halten mußte ohne daß sichergestellt war, daß die Share-Option überhaupt genutzt wurde, schmeckte mir nicht.
Die Lösung ist DirectShare. Hier kann der Benutzer direkt mit häufig genutzten Kontakten teilen oder andere externe Apps nutzen. Eine dieser Apps ist dabei dann auch wieder der Buddy-Tracker, der dann den alten Dialog zur Gruppenauswahl der Buddies bereit stellt. Man hat jetzt also das Beste aus beiden Welten.
Auf Geräten die noch nicht Lollipop haben funktioniert das auch, nur fällt die Option weg, direkt an Kontakte zu senden. Hier muß man die Auswahl dann jeweils in der gewählten App treffen.

Und es gibt noch etwas Eye-Candy: Für Buddies und Orte können Bilder angegeben werden, die dann bei den Markern auf der Karte verwendet werden. Natürlich wollte ich dabei die Default-Icons als Vector-Drawables haben - hat ein bißchen gedauert, bis ich das gelöst hatte. Hier ist der Lint-Checker für den Code nicht ganz vollständig gewesen. Der Code war frei von entsprechenden Warnungen, ist aber auf alten Geräten gecrasht weil entsprechende Systemfunktionen fehlten ...

 

Apropos Bilder:

Auf den Geräten sind ja meist viele Fotos gespeichert und die Geräte erlauben in zu den Bildern auch die Ortsinformationen zu speichern. Da liegt es nahe, diese Informationen auch zu nutzen und die Bilder dann in der Karte anzuzeigen. Daraus ist das Modul Buddy-Tracker Pictures entstanden.

Dabei entsteht schnell das Problem, daß zu viele Einträge auf die Karte gezeichnet werden müssen. Passenderweise bietet Google für seine Kartenansicht ein Clustering-Modul an, daß diese Einträge zu Gruppen zusammenfassen kann um so mehr Übersicht auf der Karte zu haben. Funktioniert recht performant.

Allerdings hab ich im Moment noch das Problem, daß das Zooming dann noch nicht reibungsfrei funktioniert --> Daher noch in der Beta-Phase.

 

Mit der Version 0.5. hatte ich das User-Interface gewechselt. Anfangs habe ich das Tab-Layout verwendet. Es machte für mich Sinn, da es nur eine übersichtliche Anzahl von Menüoptionen ab. So konnte man schnell und bequem zwischen den Programmteilen wechseln.
Mit der Zeit kamen weitere Fenster hinzu, die nicht prominent genug für einen eigenen Tab waren. Also hatte ich sie im Kontext-Menü geparkt. Zusammen mit den jeweiligen Einträgen für den Kontext des gerade aktiven Tabs wurde das jetzt aber zu unübersichtlich. Mit dem Drawer-Layout sind die verschiedenen Arten von Menüeinträgen jetzt wieder sauber getrennt. Außerdem hab ich etwas Arbeit in das Layout investiert. Ein paar Paddings, etwas Farbe ... macht schon einiges aus ;-)

Das Tracking kann über den Activity-Recognition-Service von Google gesteuert werden. So kann Energie gespart werden, wenn das Gerät ruht.

Die App kann über diverse Broadcast-Intents ferngesteuert werden. So kann ein individuelles Verhalten mit Apps wie Tasker, Llama oder Automate hinzu gefügt werden (Tracking nur wenn nicht mit bestimmten WLANs verbunden, nur zu bestimmten Zeiten, ...) So könnte man vielleicht so etwas wie einen automatischen Tätigkeitsnachweis oder ein Fahrtenbuch realisieren.

Zu vielen Themen gibt es eine kontextsensitive Hilfe, die eine HTML-Datei aus der App anzeigt. Für die Hilfe ist also keine Internet-Verbindung nötig.

Zu Debugging-Zwecken können die gerade erkannten Aktivitäten auch per Sprachausgabe ausgegeben werden, so daß man nicht dauernd auf das Gerät starren muß um zu wissen ob er gerade trackt oder nicht.