Englisch version   English version


Version Anpassungen
1.0 (2021-04-26) Initiale Version
2.0 (2021-05-15) ScreenToOpen hat bei Kodular nicht funktionert, wenn der Package Name geändert wurde.
2.1 (2021-06-12) - Eigenschaft FlagNewTask im AlarmIntent wurde nicht korrekt ausgewertet. Ab Android 10 muss dieses Flag auf true gesetzt sein, damit eine Activity gestartet werden kann.
- Default für Eigenschaft FlagNewTask im AlarmIntent auf true gesetzt.
- Parameter WakeUp bei den Funktionen CreateAlarm... wurde nicht korrekt ausgewertet.

Motivation

Obwohl die Android Dokumentation dringend empfiehlt, mit Benachrichtigungen zu arbeiten (siehe developer.android.com), ist es unter bestimmten Umständen dennoch notwendig, dass eine App zu einem bestimmten Zeitpunkt gestartet wird. Mit dieser Extension können Apps zu festgelegten Zeitpunkten gestartet werden. Wer zu bestimmten Zeiten Benachrichtigungen erzeugen will, muss die Extension UrsAI2Notifier benutzen.

Hinweis für Benutzer von Geräten mit Android 10 und aufwärts:

Zum Alarmzeitpunkt wird eine Klasse der Extension im Hintergrund gestartet. Seit Android 10 benötigt eine App zusätzliche Berechtigungen (SYSTEM_ALERT_WINDOW), wenn sie eine andere App starten will, während sie selbst im Hintergrund ausgeführt wird (siehe Restrictions on starting activities from the background, letzter Punkt). Diese Berechtigung kann nicht per Programm gesetzt werden, sondern muss von Anwender über einen Dialog bestätigt werden (s. Zusätzliche Berechtigungen ab Android 10 und bei Xiaomi-Geräten). Eine mögliche Lösung für das Problem wird im Beispiel vorgestellt.

 

Um eine neue Activity zu starten, muss ab Android 10 die Eigenschaft FlagNewTask im AlarmIntent auf true gesetzt sein!

 

Hinweis für Benutzer von Geräten des Herstellers Xiaomi:

Zum Alarmzeitpunkt wird eine Klasse der Extension im Hintergrund gestartet. Bei Xiaomi-Geräten wird, unabhängig von der installierten Android-Version, eine weitere Berechtigung benötigt, wenn eine App eine andere App starten will, während sie selbst im Hintergrund ausgeführt wird. Diese Berechtigung nicht per Programm gesetzt werden, sondern muss von Anwender über einen Dialog bestätigt werden (s. Zusätzliche Berechtigungen ab Android 10 und bei Xiaomi-Geräten). Es kann auch nicht per Programm abgefragt werden, ob diese Berechtigung bereits erteilt wurde. Eine mögliche Lösung für das Problem wird im Beispiel vorgestellt.

Benutzer von Xiaomi-Geräten mit der Android Version 10 und aufwärts müssen beide Berechtigungen erteilen.


In­halts­ver­zeich­nis

Download

Verwendung

Alarme

Intentionen (Intent)

Zusätzliche Berechtigungen ab Android 10 und bei Xiaomi-Geräten

Android 10

Xiaomi Geräte

Referenz

Eigenschaften

Funktionen

Ereignisse

Referenz AlarmIntent

Beispiel

Werkzeuge

Download

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

Verwendung

Hinweis:

Die Extension funktioniert nicht im Companion. Alarme werden über Broadcast-Nachrichten ausgelöst. Damit eine App auch im geschlossenen Zustand Broadcast-Nachrichten muss die App einen Broadcast-Receiver bereitstellen. Dieser muss im Manifest der App deklariert werden. Letzteres ist beim Companion nicht möglich.

Aufgaben, die vom Betriebssystem übernommen werden sollen, werden diese über einen Intent mitgeteilt. Ein Intent (deutsch: Vorhaben, Intention) ist eine abstrakte Beschreibung einer auszuführenden Operation. Die Operation, die zum Alarmzeitpunkt ausgeführt werden soll, wird durch einen Intent festgelegt.

Die Extension enthält zwei Blöcke:

UrsAI2Alarm: Stellt Eigenschaften und Methoden bereit, die die Erzeugung von Alarmen ermöglichen.

AlarmIntent: Legt die Operation fest, die zum Alarmzeitpunkt ausgeführt werden soll.

Alarme

Der UrsAI2Alarm-Block kann Alarme erzeugen und auch wieder löschen. Ein Alarm wird eindeutig durch den RequestCode identifiziert. Beider Erstellung eines Alarms muss dieser festgelegt werden und kann zum Löschen eines noch nicht ausgelösten Alarms genutzt werden.

Leider bietet Android keine Möglichkeit, abzurufen, welche Alarme noch auf die Auslösung warten. Man muss dies selbst verwalten. Das Beispiel Notification Alarm Test zeigt, wie dies geschehen kann.

CreateAlarm und CreateAlarmEx  erzeugen Alarme nach einer angegebenen Verzögerung Der Android AlarmManager führt die hinterlegte Aktion auch dann aus, wenn die App bereits geschlossen ist. CreateAlarmAt erzeugt den Alarm zu einem bestimmten Zeitpunkt.

CancelAlarm löscht einen noch nicht ausgelösten Alarm.

Intentionen (Intent)

Android benutzt Intent-Objekte, um dem System Aufträge zu erteilen. Ein Intent enthält alle Angaben, die notwendig sind, den Auftrag auszuführen. Der AI2 ActivityStarter z.B. benutzt intern Intents um andere Apps zu starten.

Über ein AlarmIntent-Objekt, dass den CreateAlarm...-Funktionen übergeben wird, wird festgelegt, welche Aktion ausgeführt werden soll, wenn der Alarmzeitpunkt eintritt.

Die AlarmIntent-Komponente ist eine Sammlung von Eigenschaften. Sie besitzt weder Funktionen noch Ereignisse.

Der Aktionstyp (ActionType) bestimmt, welche Aktion mit dem Intent ausgelöst wird:

Zusätzliche Berechtigungen ab Android 10 und bei Xiaomi-Geräten

Hinweis: Benutzer von Xiaomi-Geräten mit der Android Version 10 und aufwärts müssen beide Berechtigungen erteilen!

Android 10

Seit Android 10 benötigt eine App zusätzliche Berechtigungen (SYSTEM_ALERT_WINDOW), wenn sie eine andere App starten will, während sie selbst im Hintergrund ausgeführt wird (siehe Restrictions on starting activities from the background, letzter Punkt). Diese Berechtigung kann nicht per Programm gesetzt werden, sondern muss von Anwender über einen Dialog bestätigt werden.

Die Extension stellt die Funktion CheckBackgroundLaunchPermission bereit. Die Funktion prüft, ob die installierte Android Version einen API-Level von 29 (Android 10) oder höher hat und ob dann die Berechtigung SYSTEM_ALERT_WINDOW erteilt wurde. Falls es notwendig ist, dass diese Berechtigung noch erteilt wird, wird ein Dialog zum Erteilen der Berechtigung geöffnet:

 
Deutsche Variante   Englische Variante

Das Ergebnis der Berechtigungsabfrage wird über das Ereignis AfterBackgroundPermssion zurück geliefert. Der neue Zustand der Berechtigung ist nicht sofort nach dem Schließen des Berechtigungsdialogs verfügbar. Das Ereignis wird deshalb erst nach einer kurzen Verzögerung (Eigenschaft PermissionDelay, Vorreinstellung 500 ms) nach dem Schließen des Dialogs ausgelöst. Während dieser Zeit ist der Zustand der Berechtigung undefiniert. Es empfiehlt sich, darauf zu achten, dass währenddessen keine unsinnigen Daten angezeigt werden oder problematische Eingabe gemacht werden können. Am besten stellt man alle betroffenen Bildschirmelemente in ein VerticalArrangement. Dieses kann man zeitweise unsichtbar schalten oder z.B. über die Funktion EnableArrangement der UrsAI2ComponentGroup Extension deaktivieren (s.u. Beispiel).

Zur detaillierten Behandlung dieser Berechtigung stehen zur weiterhin Verfügung:

Xiaomi Geräte

Bei Xiaomi-Geräten wird, unabhängig von der installierten Android-Version, eine weitere Berechtigung benötigt, wenn eine App eine andere App starten will, während sie selbst im Hintergrund ausgeführt wird. Diese Berechtigung nicht per Programm gesetzt werden, sondern muss von Anwender über einen Dialog bestätigt werden (s. Zusätzliche Berechtigungen ab Android 10 und bei Xiaomi-Geräten). Erschwerend kommt hinzu, dass nicht per Programm abgefragt werden kann, ob diese Berechtigung bereits erteilt wurde.

Für die Behandlung dieser Problematik stehen folgende Elemente zur Verfügung:

Der Xiaomi-Berechtigungseditor:

 
Deutsche Variante   Englische Variante

Das Beispielprojekt zeigt eine Möglichkeit, wie diese Berechtigungen behandelt werden können.

Man kann die Berechtigungen auch über die Settings-App vergeben. Dieser Blog-Eintrag zeigt wie es geht: Enable “display pop-up windows” on new Xiaomi phones. Eine andere Zugangsmöglichkeit: Lange auf das Symbol der App drücken, dann "App-Info" auswählen.

Referenz

Eigenschaften

CanDrawOverlays
Ruft ab, ob die Permission SYSTEM_ALERT_WINDOW erteilt wurde.
CanLaunchFromBackground
Ruft ab, ob die App andere Apps starten darf, während sie selbst im Hintergrund arbeitet.
CurrentLanguage
Liefert die eingestellte Sprache zurück ("de", "en", etc. siehe ISO-639-1-Codes).
IsXiaomi
Ruft ab, ob es ein Xiaomi-Gerät ist.
Manufacturer
Ruft den Namen des Herstellers des Geräts ab.
PermissionDelay
Verzögerung der erneuten Abfrage von CanLaunchFromBackground nach dem schließen das Permissiondialogs (siehe Zusätzliche Berechtigungen ab Android 10 und bei Xiaomi-Geräten). Die Voreinstellung ist 500 ms.
Version
Liefert die Versionsbezeichnung der Extension.
VersionSDK
Liefert die Android SDK Version (API level).

Funktionen

CancelAlarm (RequestCode)
Löscht einen noch nicht ausgelösten Alarm. RequestCode: Eindeutige numerische ID für diesen Alarm.
CheckBackgroundLaunchPermission ()
Prüft, ob die App andere Apps starten kann, währen sie selbst im Hintergrund arbeitet. Falls dies nicht der Fall ist, wird die Berechtigung angefragt.
CreateAlarm (RequestCode, Delay, Type, WakeUp, AlarmIntentObject)
Führt die durch AlarmIntentObject definierte Operation nach einer durch Delay bestimmten Verzögerung aus. RequestCode: Eindeutige numerische ID für diesen Alarm. Delay: Verzögerung in Sekunden. Type: Angabe der Genauigkeit. WakeUp: Weckt das Gerät auf, wenn die Zeit abgelaufen ist.  AlarmIntentObject: legt fest, welche Aktion beim Antippen der Benachrichtigung ausgeführt.

Type erlaubt die Angaben 0..3. Es werden die folgenden Methoden aufgerufen:

  • 0: AlarmManager.set (ab API Level 1) Ab API 19 wird die an diese Methode übergebene Auslösezeit als ungenau behandelt: Der Alarm wird nicht vor dieser Zeit übermittelt, kann jedoch verschoben und einige Zeit später übermittelt werden.
  • 1: AlarmManager.setExact (ab API Level 19) Der Alarm wird so weit wie möglich zur gewünschten Zeit ausgelöst.
  • 2: AlarmManager.setAndAllowWhileIdle (ab API Level 23) Dieser Alarm wird auch dann ausgeführt, wenn sich das System im Leerlaufmodus (doze mode) befindet.
  • 3: AlarmManager.setExactAndAllowWhileIdle (ab API Level 23) Der Alarm wird so weit wie möglich zur gewünschten Zeit ausgelöst, auch dann, wenn sich das Gerät im Leerlaufmodus (doze mode) befindet.

Reicht der aktuelle API-Level nicht aus, wird der Typ angepasst: 10; 20; 310;

Wenn der Wert für Delay kleiner als Null ist, wird die Benachrichtigung nicht angelegt und Screen.ErrorOccurred mit ErrorNumber 17007 ausgelöst.

Wenn das übergebene Objekt im Parameter AlarmIntentObject nicht vom Typ AlarmIntent ist, wird die Benachrichtigung nicht angelegt und Screen.ErrorOccurred mit ErrorNumber 17006 ausgelöst.

CreateAlarmAt (RequestCode, Millis, Type, WakeUp, AlarmIntentObject)
Führt die durch AlarmIntentObject definierte Operation zum durch Millis bestimmten Zeitpunkt aus. RequestCode: Eindeutige numerische ID für diesen Alarm. Millis: der Alarmzeitpunkt in Millisekunden seit dem 1.1.1970. Type: Angabe der Genauigkeit. WakeUp: Weckt das Gerät auf, wenn die Zeit abgelaufen ist. UrsNotificationObjekt: legt die Eigenschaften der zum Alarmzeitpunkt zu erstellenden Benachrichtigung fest. UrsIntentObject: legt fest, welche Aktion beim Antippen der Benachrichtigung ausgeführt.

Type erlaubt die Angaben 0..3. Es werden die folgenden Methoden aufgerufen:

  • 0: AlarmManager.set (ab API Level 1)
    Ab API 19 wird die an diese Methode übergebene Auslösezeit als ungenau behandelt: Der Alarm wird nicht vor dieser Zeit übermittelt, kann jedoch verschoben und einige Zeit später übermittelt werden.
  • 1: AlarmManager.setExact (ab API Level 19)
    Der Alarm wird so weit wie möglich zur gewünschten Zeit ausgelöst.
  • 2: AlarmManager.setAndAllowWhileIdle (ab API Level 23)
    Dieser Alarm wird auch dann ausgeführt, wenn sich das System im Leerlaufmodus (doze mode) befindet.
  • 3: AlarmManager.setExactAndAllowWhileIdle (ab API Level 23)
    Der Alarm wird so weit wie möglich zur gewünschten Zeit ausgelöst, auch dann, wenn sich das Gerät im Leerlaufmodus (doze mode) befindet.

Reicht der aktuelle API-Level nicht aus, wird der Typ angepasst: 10; 20; 310;

Der Wert für Millis kann aus einer Clock-Komponente über die Methode GetMillis gewonnen werden.

Wenn der Wert für Millis kleiner als die aktuelle Systemzeit ist, wird die Benachrichtigung nicht angelegt und Screen.ErrorOccurred mit ErrorNumber 17008 ausgelöst.

Wenn das übergebene Objekt im Parameter AlarmIntentObject nicht vom Typ AlarmIntent ist, wird die Benachrichtigung nicht angelegt und Screen.ErrorOccurred mit ErrorNumber 17006 ausgelöst.

CreateAlarmEx (RequestCode, Delay, Type, WakeUp, AlarmIntentObject)
Führt die durch AlarmIntentObject definierte Operation nach einer durch Delay bestimmten Verzögerung aus. Zurück geliefert wird der Zeitpunkt, zu dem der Alarm ausgelöst wird. RequestCode: Eindeutige numerische ID für diesen Alarm. Delay: Verzögerung in Sekunden. Type: Angabe der Genaugkeit. WakeUp: Weckt das Gerät auf, wenn die Zeit abgelaufen ist. UrsNotificationObjekt: legt die Eigenschaften der zum Alarmzeitpunkt zu erstellenden Benachrichtigung fest. UrsIntentObject: legt fest, welche Aktion beim Antippen der Benachrichtigung ausgeführt.

Es wird der Auslösezeit in Millisekunden seit 1.1.1970 zurück geliefert. Dieser Wert kann z.B. an die Methode MakeInstantFromMillis einer Clock-Komponente zur Erstellung eines lesbaren Datum-Zeit-Format übergeben werden.

Type erlaubt die Angaben 0..3. Es werden die folgenden Methoden aufgerufen:

  • 0: AlarmManager.set (ab API Level 1) Ab API 19 wird die an diese Methode übergebene Auslösezeit als ungenau behandelt: Der Alarm wird nicht vor dieser Zeit übermittelt, kann jedoch verschoben und einige Zeit später übermittelt werden.
  • 1: AlarmManager.setExact (ab API Level 19) Der Alarm wird so weit wie möglich zur gewünschten Zeit ausgelöst.
  • 2: AlarmManager.setAndAllowWhileIdle (ab API Level 23) Dieser Alarm wird auch dann ausgeführt, wenn sich das System im Leerlaufmodus (doze mode) befindet.
  • 3: AlarmManager.setExactAndAllowWhileIdle (ab API Level 23) Der Alarm wird so weit wie möglich zur gewünschten Zeit ausgelöst, auch dann, wenn sich das Gerät im Leerlaufmodus (doze mode) befindet.

Reicht der aktuelle API-Level nicht aus, wird der Typ angepasst: 10; 20; 310;

Wenn der Wert für Delay kleiner als Null ist, wird die Benachrichtigung nicht angelegt und Screen.ErrorOccurred mit ErrorNumber 17007 ausgelöst.

Wenn das übergebene Objekt im Parameter UrsNotificationObject nicht vom Typ UrsNotification ist, wird die Benachrichtigung nicht angelegt und Screen.ErrorOccurred mit ErrorNumber 17005 ausgelöst.

Wenn das übergebene Objekt im Parameter UrsIntentObject nicht vom Typ UrsIntent ist, wird die Benachrichtigung nicht angelegt und Screen.ErrorOccurred mit ErrorNumber 17006 ausgelöst.

OpenMiuiPermissionEditor ()
Öffnet den MIUI-Permission-Editor.

Ereignisse

AfterBackgroundPermssion (Result)
Liefert das Ergebnis von CheckBackgroundLaunchPermission. Zwischen dem Schließen des  Berechtigungsdialog und der Auslösung des Ereignisses gibt es eine Verzögerung von PermissionDelay Millisekunden (see Zusätzliche Berechtigungen ab Android 10 und bei Xiaomi-Geräten).

Referenz AlarmIntent

Hinweis:
Bei den meisten Flags ist mir nicht wirklich klar, was sie genau bewirken. Ich habe mich zwar um eine passende Übersetzung bemüht, bin mir aber nicht sicher on das überall gelungen ist. Im Zweifelsfall bitte die verlinkte Originalreferenz benutzen.

Ab Android 10 muss die Eigenschaft FlagNewTask auf true gesetzt sein.

Es gibt ein Problem beim fortlaufenden Erzeugen von Alarmen mit Intents vom Typ Screen, wenn dies nicht Screen1 ist und anschließend mit control.close application geschlossen werden. Grund sind interne Abläufe in App-Inventor-Programmen. Am besten ruft man über den Alarm Screen1 auf, wertet den Parameter control.get start value aus und ruft von Screen1 über control.open another screen den entsprechenden Screen auf.

Der Aktionstyp (ActionType) bestimmt, welche Aktion mit dem Intent ausgelöst wird:

 Die Spalte S markiert Felder die für den ActionType Screen relevant sind, die Spalte L die für den ActionType Launcher.

Bezeichnung Typ S L Funktion Voreinstellung
ActionType choice
(nur im Designer)
X X Legt den Aktionstyp fest. Mögliche Werte sind Screen oder Launcher. Je nach Aktionstyp werden verschiedene Felder ausgewertet. None
ActivityAction text - X Die auszuführende allgemeine Aktion. -none-
ActivityClass text - X Gibt den Klassenteil der spezifischen Komponente an, die gestartet werden soll.

ActivityPackage und ActivityClass definieren die Activity, die beim Antippen der Benachrichtigung gestartet werden soll.
-none-
ActivityPackage text - X Gibt den Paketnamen der spezifischen Komponente an, die gestartet werden soll.

ActivityPackage und ActivityClass definieren die Activity, die beim Antippen der Benachrichtigung gestartet werden soll.
-none-
DataType text - X Gibt den MIME-Typ an, der an die Activity übergeben werden soll -none-
DataUri text - X Gibt den Daten-URI an, der zum Starten der Activity verwendet wird. -none-
FlagClearTask boolean X X Die gestartete Aktivität wird ein neuer Task im Verlaufsstapel. false
FlagClearTop boolean X X Wenn die zu startende Activity bereits in dem aktuellen Task ausgeführt wird, wird keine neue Instanz dieser Activity gestartet. Stattdessen werden alle anderen darüber liegenden Activitys geschlossen und dieser Intent an die alte Aktivität, jetzt an der Spitze des Activity-Stacks, als neuer Intent übergeben. false
FlagExcludeFromRecent boolean X X Die neue Activity wird nicht in der Liste der kürzlich gestarteten Activitys gespeichert. false
FlagNewTask boolean X X Diese Activity wird zum Beginn eines neuen Task in diesem Verlaufsstapel.
Ab Android 10, muss dieses Flag auf true gesetzt sein.
true
FlagNoAnimation boolean X X Dieses Flag verhindert, dass das System eine Aktivitätsübergangsanimation erzeugt, um zum nächsten Aktivitätsstatus zu gelangen. false
FlagNoHistory boolean X X Die neue Activity wird nicht im Verlaufsstapel gespeichert. Sobald der Benutzer sie verlässt, ist die Activity beendet. false
FlagPreviousIsTop boolean X X Wenn dieser Intent dazu verwendet wird, um eine neue Activity zu starten, wird die aktuelle Activity nicht als oberste Activity gewertet. Die vorherige Activity wird als oberste Activity verwendet, wobei davon ausgegangen wird, dass die aktuelle Activity sofort beendet wird. false
FlagReorderToFront boolean X X Dieses Flag bewirkt, dass die gestartete Activity an die Spitze des Verlaufsstapels verschoben wird, wenn sie bereits ausgeführt wird. false
FlagResetTaskIfNeeded boolean X X Wird diese Activity entweder in einem neuen Task gestartet oder an die Spitze eines vorhandenen Task gebracht, wird sie als Einstieg für den Task gestartet. Dies führt dazu, dass alle Zugehörigkeiten erstellt werden, die erforderlich sind, um diesen Task in den richtigen Zustand zu versetzen (Activity hineinverschieben oder entfernen) oder diesen Task bei Bedarf einfach in seinen Ausgangszustand zurückzusetzen. false
FlagSingleTop boolean X X Wenn gesetzt, wird die Activity nicht gestartet, wenn sie bereits oben im Verlaufsstapel ausgeführt wird. false
FlagTaskOnHome boolean X X Dieses Flag bewirkt, dass ein neu startender Task über der aktuellen Home Activity (falls vorhanden) platziert wird. Das heißt, wenn der Benutzer die Back-Taste drückt, wird er immer wieder zum Home Screen zurückkehren, auch wenn dies nicht die letzte Activity war, die er ausgeführt hat. Dies kann nur in Verbindung mit FLAG_ACTIVITY_NEW_TASK verwendet werden. false
ScreenStartValue text X - Der Startwert, der dem zu öffnenden Screen übergeben werden soll. Abrufbar per Control.getStartValue . -none-
ScreenToOpen text X - Der Name des Screens, der beim Alarm geöffnet werden soll. Siehe auch Hinweis zu Beginn diese Abschnitts. "Screen1"

Beispiel

Das Download-Archiv enthält ein Beispiel-Projekt:

 UrsAlarmTest

Hinweis:

Die Extension funktioniert nicht im Companion. Alarme werden über Broadcast-Nachrichten ausgelöst. Damit eine App auch im geschlossenen Zustand Broadcast-Nachrichten muss die App einen Broadcast-Receiver bereitstellen. Dieser muss im Manifest der App deklariert werden. Letzteres ist beim Companion nicht möglich.

Das Projekt besitzt zwei Schaltflächen:

 Jeweils nach der Erstellung des Alarms wird die App geschlossen. Der Alarm wird also bei nicht geöffneter App ausgeführt.

Android bietet leider keine Möglichkeit zu ermitteln, welche Alarme noch ausstehen. Das Beispiel Notification Alarm Test zeigt, wie man Alarme verwalten kann.

Das Beispiel zur AppLauncher-Extension zeigt, wie die besonderen Berechtigungen bei Android 10 oder Xiaomi-Geräten angefordert werden können.

Werkzeuge

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