Version Anpassungen
1.0 (2025-10-09) Initiale Version

Motivation

Bei App-Inventor-Projekten liefern die Sensoren keine Werte, wenn sich die App nicht mehr im Vordergrund befindet. Diese Extension stellt die Werkzeuge bereit, um Sensordaten auch dann auswerten zu können, wenn sich die App im Hintergrund befindet oder der Bildschirm ausgeschaltet wird.

Die meisten Sensordaten werden in hoher Frequenz angeliefert und sind mehr oder weniger verrauscht.


In­halts­ver­zeich­nis

Download

UrsAI2SensorUtil

Verwendung Komponente UrsAI2SensorUtil

Funktionsweise

ForegroundService, WakeLock, BatteryOptimization

WiFiLock

Berechtigung für Benachrichtigungen

Benachrichtigungskanal

Benachrichtigung

Gestaltung

Verhalten

Sensoraktivierung

Ereignisse zum Aktivitätszyklus

Referenz UrsAI2SensorUtil

Eigenschaften

Funktionen

Ereignisse

Verwendung Komponente UrsSensorAverager

Referenz UrsSensorAverager

Eigenschaften

Verwendung Komponente UrsAverager

Referenz

Eigenschaften

Funktionen

Beispielprojekt

Bereiche

Implementierung

Werkzeuge

Hinweis: Die Extension ist wegen des notwendigen ForegroundService ggf. nicht für eine Mehrfachinstanziierung geeignet. Deshalb sollte man nur eine Instanz der Extension in der gesamten App verwenden.

Download

Das ZIP-Archiv UrsAI2SensorUtil zum Download. Das Archiv enthält den Quellcode, das kompilierte Binary zum Upload in den App Inventor und eine Beispiel-Anwendung.

UrsAI2SensorUtil

Die Extension enthält drei Komponenten:

Icon ursAI2SensorUtil Die Komponente UrsAI2SensorUtil enthält Methoden, die es ermöglichen, Sensordaten auch dann auswerten zu können, wenn sich die App im Hintergrund befindet oder sogar, wenn der Bildschirm ausgeschaltet ist (Standby-Modus, Doze-Mode).

Icon UrsSensorAverager Die Komponente UrsSensorAverager liefert Mittelwerte von Daten der Sensorkomponenten, um verrausche Daten zu glätten.

Icon UrsAverager Die Komponente UrsAverager liefert Mittelwerte von allgemeinen Daten, um verrausche Daten zu glätten.

Verwendung Komponente UrsAI2SensorUtil

Funktionsweise

Damit Sensordaten auch dann zur Verfügung stehen, wenn sich die App im Hintergrund befindet oder der Bildschirm ausgeschaltet ist, muss zunächst verhindert werden, dass das Gerät in den Doze-Mode wechselt, bei dem die CPU abgeschaltet wird. Bei älteren Android-Versionen reichte es, einen WakeLock anzufordern. In späteren Versionen reichte das nicht aus. Es musste zusätzlich ein ForegroundService angelegt werden. Dieser ForegroundService ist zwangsläufig mit einer Benachrichtigung (Notification) verbunden, die dem Anwender anzeigen soll, dass der Stromsparmodus ausgesetzt ist. In noch späteren Android-Versionen kann der Anwender diese Benachrichtigung löschen, ohne das der ForegroundService gestoppt wird. Er kann auch verbieten, dass die App Benachrichtigungen anzeigt. In den neuesten Android-Versionen sind Benachrichtigungen nach der Installation der App standardmäßig abgeschaltet. Das Ganze wird noch unübersichtlicher, weil die konkrete Implementierung dieser Mechanismen von Gerätehersteller zu Gerätehersteller unterschiedlich erfolgt.

Aus Gründen der Anwenderfreundlichkeit sollte man sicher stellen, dass der Anwender weiß, warum eine Benachrichtigung in Zusammenhang mit einen WakeLock und einem ForegroundService durchaus sinnvoll ist und ihm die Möglichkeit geben, Benachrichtigungen zu erlauben.

In den neuesten Android-Versionen ist dies nicht mehr ausreichend. Die App braucht die zusätzliche Erlaubnis, im Hintergrund aktiv zu bleiben. Man muss also den Anwender auffordern eine entsprechende Berechtigung zu erteilen. Er kann die Berechtigung später auch wieder entziehen.

In der ein oder anderen Anwendung sollen die lfd. Sensordaten versendet werden. Damit Android die WiFi-Funktionen im Hintergrund-Modus nicht abschaltet, muss ein WiFiLock angefordert werden.

Damit wäre für Android alles bereit, um weiterhin Sensordaten zu erhalten. Leider macht da App-Inventor einen Strich durch die Rechnung. Die Sensor-Komponenten sind so programmiert, dass sie sich automatisch abschalten, wenn die App aus dem Vordergrund verdrängt wird :-(

Die Android-Ereignisse onPause und onResume (siehe Aktivitätslebenszyklus) werden ausgenutzt, um die Sensoren ab- und anzuschalten:

@Override public void onPause() {
  
if (enabled) {
      stopListening();
   }
}
@
Override public void onDelete() {
   if (enabled) {
      stopListening();
   }
}

ForegroundService, WakeLock, BatteryOptimization

Um Sensordaten zu erhalten, wenn die App im Hintergrund ausgeführt wird oder wenn der Bildschirm ausgeschaltet wird, ist es notwendig einen WakeLock anzufordern, in Kombination mit der Einrichtung eines ForegroundService.

Der App-Inventor-Companion besitzt leider nicht die Berechtigungen, einen WakeLock anzufordern oder einen ForegroundService einzurichten. Dazu muss die App kompiliert werden. Das ist sehr umständlich, wenn man i.W. die Sensorfunktionen testen will. Der ForegroundService wird deshalb nur auf Anforderung durch die Funktion StartForegroundService angelegt. Mit dem ForegroundService wird auch gleichzeitig ein PARTIAL_WAKE_LOCK angefordert. Der ForegroundService kann über die Funktion StopForegroundService wieder gestoppt werden.

Ob zusätzlich ein WiFiLock angefordert werden soll, kann über die Eigenschaft AquireWiFiLock eingestellt werden.

Wenn der ForegroundService gestartet wurde, wird dies über das Ereignis AfterServiceStarted angezeigt.

Bei neueren Geräten reicht es nicht aus, einen ForegroundService in Kombination mit einem WakeLock anzulegen. Es muss zusätzlich vom Anwender die Berechtigung zur Ausführung im Hintergrund erteilt werden. Über die Eigenschaft IsIgnoringBatteryOptimizations kann abgefragt werden, ob diese Berechtigung bereits erteilt wurde. Sie liefert true, wenn die Ausführung im Hintergrund möglich ist.

Der Anwender kann über die Methode RequestIgnoreBatteryOptimizations aufgefordert werden, die Berechtigung zur Hintergrundaktivität zu erteilen. Das Ergebnis der Aufforderung wird im Ereignis OnBackgroundPermissionResponse zurück geliefert. Der Companion besitzt nicht die Berechtigung die Zulassung der Hintergrundaktivität zu erfragen. Dies funktioniert nur in der kompilierten App.

Ob die App im Companion läuft, also kein ForegroundService, kein WakeLock und keine Abfrage  zur Hintergrundaktivität möglich ist, kann über die Eigenschaft IsRunningInCompanion abgefragt werden.

WiFiLock

Sollen Daten über das Netz versendet werden, ist es ggf. notwendig einen WiFiLock anzufordern, damit sichergestellt wird, dass der WiFi-Komponente nicht abgeschaltet wird. Wenn die Eigenschaft AquireWifiLock beim Start des ForegroundService gesetzt, wird zusätzlich ein WiFiLock angefordert.

Berechtigung für Benachrichtigungen

Hinweis: Im Zuge der Android-Weiterentwicklung hat sich die Implementierung von Benachrichtigungen mehrfach erheblich geändert. Außerdem gibt es Abhängigkeiten vom Gerätemodell.

Der ForegroundService muss zwingend (und auch sinnvollerweise) mit einer Benachrichtigung (Notification) versehen sein. Diese wird bei der Einrichtung des ForegroundService angelegt.

In neueren Android-Versionen (ab Android 14?) sind Benachrichtigungen nicht automatisch aktiviert, bzw. können vom Benutzer deaktiviert werden. Dies gilt auch für die Benachrichtigungen, die an einen ForegroundService gebunden sind. Der ForegroundService zur Sensordatenermittlung ist i.d.R. mit einem WakeLock verbunden, der verhindert, dass die CPU ausgeschaltet wird. Somit werden auch dann Sensordaten geliefert, wenn der Bildschirm des Smartphones ausgeschaltet wird. Das ist m.E. ein unglückliche Entwicklung, da fortlaufend der Akku belastet wird, ohne dass der Anwender davon etwas erfährt.

Ob der Anwender die Berechtigung zur Anzeige von Benachrichtigung für die App erteilt hat, kann über die Eigenschaft HasPostPermission abgefragt werden. Diese fragt aber nur die generelle Berechtigung ab, ob die App Benachrichtigungen anzeigen darf. Der Anwender kann immer noch die Berechtigung für einen speziellen Kanal entziehen. Hier habe ich leider nicht herausgefunden, wie man das Anfragen kann.

Die Extension kann die Berechtigung, Benachrichtigungen zu senden, über die Funktion RequestNotificationPermission anfordern. Das Ergebnis wird über das Ereignis OnPermissionResponse zurück geliefert. In der Anleitung zu der App sollte unbedingt auf den Grund der Abfrage hingewiesen werden. Das Beispielprojekt zeigt, wie so etwas funktionieren könnte.

Kanalspezifische Berechtigungsvergabe

Kanalspezifische Berechtigungsvergabe für die Beispiel-App bei einem Motorola g15, deutsche Version. Obwohl die allgemeine Berechtigung zur Anzeige von Benachrichtigungen erteilt wurde, die Berechtigung für den Kanal mit dem Namen URS Sensor Test verweigert worden. In der Test-App wird dieser Kanal für die Benachrichtigung des ForegroundService benutzt.

Ab Android 15 (?) kann der Anwender auch dann Benachrichtigungen löschen, wenn sie mit einem ForegroundService verbunden sind. Dies hat keinen Einfluss auf die Funktion der Services. Die App läuft auch im Hintergrund weiter. Wenn die Eigenschaft NotificationDeletable auf false gesetzt ist, generiert die Extension eine neue Benachrichtigung, wenn sie gelöscht wurde.

Benachrichtigungskanal

Eine Benachrichtigung muss einem Benachrichtigungskanal (NotificationChannel) zugeordnet werden. Dieser wird bereits bei der ersten Instanziierung der Extension angelegt, d.h. beim ersten Start der kompilierten App mit dieser Extension. Beim Betrieb im Companion werden kein Benachrichtigungskanal und demzufolge auch keine Benachrichtigung angelegt.

Jeder Benachrichtigungskanal besitzt eine eindeutige Kennung, die zur Android-internen Identifizierung des Kanals dient. Diese Kennung (Eigenschaft ChannelID) wird durch die Extension festgelegt und kann nicht nachträglich geändert werden.

Ebenfalls wird die Bedeutsamkeit der Kanals (Eigenschaft ChannelImportance) bei der ersten Instanziierung der Extension festgelegt und kann nicht nachträglich geändert werden.

Die Bezeichnung des Kanals (Eigenschaft ChannelName) und die Kanalbeschreibung (Eigenschaft ChannelDescription) können nachträglich geändert werden.

Der Benachrichtigungston wird explizit abgeschaltet.

Ob die App im Companion läuft, also keine Benachrichtigung vorgesehen ist, kann über die Eigenschaft IsRunningInCompanion abgefragt werden.

Benachrichtigung

Die Benachrichtigung (Notification) wird angezeigt, wenn der ForegroundService gestartet wird und wieder gelöscht, wenn der Service gestoppt wird. Ob im konkreten Fall eine Benachrichtigung angezeigt wird, hängt davon ab, ob die App die dazu notwendigen Berechtigungen besitzt (siehe auch Abschnitt Berechtigung für Benachrichtigungen).

Jede Benachrichtigung besitzt eine eindeutige ID-Nummer. Diese wird von der Extension festgelegt und kann über die Eigenschaft NotificationID abgefragt werden.

Gestaltung

Benachrichtigungselemente

Die Gestaltung der Benachrichtigung geschieht über die Eigenschaften NotificationTitle, NotificationText, NotificationIcon bzw. NotificationIconAsset, NotificationLargeIcon. Hinzu kommen evtl. bis zu drei Aktionsschaltflächen, die über die Eigenschaften Action1Title, Action2Title und  Action3Title definiert werden. Es werden nur die Schaltflächen angezeigt, zu denen ein Wert angegeben wurde.

Das Icon für die Benachrichtigung wird über die Eigenschaft NotificationIconAsset festgelegt. Dieses Icon wird auch in der Statusleiste angezeigt. Es sollte zweifarbig sein (Hintergrund transparent und Grafik in weiß) in der Größe 96x96 Pixel, z.B.:

Notification Icon

Falls kein eigenes Icon entworfen werden soll, kann über die Eigenschaft NotificationIcon eines der System-Icons angezeigt werden. NotificationIconAsset hat Vorrang vor NotificationIcon.

Verhalten

Mit NotificationDeletable kann man steuern, ob der Anwender die Benachrichtigung löschen darf. Das Verhalten der Benachrichtigungen hat sich im Laufe der verschiedenen Android-Versionen deutlich verändert. Außerdem besteht eine Abhängigkeit von der konkreten Implementierung von Android durch die Hersteller (siehe auch Abschnitt Berechtigung für Benachrichtigungen). Je nach Android-Version ist das Löschen einer Benachrichtigung, die mit einem ForegroundService verbunden ist, nicht möglich, kann über NotificationDeletable verboten werden oder bewirkt, dass die Benachrichtigung nach dem Löschen neu erzeugt wird. Voraussetzung ist, dass der Anwender in den neueren Android-Versionen die Berechtigung zum Senden von Benachrichtigungen erteilt hat. In den neueren Versionen wird je nach Stellung von NotificationDeletable die Benachrichtigung neu erzeugt oder das Ereignis OnDeleteNotification ausgelöst.

Mit der Eigenschaft ScreenToOpen wird festgelegt, was beim Antippen der Benachrichtigung geschehen soll. Wenn der Wert leer bleibt, passiert nichts, wenn die Benachrichtigung angetippt wird. Ansonsten wird der angegebene Screen geöffnet. Wenn der Screen neu geöffnet wird, kann über die Eigenschaft StartValue ein Startwert mitgegeben wird, der über die Methode Control.get start value abgefragt werden kann.

Jede Benachrichtigung kann mit bis zu drei Aktionsschaltflächen versehen werden. Diese werden durch die Eigenschaften Action1Title, Action2Title und  Action3Title angefordert und definiert. Wird eine dieser Schaltflächen angetippt, wird das Ereignis OnActionClick ausgelöst. Die dabei übergebene Aktionsnummer bezieht sich auf die Nummer in Action?Title.

Sensoraktivierung

Wie oben beschrieben schalten die Sensorkomponenten den Empfang von Sensorereignissen ab, wenn die App in den Hintergrund verdrängt wird. Die Komponenten registrieren sich während der Initialisierung beim übergeordneten Screen (Klasse Form) für den Empfang der Aktivitätszyklusereignisse onPause und onResume. Diese Ereignisse werden dann in der Sensorkomponente dazu verwandt, den Empfang von Sensorereignissen an- und abzuschalten.

Die Form-Klasse führt eine Liste aller für die Aktivitätszyklusereignisse registrierten Komponenten. Empfängt sie eines der genannten Ereignisse leitet sie diese an alle Elemente der Liste weiter. Die Methode RemoveListeners entfernt die angegebene Sensorkomponente wieder aus der Liste. Damit werden die relevanten Ereignisse nicht mehr weiter geleitet und der Empfang der Sensorereignisse bleibt aktiviert.

Ereignisse zum Aktivitätszyklus

Unter Umständen ist es wichtig zu wissen, in welchem (Lebenszyklus-) Zustand sich die App befindet. Deshalb sind einige Ereignisse herausgeführt, die Änderungen des Zustands anzeigen. Diese sind:

Referenz UrsAI2SensorUtil

Eigenschaften

Action1Title
The title for action button #1.
Action2Title
The title for action button #2.
Action3Title
The title for action button #3.
AquireWiFiLock
Specifies wether a WiFilock should be aquired when starting the foregroundservice.
AreNotificationsEnabled
Returns whether notifications are enabled for this app.
ChannelDescription
The user visible
ChannelID
The internal id of this channel.
ChannelImportance
The level of interruption of this notification channel.
ChannelName
The the user visible name of this channel.
IsIgnoringBatteryOptimizations
Returns wether the app is running in the companion.
IsRunningInCompanion
Returns wether the app is running in the companion.
NotificationDeletable
The notification can be dismissed by the user.
NotificationIcon
The resource name of a drawable to use as the icon in the status bar.
NotificationIconAsset
The small icon representing this notification in the status bar and content view.
NotificationID
Gets the ID of the notification.
NotificationLargeIcon
The large icon for the notification.
NotificationText
Specifies the text of the notification.
NotificationTitle
Specifies the title of the notification.
ScreenToOpen
The Screen that will be opened when the notifaction is clicked.
StartValue
The start value for a new opened screen.
Version
Returns the component's version name.
VersionSDK
Returns the running Android SDK version.

Funktionen

RemoveListeners (Sensor)
Removes onPause and onResume listeners.
RequestIgnoreBatteryOptimizations ()
Ask the user to allow the app to ignore battery optimizations.
RequestNotificationPermission ()
Requests the permission to post notifications.
StartForegroundService ()
Starts the foregroundservice
StopForegroundService ()
Stops the foregroundservice

Ereignisse

AfterServiceStarted ()
Indicates that the foreground service was started.
OnActionClick (ActionNo)
The notification or an action button was clicked by the user.
OnBackgroundPermissionResponse (Granted)
Returns the result of RequestIgnoreBatteryOptimizations.
OnDeleteNotification ()
Indicates the change of sensor data.
c (Granted)
Returns the result of RequestNotificationPermission.
OnPause ()
The app is paused.
OnResume ()
The app is resumed.
OnStop ()
Triggered when app is stopped.

Verwendung Komponente UrsSensorAverager

Sensordaten werden mit einer hohen Frequenz (i.d.R. 50 Hz) angeliefert und sind häufig verrauscht. Die Komponente UrsSensorAverager mittelt die Werte die von Android gelieferten Werte.

Im Designer wird mit der Eigenschaft Source festgelegt, von welchem Sensor die Daten gemittelt werden sollen. Die Eigenschaft DataSourceKey legt fest, welcher der Werte gemittelt werden soll. Die Eigenschaft CacheSize gibt an, über wie viele Werte gemittelt werden soll. Übersteigt die Anzahl der gespeicherten Werte den Wert von CacheSize wird der älteste Wert verworfen.

Mit der im Folgenden gezeigten Einstellung werden die letzten fünf Werte X-Werte des AccelerometerSensor gemittelt.

Designer Properties

Es stehen zwei verschiedene Mittelwerte zur Verfügung. Die Eigenschaft Average liefert das arithmetische Mittel. WeightedAverage liefert ein gewichtetes Mittel, bei dem die jüngsten Werte am stärksten und die ältesten nur schwach gewichtet werden. Sind fünf Werte im Cache (V1 (älteste Wert), V2 .. V5 (jüngster Wert) wird wie folgt berechnet:

Result = (V1 * 1 + V2 * 2 +  .. + V5 * 5) / (1 + 2 + .. + 5)

Die Eigenschaft Count gibt an, in wie weit der Cache gefüllt. Nach einer Anlaufzeit hat Count den Wert von CacheSize.

Referenz UrsSensorAverager

Eigenschaften

Average
Calcutes the average of the stored values.
CacheSize
Specifies the number of values to aggregate.
Count
Gets the number of stored values.
DataSourceKey
Sets the Data Source key identifier for the value to import from the attached Data Source.

An example is the tag of the TinyDB component, which identifies the value.

The property is a Designer-only property, and should be changed after setting the Source component of the Chart Data component.

A complete list of applicable values for each compatible source is as follows:

  • For the AccelerometerSensor, the value should be one of the following: X, Y or Z.
  • For the GyroscopeSensor, the value should be one of the following: X, Y or Z.
  • For the LocationSensor, the value should be one of the following: latitude, longitude, altitude or speed.
  • For the OrientationSensor, the value should be one of the following: pitch, azimuth or roll.
  • For the Pedometer, the value should be one of the following: WalkSteps, SimpleSteps or Distance.
  • For the ProximitySensor, the value should be distance.
Source
Sets the Source to use for the Data component. Valid choices include AccelerometerSensor, GyroscopeSensor, LocationSensor, OrientationSensor, Pedometer or ProximitySensor.
WeightedAverage
Calcutes the weighted average of the stored values.

Verwendung Komponente UrsAverager

Nicht jede Sensorkomponente kann in die oben beschriebenen eingebunden werden. Die möglichen Sensortypen werden (vermutlich) hart gefiltert. Die Komponente UrsAverager bietet die gleichen Mittelwertfunktionen wie UrsSensorAverager, kann aber mit beliebigen Werten bestückt werden. Zur Mittelung von Sensorwerten sollte unbedingt eine Instanz von UrsSensorAverager benutzt werden. Die Übernahme wird intern geregelt. Bei der Verwendung von UrsAverager müssen die Daten über den aufwändigen App-Inventor-Ereignismechanismus geschleust werden.

Die Eigenschaft CacheSize gibt an, über wie viele Werte gemittelt werden soll. Mit der Methode Add werden neue Werte dem Cache hinzugefügt. Übersteigt die Anzahl der gespeicherten Werte den Wert von CacheSize wird der älteste Wert verworfen.

Es stehen zwei verschiedene Mittelwerte zur Verfügung. Die Eigenschaft Average liefert das arithmetische Mittel. WeightedAverage liefert ein gewichtetes Mittel, bei dem die jüngsten Werte am stärksten und die ältesten nur schwach gewichtet werden. Sind fünf Werte im Cache (V1 (älteste Wert), V2 .. V5 (jüngster Wert) wird wie folgt berechnet:

Result = (V1 * 1 + V2 * 2 +  .. + V5 * 5) / (1 + 2 + .. + 5)

Die Eigenschaft Count gibt an, in wie weit der Cache gefüllt. Nach einer Anlaufzeit hat Count den Wert von CacheSize.

Referenz

Eigenschaften

Average
Calcutes the average of the stored values.
CacheSize
Specifies the number of values to aggregate.
Count
Gets the number of stored values.
WeightedAverage
Calcutes the weighted average of the stored values.

Funktionen

Add (value)
Add a new value to the data cache.

Beispielprojekt

Das Beispielprojekt versucht alle wesentlichen Features der Extension darzustellen. Es sind drei Screens implementiert:

Bereiche

Screen1 besteht aus mehreren Bereichen. Zum besseren Überblick sind diese farblich hinterlegt.

Konstante Daten

Bereich konstante Daten

Angezeigt werden: ein evtl. Startwert, der SDK-Level der laufenden Android-Version, die Version der Extension und der Werte der Eigenschaften AreNotificationsEnabled und IsIgnoringBatteryOptimizations Die Werte werden im Ereignis Screen1.Initialize ermittelt. AreNotificationsEnabled und IsIgnoringBatteryOptimizations werden im Ereignis OnNotificationPermissionResponse bzw. OnBackgroundPermissionResponse angepasst.

Berechtigungen

Damit die App wie vorgesehen funktioniert, sind zwei Berechtigungen erforderlich: die Berechtigung, Benachrichtigungen zu erstellen, und die Berechtigung, im Hintergrund aktiv zu sein.

Bereich Berechtigung

Diese Bereiche werden im nicht im Companion angezeigt, da dort kein ForegroundService angelegt werden kann und auch die Berechtigung zur Hintergrundaktivität nicht erteilt werden kann. In der kompilierten App werden sie angezeigt, wenn die entsprechende Berechtigung nicht erteilt sind.

Der angezeigten Texte lauten vollständig "You must grant permission to post notifications for the app to work correctly." und "You must grant permission to operate in the background for the app to work correctly.".

Über die Schaltfläche cmdRequestNotificationPermission (Text: Request Notification Permission) wird über die Funktion RequestNotificationPermission ein Dialog zur Erteilung der Berechtigung zum Senden von Benachrichtigungen geöffnet. Die Schaltfläche cmdRequestBackgroundPermission (Text: Request Background Permission) ruft die Funktion RequestIgnoreBatteryOptimizations auf. Hierdurch wird ein Dialog geöffnet, der die Berechtigung für Hintergrundaktivitäten erfragt:

Dialog: Berechtigung zum Senden von Benachrichtigungen   Dialog: Berechtigung zur Hintergrundaktivität

Beide Dialoge stammen von einem Motorola g15 mit Android 15.

Wenn eine Berechtigung erteilt wurde, wird der entsprechende Bereich unsichtbar geschaltet. Sind beide Berechtigungen erteilt, erscheint der Bereich zum Starten des ForegroundService.

ForegroundService, Benachrichtigung

Bereich ForegroundService, Benachrichtigung

Dieser Bereich steht im Companion nicht zur Verfügung, da dort kein ForegroundService angefordert werden kann. In der kompilierten App erscheint er nur, wenn die Berechtigung zum Senden von Benachrichtigungen erteilt wurde.

Man kann den ForegroundService starten, inkl. der oben gezeigten Benachrichtigung und WakeLock, und auch wieder stoppen. Bei laufendem ForegroundService wird die CPU nicht abgeschaltet und die Sensoren liefern auch dann Ergebnisse, wenn die App in den Hintergrund gelangt oder der Bildschirm ausgeschaltet wird. Um das zu verifizieren, werden über den Timer tmReadAcc bei gestartetem Beschleunigungssensor dessen Daten per UDP an die Broadcast-Adresse 255.255.255.255, Port 2222 gesendet.

Das Verhalten der Benachrichtigung kann angepasst werden. Wenn die Benachrichtigung angezeigt wird, kann über die Schaltfläche cmdAlterNotification (Alter Notification Title) die Überschrift der Benachrichtigung in "Altered Title" abgeändert. Über die Schaltfläche cmdAlterChannel kann gezeigt werden, dass man den Namen des Benachrichtigungskanals nachträglich ändern kann. Der neue Name ist dann "New Channel".

Geänderte Benachrichtigungsparameter

Wird eine der Aktionsschaltflächen in der Benachrichtigung angetippt, wird dessen Nummer kurz im Label lblActionButton angezeigt. Über den Timer tmClearActionMsg wird die Anzeige nach drei Sekunden wieder gelöscht.

Beschleunigungssensor

Bereich Beschleunigungssensor

In diesem Bereich werden die Daten des Beschleunigungssensors angezeigt. Wenn der Sensor gestartet wurde, die Messdaten des Ereignisses SensorChanged in der eingestellten Rate im Label lblFromEventAcc angezeigt. Außerdem wird, gesteuert über den Timer tmReadAcc, die aktuellen Messwerte im Sekundentakt über die Funktion GetValues abgerufen und im Label lblFromReadingAcc angezeigt. Zusätzlich werden die  Daten per UDP an die Broadcast-Adresse 255.255.255.255, Port 2222 gesendet.

Zusätzlich werden im Sekundentakt gemittelte X-Werte des Beschleunigungssensors über eine Instanz von UrsSensorAverager abgerufen und angezeigt.

Magnetfeldsensor

Bereich MagneticFiledSensor

Der Magnetfeldsensor funktioniert ähnlich wie der Beschleunigungssensor. Leider ist die Benutzung der UrsSensorAverager-Komponente nicht möglich (durch den App Inventor nicht vorgesehen. Hier muss zur Glättung auf die UrsAverager-Komponente zurück gegriffen werden. Im Ereignis MagneticChanged werden die gemeldeten xStrength-Werte an eine UrsSensorAverager-Komponente übergeben.

Glättung des Messwertes

Implementierung

Zur besseren Übersicht sind die Funktionsblöcke nach Aufgaben sortiert:

Ünersicht über die Code-Blöcke

Werkzeuge

Für die Erstellung einer eigenen Extension habe ich einige Tipps zusammengestellt: AI2 FAQ: Extensions entwickeln.