Englisch version   English version


Version Anpassungen
1.0 (2021-05-05) Initiale Version
1.1 (2021-07-11)
1.2 (2021-09-12)

Wird die Extension in mehreren Apps verwandt, löst ein Antippen einer Aktionsschaltfläche das zugehörige Ereignis in allen Apps gleichzeitig aus. Das liegt an der Globalität der verwendeten Broadcast-Receiver. Abhilfe: Die Intents für die Aktionsschaltflächen sind mit dem App-Namen individualisiert. Beim Empfang einer Broadcast wird der Name überprüft und nur die passenden Nachrichten weiter verarbeitet.

Kodular stellt nun auch viele Androidx-Funktionen bereit. Es muss nur noch "androidx.media.jar" eingebunden werden.

Der Foreground-Service wird nun per UsesServices-Annotaion in der Quelle und manuell in die Rubrik broadcastReceivers in der generierten .aix-Datei eingetragen.

Durch diese Änderungen ist nicht mehr notwendig zwei verschiedene Version der Extension für App Inventor und Kodular zu haben.


Anpassung bestehender Kodular-Projekte:

Es besteht interne Namensgleichheit. Deshalb kann die alte Version durch die neue ersetzt werden. Dies geht jedoch nur über einen Export des Projekts und einem Reimport.

  • Sicherheitskopie des Projekts erstellen.
  • Projekt exportieren.
  • In der .aia-Datei (ist ein ZIP-Archiv) im Verzeichnis assets/external_comps das Verzeichnis de.ullisroboterseite.ursai2medianotificationk löschen.
  • Aus der Extension (.aix-Datei, ebenfalls ein ZIP-Archiv) das Verzeichnis de.ullisroboterseite.ursai2medianotification an diese Stelle in der .aia-Datei kopieren.
  • Das Projekt (.aia-Datei) nach Kodular reimportieren.
1.3 (2021-09-15) Wie oben. Nun auch für das Anklicken der Notification und das Löschen individualisierte Intents um Überschneidungen bei gleichzeitiger Benutzung der Extension in mehreren Apps zu verhindern.


Download

Verwendung

Über Benachrichtigungskanäle

Konfiguration

Foreground-Service / Doze-Mode

Schaltflächen in der Media-Notification

Ereignisse aktivieren

Meta-Daten und Erscheinungsbild

Fortschrittsbalken (ProgressBar, ab Android 10, API Level 29)

Handhabung

Fehlerbehandlung

Referenz

Eigenschaften

Funktionen

Ereignisse

Beispiel

Die Benutzeroberfläche

Steuerelemente

Optionen

Zum Verständnis der Implementierung

Erstellen der Extension

Bereitstellen der Bibliotheken

Kopieren der Bibliotheken

Deklaration in den Quellen

Pachten der .aix-Dateien für Kodular

Portieren eines Projekts vom App Inventor nach Kodular

Werkzeuge

 

Download

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

Verwendung

Seit dem API-Level 21 (LolliPop 5.0) gibt es die Media Controls, eine besondere Form der Benachrichtigung (Notification), die eigens zur Steuerung von Mediaplayern  entwickelt wurde. Der Clou ist, dass auch Steuerimpulse externer Wiedergabegeräte ausgewertet werden.

Diese Extension ist ausschließlich zu Verwaltung von Media-Notifications gedacht. Wer reguläre Benachrichtigungen erstellen will, sollte die Extension UrsAI2Notifier benutzen.

Über Benachrichtigungskanäle

Mit dem API-Level 26 (Version Oreo 8.0) hat Android das Konzept der Benachrichtigungskanäle eingeführt (NotificationChannel, bei manchen Geräten auch Benachrichtigungskategorien genannt). Sämtliche Benachrichtigungen müssen ab API Level 26 einem solchen Kanal zugeordnet werden. Bis einschließlich API Level 25 sind alle den Benachrichtigungskanal betreffende Angaben und Funktionen wirkungslos.

Das Benachrichtigungskonzept ist relativ komplex. Android erlaubt es, Einstellungen sowohl auf der Geräteebene, als auch auf der Kanalebene und bei den Benachrichtigungen selbst vorzunehmen.

Viele Eigenschaften der Benachrichtigungen, z.B. die Wichtigkeit (Importance), werden auf der Kanal-Ebene festgelegt. Diese Eigenschaften werden von der App bei der Anlage des Kanals festgelegt. Der Benutzer hat mit Hilfe die App Eigenschaften vollen Zugriff auf die meisten der Kanalattribute und kann sie nach belieben modifizieren. Die Modifikationen des Benutzers sollen nicht überschrieben werden. Deshalb können die Kanaleigenschaften nachträglich nicht mehr per Programm geändert werden.  Das geht sogar soweit, dass, wenn eine Kanal gelöscht und anschließend wieder angelegt wird, er mit den zuletzt vorhandenen Einstellungen erzeugt wird. Das "Löschen" ist praktisch nur ein "Verstecken". Lediglich die Eigenschaften Name und Description eines Kanals lassen sich nachträglich ändern. Die Beseitigung von Schreibfehler wäre ansonsten unmöglich.

Man sollte sich also sehr gut überlegen, welche Eigenschaften einem Kanal zugewiesen werden.

Die Extension bietet die Eigenschaften ChannelID, ChannelName, ChannelDescription und ChannelImportance zur Festlegung der Kanaleigenschaften. Der Kanal wird direkt nach Start der App angelegt (im Companion erst dann, wenn das erste Mal ShowNotification aufgerufen wird).

Will man andere Eigenschaften ändern, muss ein neuer Kanal (neue ChannelID) verwendet werden. Den bestehenden Kanal versteckt man sinnvollerweise beim Start der App mit HideChannel.

Konfiguration

Sämtliche Änderungen haben keine sofortige Wirkung. Erst beim nächsten Aufruf von ShowNotification werden sie übernommen.

Foreground-Service / Doze-Mode

FFür manche Projekte ist es notwendig zu verhindern, dass die zugehörige App vom Betriebssystem deaktiviert wird. Mit der Version 6.0 (Marshmallow) hat Android den Doze-Modus zur Optimierung der Akku-Laufzeiten eingeführt. Diese Funktion schaltet, wenn keine App aktiv bedient wird, nach und nach alles herunter (Display, CPU, WiFi, etc.). Um den Doze Mode wirkungsvoll zu umgehen, ist es notwendig, einen Foreground-Service anzulegen. Viele nützliche Hintergrundinformationen findet man im ZEBRA Developer Portal: Keeping your Android application running when the device wants to sleep.

Die meisten Android-Installationen erkennen, wenn ein Mediaplayer aktiv ist und schalten das Gerät nicht ab. Für den Fall, dass dies doch geschieht, kann über die Eigenschaft ForegroundService festgelegt werden, dass bei der Anzeige der Notification ein Foreground-Service gestartet wird. Hat die installierte Android-Version einen API Level von unter 26, ist die Angabe wirkungslos.

Schaltflächen in der Media-Notification

Die Schaltfläche mit dem Play()- bzw. dem Pause()-Symbol wird immer angezeigt. Welches der beiden angezeigt wird, kann über die Funktionen SetStatePaused (zeigt an) und SetStatePlaying (zeigt ) an) eingestellt werden.

Die anderen Schaltflächen lassen sich über die Support...-Funktionen an- und abstellen, je nachdem welche Funktionen die App unterstützt.

Ereignisse aktivieren

Ist ClickAble gesetzt, wird beim Anklicken des Benachrichtigungskörpers die App in den Vordergrund gebracht und das Ereignis OnClick ausgelöst. Ist ClickAble auf false gesetzt, passiert beim Anklicken der Benachrichtigung nichts.

Um die App in dem Ereignis in den Vordergrund zu bringen, ist ein kleiner Trick notwendig. Im Beispiel wird im OnClick-Ereignis ein Screen mit der Bezeichnung Dummy geöffnet. Dieser Screen schließt sich unmittelbar im Ereignis Screen.Initialize selbst wieder:

 

Wird DeleteAble gesetzt, kann der Anwender die Benachrichtigung, z.B. durch Wischen, löschen. Wenn die Notification vom Anwender gelöscht wird, wird das Ereignis UserCanceled ausgelöst.

Meta-Daten und Erscheinungsbild

Die Hintergrundfarbe ist nicht einstellbar, sondern wird von Android automatisch aus dem Album-Image ermittelt.

Über die Funktion SetMetaData und SetMetaDataEx können Titel, Interpret und und ein Bild (AlbumImage) angegeben werden, die in der Benachrichtigung angezeigt werden.

AlbumImage

Für AlbumImage sind folgende Angaben möglich:

Typ Präfix Beispiel
URL http oder https https://ullisroboterseite.de/android-AI2-MediaNotification/MediaNotification.png
Asset // oder nichts //MediaNotification.png oder einfach nur MediaNotification.png
Datei, relativer Pfad / /data/user/0/appinventor.ai_bienonline.UrsMediaNotificationAI2/MediaNotification.png
Datei, absoluter Pfad file:///  file:///Android/data/appinventor.ai_bienonline.UrsMediaNotificationAI2/MediaNotification.png

Bei der Angabe einer URL ist zu beachten, dass das Bild synchron geladen wird. Dies kann bei großen Dateien oder langsamen Verbindungen einige Zeit in Anspruch nehmen. Eine andere Möglichkeit ist es, eine Extension zu verwenden, die einen asynchronen (nebenläufigen) Download der Datei ermöglicht (z.B. die Extension ImageLoader).

Um den Zugriff auf die Dateien zu erleichtern, gibt es die Funktionen

Small Icon

Die Möglichkeit, eigene Grafiken für das SmallIcon einzubinden (Eigenschaft SmallIconImage), besteht erst ab API Level 23. Deshalb gibt es zusätzlich die Möglichkeit über die Eigenschaft SmallSystemIcon ein System-Icon auszuwählen (für mögliche Angaben siehe: System Notification Icons). Die Auswahlregel ist wie folgt:

Bedingung Auswahl
API Level SmallIconImage SmallSystemIcon
≥ 23 gefüllt X SmallIconImage
leer gefüllt SmallSystemIcon
leer leer kein Icon
< 23 X gefüllt SmallSystemIcon
X leer kein Icon

Fortschrittsbalken (ProgressBar, ab Android 10, API Level 29)

Ab Android 10 kann die Media-Notification einen Fortschrittsbalken (ProgressBar) und eine Suchleiste (SeekBar) anzeigen. Dazu muss die Spieldauer (Duration) des Media-Objekts und die aktuelle Abspielposition (CurrentPosition) bekannt sein.

SetMetaDataEx erlaubt die Angabe der Spieldauer, die für die Anzeige eines Fortschrittsbalkens (ProgressBar) benötigt wird. Einige Media-Player, wie der im Beispiel benutzte TaifunPlayer, liefern diese Information. Dazu muss der Player aber entsprechend initialisiert sein.

Der Funktion ShowWithProgressBar zeigt einen Fortschrittsbalken an. Er startet an mit der Position, die im Parameter CurrentPosition übergeben wird. Danach läuft er selbständig weiter. Wenn man die Abspielposition per Programm ändert, muss man den Fortschrittsbalken wieder mit ShowWithProgressBar synchronisieren.

Bei Versionen älter als Android 10, funktionieren SetMetaDataEx und ShowWithProgressBar ebenfalls, allerdings wird kein Fortschrittsbalken angezeigt.

Handhabung

Man stellt die initialen Eigenschaften der Komponente passend ein, übergibt die Media-Metadaten (SetMetaData oder SetMetaDataEx) und ruft anschließend ShowNotification bzw. ShowWithProgressBar auf. Von nun an braucht man eigentlich nur noch auf die Ereignisse reagieren. Je nach Ereignis stellt man den Mediaplayer passend ein, passt Eigenschaften der Komponente an und ruft wieder ShowNotification auf.

In der Regel soll der Mediaplayer nicht nur von der Media-Notification gesteuert werden. Meist enthält die App ebenfalls Steuerelemente, die den Player kontrollieren sollen. Um die Blöcke im Projekt einfach zu gestalten, gibt es die Funktionen Play, Pause, Rewind, etc., die die gleichen Ereignisse auslösen, wie die Notification. Es ist also keine doppelte Programmierung für die Steuerelemente auf der Benutzeroberfläche notwendig. Es muss lediglich die passende Funktion aufgerufen werden.

Fehlerbehandlung

 Fehler werden über das Ereignisse Screen.ErrorOccurred  gemeldet.

Code Text Bedeutung Anmerkung
17500 Album image not found. Das angegebene Album-Image konnte nicht geladen werden. Betroffene Funktionen sind SetMetaData und SetMetaDataEx
17501 No meta data set. Die Benachrichtigung soll angezeigt werden, ohne dass vorher SetMetaData oder SetMetaDataEx aufgerufen wurde. Betroffene Funktion ist ShowNotification.
17502 SmallIconImage invalid. Die Grafik-Datei beim Parameter SmallIconImage kann nicht geladen werden. Betroffene Funktion ist ShowNotification. Die Benachrichtigung wird ohne ein Icon angezeigt.
17503 SmallSystemIcon invalid. Die Angabe beim Parameter SmallSystemIcon kann nicht aufgelöst werden. Betroffene Funktion ist ShowNotification. Die Benachrichtigung wird ohne ein Icon angezeigt.
17504 Cannot start foreGround service. Der angeforderte Foreground-Service kann nicht gestartet werden. Betroffene Funktion ist ShowNotification.
17506 Not an UrsMediaHelper component. Die übergebene Komponente ist nicht vom Typ UrsMediaHelper. Betroffene Funktion ist SetMetaDataFromMH.

Referenz

Eigenschaften

ChannelDescription
Für den Benutzer sichtbare Beschreibung des Benachrichtigungskanals (NotificationChanel). Diese Eigenschaft kann nachträglich geändert werden.
ChannelID
Die ID des Benachrichtigungskanals (NotificationChanel) (nicht nachträglich änderbar).
ChannelImportance
Legt die Bedeutsamkeit (Importance) des Kanals fest. Die Voreinstellung ist NotificationManager.IMPORTANCE_LOW.
ChannelName
Für den Benutzer sichtbarer Name des Benachrichtigungskanals (NotificationChanel). Diese Eigenschaft kann nachträglich geändert werden.
ClickAble
true: Das Anklicken der Benachrichtigung stellt die App in den Vordergrund und löst dort das Ereignis OnClick aus. false: Das Anklicken der Benachrichtigung hat keine Wirkung.
Hinweis: Das Ändern dieser Eigenschaft wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
DeleteAble
Die Benachrichtigung kann vom Anwender, z.B. durch Wischen, gelöscht werden. Diese Option hat bei aktivem Foreground-Service keine Wirkung. Der Foreground-Service verbietet das Löschen der Benachrichtigung.
Hinweis: Das Ändern dieser Eigenschaft wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
ForegroundService
Bei der Anzeige der Benachrichtigung wird ein Foreground-Service gestartet. Der Foreground-Service verhindert, dass der Doze-Modus zuschlägt. Die Funktion ist im Companion wirkungslos, da hier keine Foreground-Services unterstützt werden. Je nach Android-Version und Hersteller des Geräts sind weitere Maßnahmen notwendig (s. Beispiel).
IsRunningInCompanion
Gibt an, ob die Anwendung aktuell im Companion läuft.
SmallIconImage
Erst ab API Level 23! Asset-Name (Rubrik Media im App Inventor) der Datei für das Icon in der Status-Leiste (siehe auch Notification.Builder.setSamallIcon). Bei Versionen bis API Level 22 wird diese Angabe ignoriert. Siehe auch Meta-Daten und Erscheinungsbild.
Ob das Icon angezeigt wird, ist abhängig von der Android-Version, vom Gerätehersteller und der Bedeutsamkeitsstufe des Benachrichtigungskanals.
Hinweis: Das Ändern dieser Eigenschaft wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
SmallSystemIcon
Icon für Android-Versionen bis API-Level 22. Für mögliche Angaben siehe: System Notification Icons. Siehe auch Meta-Daten und Erscheinungsbild.
Ob das Icon angezeigt wird, ist abhängig von der Android-Version, vom Gerätehersteller und der Bedeutsamkeitsstufe des Benachrichtigungskanals.
Hinweis: Das Ändern dieser Eigenschaft wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
StateIsPlaying
Liefert den Zustand der Benachrichtigung. true: Das Pause-Symbol () wird angezeigt. false: das Play-Symbol () wird angezeigt.
SupportFastForward
In der Benachrichtigung wird das Symbol für Fast Forward (>>) angezeigt.
Hinweis: Das Ändern dieser Eigenschaft wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
SupportRewind
In der Benachrichtigung wird das Symbol für Rewind (<<) angezeigt.
Hinweis: Das Ändern dieser Eigenschaft wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
SupportSkipToNext
In der Benachrichtigung wird das Symbol für Skip to next (>|) angezeigt.
Hinweis: Das Ändern dieser Eigenschaft wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
SupportSkipToPrevious
In der Benachrichtigung wird das Symbol für Skip to previous (|<) angezeigt.
Hinweis: Das Ändern dieser Eigenschaft wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
Version
Versionsname der Extension. Version für Kodular beginnen mit einem "K", z.B. "K1.0.0".
VersionSDK
Der API-Level der aktuell laufenden Android-Instanz.

Funktionen

FastForward ()
Löst das Ereignis OnFastForward aus. Schaltflächen auf der Benutzeroberfläche können über diese Funktion das gleiche Ereignis (und so auch den gleichen Code) wie das Antippen der Media-Schaltfläche Fast Forward auslösen.
GetAppDataDir ()
Liefert den Pfad für das app-spezifische Verzeichnis. Der Aufruf von GetAppDataDir() auf meinem Testgerät für das Beispiel-Programm liefert folgendes Ergebnis:
     /data/user/0/appinventor.ai_bienonline.UrsMediaNotificationAI2/
GetDownloadDir (Prefix)
Liefert den Pfad für das Download-Verzeichnis. Der bei Prefix angegebene wird den Namen vorangestellt. Der Aufruf von GetDownloadDir("file://") auf meinem Testgerät für das Beispiel-Programm liefert folgendes Ergebnis:
     file:///storage/emulated/0/Download/
GetVolumes (Prefix)
Liefert eine Liste der installierten Speicher (Volumes). Unter Index 1 findest man meist den internen Speicher, unter Index 2 die externe SD-Karte. Der bei Prefix angegebene wird den Namen vorangestellt. Der Aufruf von getVolumes("file://) gibt auf meinem Testgerät folgende Elemente:
     file:///storage/emulated/
     file:///storage/F277-0260/
HideChannel ()
Versteckt den Channel. Erst ab API Level 26!
Wenn ein neuer Kanal mit derselben ID erstellt wird, wird der gelöschte Kanal mit allen Einstellungen wieder hergestellt, die er vor dem Löschen hatte.
Pause ()
Löst das Ereignis OnPause aus. Schaltflächen auf der Benutzeroberfläche können über diese Funktion das gleiche Ereignis (und so auch den gleichen Code) wie das Antippen der Media-Schaltfläche Pause auslösen.
Play ()
LLöst das Ereignis OnPlay aus. Schaltflächen auf der Benutzeroberfläche können über diese Funktion das gleiche Ereignis (und so auch den gleichen Code) wie das Antippen der Media-Schaltfläche Play auslösen.
Rewind ()
Löst das Ereignis OnRewind aus. Schaltflächen auf der Benutzeroberfläche können über diese Funktion das gleiche Ereignis (und so auch den gleichen Code) wie das Antippen der Media-Schaltfläche Rewind auslösen.
SetMetaData (Title, Artist, AlbumImage)
Die Meta-Daten werden an die Benachrichtigung übergeben. Wie der Parameter AlbumImage beschickt werden kann, wird im Abschnitt Meta-Daten und Erscheinungsbild näher erläutert.
Wenn das Album-Image nicht geladen werden kann, wird das Ereignis Screen.ErrorOccurred mit der Fehlernummer 17500 ausgelöst. Die Meta-Daten werden ohne ein Album-Image angelegt.
Hinweis: Das Ändern dieser Daten wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
SetMetaDataEx (Title, Artist, AlbumImage, Duration)
Die Meta-Daten werden an die Benachrichtigung übergeben. Wie der Parameter AlbumImage beschickt werden kann, wird im Abschnitt Meta-Daten und Erscheinungsbild näher erläutert.
Wenn das Album-Image nicht geladen werden kann, wird das Ereignis Screen.ErrorOccurred mit der Fehlernummer 17500 ausgelöst. Die Meta-Daten werden ohne ein Album-Image angelegt.
Hinweis: Das Ändern dieser Daten wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
SetMetaDataFromMH (MediaHelper)
Die Meta-Daten werden aus einer UrsMediaHelper-Komponente übernommen.
Wenn die übergebene Komponente nicht vom Typ UrsMediaHelper ist, wird das Ereignis Screen.ErrorOccurred mit der Fehlernummer 17506 ausgelöst.
Hinweis: Das Ändern dieser Daten wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
SetStatePaused ()
Die Benachrichtigung erhält den Status Pause. Das Play-Symbol () wird angezeigt.
Hinweis: Das Ändern dieser Daten wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
SetStatePlaying ()
Die Benachrichtigung erhält den Status Play. Das Play-Symbol () wird angezeigt.
Hinweis: Das Ändern dieser Daten wirkt sich erst nach dem nächsten Aufruf von ShowNotification aus.
ShowNotification ()
Die Benachrichtigung wird angezeigt. Wenn die ForegroundService eingeschaltet ist, wird in der kompilierten App ein Foreground-Service gestartet (nicht im Companion). Für mögliche Fehler siehe Abschnitt Fehlerbehandlung.
ShowWithProgressBar (CurrentPosition)
Die Benachrichtigung wird angezeigt. Unter Android 10 und folgende wird, wenn über SetMetaDataEx die Spieldauer (Duration) übermittelt wurde, ein Fortschrittsbalken angezeigt. Die Position der Fortschrittsmarkierung von aus den Angabe zu CurrentPosition in Relation zu Duration ermittelt.
Wenn die ForegroundService eingeschaltet ist, wird in der kompilierten App ein Foreground-Service gestartet (nicht im Companion). Für mögliche Fehler siehe Abschnitt Fehlerbehandlung.
SkipToNext ()
Löst das Ereignis OnSkipToNext aus. Schaltflächen auf der Benutzeroberfläche können über diese Funktion das gleiche Ereignis (und so auch den gleichen Code) wie das Antippen der Media-Schaltfläche Skip to next auslösen.
SkipToPrevious ()
Löst das Ereignis SkipToPrevious aus. Schaltflächen auf der Benutzeroberfläche können über diese Funktion das gleiche Ereignis (und so auch den gleichen Code) wie das Antippen der Media-Schaltfläche Skip to previous auslösen.
Stop ()
Löscht die Benachrichtigung. Ein ggf. aktivierter Foreground-Service wird gestoppt.

Ereignisse

OnClick ()
Die Benachrichtigung wurde angeklickt. Nur aktiv, wenn Eigenschaft ClickAble eingestellt ist
OnFastForward (FromNotification)
Das Symbol Fast Forward (>>) in der Benachrichtigung wurde angeklickt (FromNotification = true) oder die Funktion FastForward wurde aufgerufen (FromNotification = false).
OnPause (FromNotification)
Das Symbol Pause () in der Benachrichtigung wurde angeklickt (FromNotification = true) oder die Funktion Pause wurde aufgerufen (FromNotification = false).
OnPlay (FromNotification)
Das Symbol Play () in der Benachrichtigung wurde angeklickt (FromNotification = true) oder die Funktion Play wurde aufgerufen (FromNotification = false).
OnRewind (FromNotification)
Das Symbol Rewind (<<) in der Benachrichtigung wurde angeklickt (FromNotification = true) oder die Funktion Rewind wurde aufgerufen (FromNotification = false).
OnSkipToNext (FromNotification)
Das Symbol Skip to next (>|) in der Benachrichtigung wurde angeklickt (FromNotification = true) oder die Funktion SkipToNext wurde aufgerufen (FromNotification = false).
OnSkipToPrevious (FromNotification)
Das Symbol Skip to previous (|<) in der Benachrichtigung wurde angeklickt (FromNotification = true) oder die Funktion SkipToPrevious wurde aufgerufen (FromNotification = false).
OnStop (FromNotification)
Die Funktion Stop wurde aufgerufen (FromNotification = false). Ein evtl. aktiver Foreground-Service wurde gestoppt.
UserCanceled ()
Der Anwender hat die Benachrichtigung gelöscht. Nur aktiv, wenn Eigenschaft DeleteAble eingestellt und kein Foreground-Service aktiv ist. Ein aktiver Foreground-Service verbietet das Löschen der zugehörigen Benachrichtigung.

Beispiel

Das Download-Archiv enthält ein Beispiel-Projekt in zwei Versionen, je eine für App Inventor und Kodular:

 UrsMediaNotification

Das Download-ZIP-Archiv enthält im Verzeichnis example je eine Beispielprojektdatei für App Inventor (UrsMediaNotification.aia) und für Kodular (UrsMediaNotificationK.aia).

Das Beispiel demonstriert, wie ein Mediaplayer mit der Extension gesteuert werden kann. Als Player wird der TaifunPlayer verwendet. Es können vier verschiedene Musikstücke abgespielt werden.

In Kodular können die Fonts der Schaltflächen individuell eingestellt werden. U.a. steht dort der Material Icons Font mit vielen nützlichen Symbolen von Google zur Verfügung. Für den App Inventor wird die Extension MyFonts von Anke benutzt.

Die Benutzeroberfläche

Steuerelemente

Die Steuerelemente werden je nach aktuellen Zustand der App freigegeben oder gesperrt. Sie bewirken

Die zugehörige MediaNotification dupliziert diese Steuerelemente. Es werden nur die freigegeben Elemente angezeigt (Off Broadway ist das letzte Stück in der Playlist, SkipToNext ist deshalb gesperrt und wird nicht angezeigt):

  (Screenshot Xiaomi Redmi 5 Plus, Android Oreo 8.1)

Die Anzeige eines Stoppsymbols steht in der Android Media-Notification leider nicht zur Verfügung.

In Android 10 wird die Hintergrundfarbe automatisch an die Farbe des Album-Bildes angepasst.

(Screenshot Google Pixel 2 XL API 30 Emulator)

Ein Fortschrittsbalken (ab Android 10) wird eingeblendet, wenn man die Notification aufzieht:

Optionen

Zum Verständnis der Implementierung

Die Prozedur SetMusic füllt die Extension mit den Metadaten (Titel, Interpret, Album-Bild). Die MP3-Dateien in dem Beispielprojekt enthalte bereits alle benötigten Metadaten, so dass diese einfach mit Hilfe der UrsMediaHelper-Extension übergeben werden können. Die Metadaten lassen sich z.B. mit dem Programm Mp3tag einsehen und bearbeiten.

Bei der Initialisierung wird dafür gesorgt, dass die App gleich zu Beginn korrekt arbeitet. SetMusic stellt die Metadaten und die Musikquelle für den TainfunPlayer auf das erste Musikstück ein. Mit der Kombination MediaPlayer.Start und MediaPlayer.Pause wird erreicht, dass die Eigenschaften Duration und CurrentPosition des Mediaplayers abgerufen werden können, ohne dass er anfängt zu spielen. MediaNotification.SetStatePaused und MediaNotification.ShowNotification zeigen die Notification im Zustand Pause (Symbol ) an. WakeLock.RequestBatteryOptimization setzt die App auf die WhiteList. Beim ersten Start der App erhält der Anwender eine Anfrage, die Erlaubnis hierzu anfordert.

Bei der Änderung der Option WithForegroundService muss ein ggf. bereits gestarteter Foreground-Service mit der Anweisung MediaNotifiaction.Stop gestoppt werden. Diese Anweisung löst das Ereignis OnStop aus. Im Normalfall wird in diesem Ereignis der MediaPlayer gestoppt. Damit dies jedoch nicht beim Umschalten der Option geschieht, wird dies mit Hilfe der Variablen DontStopPlayer verhindert.

Beim Weiterschalten zum nächsten Musikstück (SkipToNext) und beim Zurückschalten (SkipToPrevious) wird zunächst der der aktuelle Zustand des Mediaplayers in einer lokalen Variablen zwischengespeichert. Dieser soll nach dem Umschalten wieder hergestellt werden. Danach wird der Player gestoppt. Das nächste (das vorhergehende) Musikstück wird ermittelt und dabei dem Zustand der Playlist entsprechenden Schaltflächen freigegeben bzw. gesperrt. Die Blöcke werden über die Prozedur SetMusic mit den Daten des neu ausgewählten Musikstücks gefüttert. Zum Schluss werden entsprechend des gespeicherten Player-Zustands die Ereignisse OnPlay bzw. OnPause ausgelöst. In den Ereignissen wird dafür gesorgt, dass der Mediaplayer und die MediaNotification passen eingestellt werden.

Erstellen der Extension

Die Extension kann zusammen mit der UrsAI2WakeLock-Entension verhindern, dass der Doze-Modus zuschlägt und das Smartphone abschaltet. Dazu wird ein ForegroundService gestartet. Dieser Service muss in der Manifest-Datei der App deklariert werden. Im App Inventor geht dies, Kodular hat noch nicht nachgezogen. Hier muss die erstellte .aix-Datei nachträglich gepacht werden.

Die folgende Beschreibung setzt voraus, dass die Entwicklungsumgebung nach dem in AI2 FAQ: Extensions entwickeln beschriebenen Schema eingerichtet wurde.

Bei Verzeichnisangaben in den folgenden Abschnitten muss <user> stets durch den entsprechenden Namen ersetzt werden!

Bereitstellen der Bibliotheken

Die Extension verwendet viele Android-Klassen aus der Androidx-Bibliothek. Das ZIP-Archiv enthält im Verzeichnis de.ullisroboterseite neben den Verzeichnissen für den Source-Code der Extension auch die Androidx-Bibliotheksdateien: androidx.core-1.3.2-runtime.jar. Diese Bibliothek muss zusätzlich in die Extension eingebunden werden.

Kopieren der Bibliotheken

Damit die Bibliotheken in die Extension eingebunden werden, müssen sie in das vorgesehene Verzeichnis kopiert und im Source-Code deklariert werden.

 Das Kopieren geschieht über das Build-Script. Dazu muss in der Datei

C:/Users/<user>/appinventor-sources/appinventor/components/build.xml

folgender Eintrag in der Rubrik CopyComponentLibraries gemacht werden:

<copy toFile="${public.deps.dir}/androidx.media.jar"      file="C:/Users/<user>/appinventor-sources/appinventor/components/src/de/ullisroboterseite/androidx.media-1.3.1-runtime.jar"/>

Deklaration in den Quellen

In der Quelle wird die benutzte Bibliothek über die Annotation @UsesLibraries deklariert und der Foreground-Service über Annotation @UsesServices:

@UsesServices(services = {
        @ServiceElement(name = "de.ullisroboterseite.ursai2medianotification.ForegroundService", enabled = "true", exported = "false") })
@UsesLibraries(libraries = "androidx.media.jar")

Die Umgebung ist nun so weit vorbereitet, dass die Extension kompiliert werden können.

Pachten der .aix-Dateien für Kodular

Der Build-Vorgang erstellt die Datei de.ullisroboterseite.ursai2medianotification.aix. Diese Datei hat das Format einer ZIP-Datei, kann also mit einem entsprechenden Programm geöffnet und bearbeitet werden. Gegebenenfalls hilft es die Datei in ...zip umzubenennen.

Die .aix-Datei enthält den Ordner de.ullisroboterseite.ursai2medianotification und darunter den Ordner files. Im Ordner files befinden sich die beiden Dateien component_build_info.json und component_build_infos.json. Beide können mit einem einfachen Texteditor geöffnet und bearbeitet werden. In beiden Dateien befindet sich der Eintrag

"services":["<service android:name=\"de.ullisroboterseite.ursai2medianotification.ForegroundService\" android:enabled=\"true\" android:exported=\"false\">\n <\/service>\n"]

und der Eintrag

"broadcastReceivers":[]    (nicht verwechseln mit "broadcastReceiver":[]) !

Der Text zwischen den eckigen Klammern bei services muss in die eckigen Klammern bei broadcastReceivers kopiert werden:

"broadcastReceivers":["<service android:name=\"de.ullisroboterseite.ursai2medianotification.ForegroundService\" android:enabled=\"true\" android:exported=\"false\">\n <\/service>\n"]

Falls die Dateien zum Bearbeiten aus dem ZIP-Archiv extrahiert wurden, müssen sie nun wieder in das Archiv (die .aix-Datei) einkopiert werden.

Werkzeuge

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