Version | Anpassungen |
---|---|
1.0 (2024-10-28) | Initiale Version |
1.1 (2024-11-03) | Interne Anpassungen |
Hinweis:
Die Lebensdauer der Gerätebatterie wird durch die Verwendung dieser Extension erheblich beeinträchtigt. Setzen Sie keine WakeLocks, wenn Sie diese nicht wirklich benötigen, verwenden Sie sie so wenig wie möglich und geben Sie sie so schnell wie möglich wieder frei.
Wenn nur gelegentlich Aktionen ausgeführt werden sollen, ist es nicht erforderlich, dass die CPU ständig aktiv ist. Stattdessen kann ein Alarm verwendet werden (siehe UrsAI2Alarm).
Für manche Projekte ist es notwendig zu verhindern, dass die zugehörige App vom Betriebssystem deaktiviert wird. Ein typisches Beispiel wäre, dass regelmäßig Sensordaten an einen MQTT-Broker gesendet werden sollen.
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.). Mit der hier beschriebenen Extension kann man erreichen, dass die CPU nicht abgeschaltet wird und die App über einen langen Zeitraum aktiv bleibt.
Viele nützliche Hintergrundinformationen findet man im ZEBRA Developer Portal: Keeping your Android application running when the device wants to sleep.
Inhaltsverzeichnis
Benachrichtigung / Benachrichtigungskanäle
Benachrichtigungskanal (NotificationChannel)
Benachrichtigung (Notification)
Benachrichtigungsaktionen (Intent)
Das ZIP-Archiv UrsAI2KeepAwake zum Download. Das Archiv enthält den Quellcode, das kompilierte Binary zum Upload in den App Inventor und eine Beispiel-Anwendung.
Hinweis: Die Extension funktioniert nicht im Companion. Dort fehlt die WAKE_LOCK-Permission. Evtl. kann man sich hierüber behelfen: Patchen des AI2 Companion - zusätzliche Permissions.
Es ist nicht sicher gestellt, dass in allen Beispielen die jeweils aktuellsten Versionen der Extensions verwendet werden. Beim Ausprobieren der Beispiele sollte man daher ggf. die neuesten Version nachladen.
Das Testprogramm wurde auf mehreren Geräten ausprobiert:
Gerät | Ergebnis |
---|---|
Smartphone Samsung A02s, Android 12 | Funktioniert wie vorgesehen |
Tablet Yestel T13_EEA, Android 13 | Funktioniert wie vorgesehen |
Smartphone ZTE Blade A73, Android 13 | Funktioniert wie vorgesehen |
Smartphone Redmi 5 Plus, Android 8.1 | Funktioniert wie vorgesehen |
Im Prinzip geht es um drei Anwendungsfälle:
Android bietet für diese Fälle folgende Lösungsmöglichkeiten:
1) Android hat seine Powermanagement-Policy mehrmals geändert. Außerdem implementieren die verschiedenen Gerätehersteller diese Funktionen z.T. unterschiedlich. Man sollte also unbedingt testen, ob die hier gemachten Angaben für das eigene Projekt zutreffen. Das oben beschriebene Verhalten der WakeLocks wurde mit diversen Geräten getestet (siehe Erfahrungsberichte).
Ein Wakelock schützt nicht davor, dass die Netzwerk-Verbindung nach einer gewissen Zeit gekappt wird. Hierzu gibt es den WifiLock. Er ermöglicht einer Anwendung, die WLAN-Verbindung aktiv zu halten. Normalerweise wird die WiFi-Hardware ausgeschaltet, wenn der Benutzer das Gerät längere Zeit nicht benutzt hat. Wenn ein WifiLock gesetzt wird, bleibt die Hardware eingeschaltet, bis die Sperre aufgehoben wird.
Die Akku-Optimierung funktioniert in der Regel auf folgende Weise:
Obwohl die Akku-Optimierung in den meisten Fällen von Vorteil ist, kann es vorkommen, dass sie bei bestimmten Apps zu Problemen führt. Wenn eine App nicht richtig funktioniert, kann es hilfreich sein, die Akku-Optimierung für diese App (vorübergehend) zu deaktivieren.
Dienste (Services) dienen dazu, länger dauernde Funktionen im Hintergrund auszuführen. Damit bleibt die App reaktiv. Die Besonderheit eines ForegroundService ist die Anzeige einer Benachrichtigung (Notification). Deshalb der Name Foreground. Mit Hilfe der angezeigten Benachrichtigung wird der Benutzer über den Status der Hintergrundaktivität informiert und er hat die Möglichkeit, Einfluss auf die Hintergrundaktivität zu nehmen.
Bei einer PARTIAL_WAKE_LOCK-Sperre wird verhindert, dass das Gerät zur Schonung des Akkus bei Inaktivität in den Stand-By-Modus wechselt. Gemäß der Android-Richtlinien darf so etwas nicht geschehen, ohne dass der Anwender darüber informiert wird. Deshalb muss zusätzlich zum WakeLock ein ForegroundService eingerichtet werden. Dessen sichtbare Benachrichtigung zeigt dem Benutzer an, dass die App weiterhin aktiv ist und Strom verbraucht.
In dieser Extension ist der ForegroundService ohne weitere Funktion. Der einzige Zweck dieses Dienstes besteht darin, den WakeLock zu aktivieren und den Benutzer darüber zu informieren, dass die Batterieoptimierung deaktiviert ist und das Gerät nicht in den Stand-by-Modus wechseln wird.
Der ForegroundService ist nur bei der Verwendung eines PARTIAL-WAKE-LOCK notwendig. Bei den anderen WakeLock-Typen kann der Anwender die fehlende Abschaltfunktion daran erkenn, dass der Bildschirm nicht abgeschaltet wird.
Hinweis:
Services müssen in der Manifest-Datei deklariert werden. Beim Companion (App Inventor und auch Kodular) fehlt dieser Eintrag. UrsAI2KeepAwake funktioniert deshalb nicht im Companion.
Für das Setzen der verschiedenen Sperren gibt es unterschiedliche Methoden. AquireFullWakeLock, AquireScreenBrightWakeLock und AquireScreenDimWakeLock erwerben den im Namen bezeichneten WakeLock. Beim Setzen der PARTIAL_WAKE_LOCK-Sperre muss die zum ForegroundService gehörende Benachrichtigung berücksichtigt werden:
Pro Instanz der Extension kann nur ein WakeLock angefordert werden. Wird ein zweiter angefordert wird vorher ein bereits aktiver Lock gelöscht.
Die Eigenschaften AcquireCausesWakeup, OnAfterRelease und EnableShowOnLockScreen beeinflussen das Verhalten der App beim Setzen bzw. Löschen einer Sperre.
Eine WakeLock-Sperre, gleich welchen Typs, wird über die Funktion ReleaseWakeLock wieder gelöscht.
Ob eine WakeLock-Sperre eingerichtet ist, kann über die Eigenschaft IsWakeLockActive abgefragt werden. Die Eigenschaft WakeLockType gibt Auskunft über den Typ der aktuell aktiven Sperre.
In seltenen Fällen, kann es notwendig sein, dass bei einer gesetzten FULL_WAKE_LOCK-, SCREEN_BRIGHT_WAKE_LOCK oder FULL_WAKE_LOCK-Sperre selbst dann die CPU weiter laufen soll, wenn der Anwender das Gerät in den Stand-By-Modus versetzen will, d.h. den Bildschirm über den Einschaltknopf abschaltet. Leider kann man den Vorgang des Abschaltens nicht einfach detektieren und man kann beim App Inventor auch keine Aufgaben an den ForegroundService übertragen.
In diesem Fall ist es sinnvoll zwei Instanzen der Extension zu benutzen und über die eine eine FULL_WAKE_LOCK- und über die andere eine PARTIAL_WAKE_LOCK-Sperre zu setzen. Zu beachten ist dabei, dass die Extension für alle Instanzen -auch über mehrere Screens hinweg- nur einen einzigen, gemeinsamen ForegroundService installieren kann. Ein PARTIAL_WAKE_LOCK darf deshalb zu einer Zeit nur von einer einzigen Instanz angefordert werden! Wird ein PARTIAL_WAKE_LOCK angefordert, wenn bereits ein solcher aktiv ist, führt das zu einem Fehler.
Einer Benachrichtigung muss in neueren Android-Versionen einem Benachrichtigungskanal (NotificationChannel) zugeordnet sein. Die Extension legt beim Start des ForegroundService eine einfache Benachrichtigung und bei Bedarf auch einen Benachrichtigungskanal an.
Werden die Funktionen AquirePartialWakeLock oder AquirePartialWakeLockFromNotification verwendet, wird durch die Extension ein Benachrichtigungskanal erzeugt. Über die Eigenschaften ChannelName, ChannelDescription werden die für den Anwender sichtbaren Eigenschaften des Kanals festgelegt. Der Kanal wird das erste Mal angelegt, wenn eine der beiden genannten Funktionen aufgerufen wird.
Eine separate Funktion für das Update der Kanal-Daten ist nicht vorgesehen. Eine Änderung der Eigenschaften wird unmittelbar an den Kanal weiter gegeben. Beide Eigenschaften (ChannelName, ChannelDescription) stehen auch im Designer zur Verfügung. Das hat zur Konsequenz, dass die Überprüfung und ggf. ein Update dieser Daten bei jedem Start der App erfolgt1). Sollen also ChannelName oder ChannelDescription geändert werden, reicht es die Daten im Designer anzupassen und die App neu zu kompilieren. Nach der Aktualisierung der App auf dem Gerät wird beim nächsten Start der App die Angaben zum Kanal automatisch angepasst. ChannelImportance legt u.a. fest, unter welchen Bedingungen eine Benachrichtigung angezeigt wird (siehe Importance, IMPORTANCE_DEFAULT ff.).
Wenn die App in Zukunft Benachrichtigungen nicht mehr über den intern angelegten Kanal behandelt werden sollen, besteht die Möglichkeit diesen über dir Funktion DeleteChannel zu löschen.
Die ID des intern angelegten Kanals (ChannelId) ist die Konstante KEEPAWAKE.
1) Beim Start der App werden die Instanzen der Extension initialisiert. Dazu gehört auch, dass die im Designer gemachten Angaben an die Instanzen übergeben werden, d.h. die Eigenschaftsfunktionen aufgerufen werden. Dies löst das Update der Kanaldaten aus (siehe auch Ereignisreihenfolge beim Start der App).
Wenn die einfachen Möglichkeiten der Extension zur Festlegung der Benachrichtigungseigenschaften nicht ausreichen, kann zusätzlich die Extension UrsAI2Notifier eingebunden werden. Über die Extension UrsAI2NotificationChannel stehen erweiterte Möglichkeiten zur Gestaltung der Benachrichtigungskanäle zur Verfügung. Details bietet die Dokumentation zu dieser Extension. Die Verwaltung der Kanaldaten geschieht dann über Eigenschaften und Funktionen der UrsAI2NotificationChannel-Extension. Die Funktionen AquirePartialWakeLockEx und AquirePartialWakeLockFromChannel ermöglichen die Spezifikation des Kanals über ein UrsAI2NotificationChannel-Objekt.
Hinweis:
Die Art und Weise wie Benachrichtigungen angezeigt werden, ist stark von der Implementierung dieser Funktion durch den Gerätehersteller abhängig. Bei meinem TE Blade A73 mit Android 13 war es z.B. nicht möglich, das Icon festzulegen oder zu ändern. Es wurde immer das Launcher-Icon der App angezeigt.
Bei der Anforderung einer PARTIAL_WAKE_LOCK-Sperre muss eine für den Benutzer sichtbare Benachrichtigung (Notification) generiert werden. Bei Verwendung der Funktionen AquirePartialWakeLock oder AquirePartialWakeLockFromChannel wird eine einfache Benachrichtigung von dieser Extension angelegt. Die Eigenschaften NotificationTitle, NotificationText und NotificationIcon bzw. NotificationIconAsset legen das Aussehen dieser Benachrichtigung fest.
Es gibt zwei Möglichkeiten, das Icon für die anzulegende Benachrichtigung festzulegen. Über die Eigenschaft NotificationIconAsset kann eine hochgeladene Grafik-Datei (Rubrik Medien im App Inventor) eingebunden werden. Es gibt aber auch die Möglichkeit eines der System-Icons zu verwenden. Dazu ist der Name der System-Icon-Ressource bei der Eigenschaft NotificationIcon anzugeben. Eine Liste der Icons gibt es hier. Die Eigenschaft NotificationIconAsset hat Vorrang vor NotificationIcon.
Eine Änderung dieser Eigenschaften hat keinen Einfluss auf eine bereits aktive Benachrichtigung. Sie dienen ausschließlich als Vorgaben für die Erzeugung einer neuen Benachrichtigung durch diese Extension, also bei einer erneuten Anforderung einer entsprechenden WakeLock-Sperre (siehe auch unten: Anpassen der aktuellen Benachrichtigung).
Wenn die einfachen Möglichkeiten der Extension zur Festlegung der Benachrichtigungseigenschaften nicht ausreichen, kann zusätzlich die Extension UrsAI2Notifier eingebunden werden. Über die Extensions UrsNotification und UrsIntent stehen erweiterte Möglichkeiten zur Gestaltung der Benachrichtigungen und den zugehörigen Aktionen zur Verfügung. Details bietet die Dokumentation zu dieser Extension. Die Verwaltung der Benachrichtigungsdaten geschieht dann über Eigenschaften und Funktionen der UrsNotification-Extension.
Die Methoden AquirePartialWakeLockEx und AquirePartialWakeLockFromNotification akzeptieren jeweils eine Instanz der UrsNotifiaction- und der UrsIntent-Extension zur Festlegung der Benachrichtigungseigenschaften und der auszuführenden Aktionen. Sämtliche Funktionalitäten können genutzt werden (BigPicture, LargeIcon, AddActionButton, Create (zur Modifikation) etc.). Die Verwaltung der Benachrichtigungseigenschaften erfolgt dann über die übergeben Objekte.
Mit Benachrichtigungen kann man den Backstack durcheinander bringen. Dann funktioniert dann kann es Probleme mit der Flussteuerung im App Inventor geben (siehe hierzu Über den BackStack (Activity Stack)).
Bei einer bereits aktiv angezeigten Benachrichtigung, gleichgültig ob intern generiert oder durch ein UrsNotifiaction-Objekt festgelegt, können die Eigenschaften Titel, Text und Icon über die Eigenschaften CurrentNotificationTitle, CurrentNotificationText und CurrentNotificationIcon ermittelt und auch geändert werden. Auf die Eigenschaften NotificationTitle, NotificationText und NotificationIcon, die zur Anlage einer neuen Benachrichtigung dienen, haben diese Änderungen keinen Einfluss.
Benachrichtigungen sind i.d.R. mit einer Aktion verbunden, die ausgeführt wird, wenn der Benutzer auf sie klickt. Über die Eigenschaft ScreenToOpen kann festgelegt werden, welche Aktion ausgeführt wird. Die Möglichkeiten sind:
Das Feld leer lassen | Die Benachrichtigung wird mit keiner Aktion verbunden. Das Anklicken der Benachrichtigung
ist wirkungslos. |
Ein Screen-Namen der App | Beim Anklicken der Benachrichtigung wird der angegebene Screen der App
geöffnet. Wenn der Eintrag im Feld Screen1 ist, wird der Screen1
der App geöffnet. Der letzte Zustand des Screens wird wieder hergestellt.
Das Screen.Initialize-Ereignis wird nicht ausgelöst. Wird ein anderer Screen der App aufgerufen, wird das Screen.Initialize-Ereignis mit einem neuen Startwert (s. Control.get start value und Control.get plain start text) ausgelöst. Wenn dieser Screen der gerade aktive Screen der App ist, wird jedoch das Ereignis OnResume ausgelöst. Wenn es den angegeben Screen nicht gibt, wird kein ForegroundService angelegt und das Ereignis Screen.ErrorOccured mit dem Fehlercode 17034 ausgelöst. |
Eine voll qualifizierte Activity-Bezeichnung | Die angegebene Activity wird gestartet. Es müssen Package-Name und Klassen-Name angegeben werden. |
Die Einstellung zur Akku-Optimierung kann über die Eigenschaft IsIgnoringBatteryOptimizations abgefragt werden. OpenBatteryOptimizationSettings öffnet einen Dialog, über den die Whitelist manuell gepflegt werden kann. Die Gestaltung des Dialogs und auch dessen Bedienung ist stark abhängig von der Android-Version und von der Implementierung durch den Gerätehersteller. Nicht jeder Anwender wird den Akku-Optimierungsdialog erfolgreich bedienen können.
Ein WiFi-Lock kann über die Funktion AquireWifiLock angefordert und über ReleaseWifiLock wieder gelöscht werden.
Ich habe mehrfach gelesen, dass einige Entwickler die Player-Komponente benutzen, um die CPU aktiv zu halten. Dies hat den Vorteil, dass man sich um ggf. notwendige Updates bei neuen Android-Versionen nicht kümmern muss. Der Nachteil ist, dass der Stromverbrauch des Geräts relativ hoch bleibt und die Lebensdauer einer Akku-Ladung deutlich reduziert. Hier die Messergebnisse für mein Smartphone:
Zustand | WakeLock | Player | Abweichung |
---|---|---|---|
Bildschirm hell | 170 mA | 230 mA | +35% |
Bildschirm aus | 30 mA | 90 mA | +200% |
Die Extension schreibt -insbesondere bei unerwarteten Fehlern (Exceptions)- Nachrichten in das Android-Log. Alle Nachrichten werden mit dem Level DEBUG (Log.d) geschrieben. Das LOG_TAG ist KEEPAWAKE.
Die von AquirePartialWakeLock erstellten Notifications haben die ID 13477.
Die gesetzten WakeLocks haben das Tag URS::WakeLock.
Die Channel-ID des durch diese Extension angelegten Benachrichtigungskanals ist KEEPAWAKE (siehe AquirePartialWakeLock und AquirePartialWakeLockFromNotification).
Code | Funktion | Fehlertext | Bedeutung |
---|---|---|---|
17031 | AquirePartialWakeLockEx AquirePartialWakeLockFromChannel |
Invalid value at UrsChannelObject | Falscher Typ beim Parameter UrsChannelObject. |
17032 | AquirePartialWakeLockEx AquirePartialWakeLockFromNotification |
Invalid value at UrsNotificationObject | Falscher Typ beim Parameter UrsNotificationObject. |
17033 | AquirePartialWakeLockEx AquirePartialWakeLockFromNotification |
Invalid value at UrsIntentObject | Falscher Typ beim Parameter UrsIntentObject. |
17034 | AquirePartialWakeLockEx AquirePartialWakeLockFromChannel |
Screen not found | Der angegebene Screen existiert in der App nicht. |
17035 | AquirePartialWakeLock AquirePartialWakeLockEx AquirePartialWakeLockFromChannel AquirePartialWakeLockFromNotification |
Cannot start ForeGroundService | Der ForeGroundService konnte nicht gestartet werden. |
17036 | AquirePartialWakeLock | Unexpected error | |
17037 | AquirePartialWakeLock AquirePartialWakeLockEx AquirePartialWakeLockFromChannel AquirePartialWakeLockFromNotification |
Unexpected error | Fehler beim Starten des ForeGroundService. |
17038 | AquirePartialWakeLockFromNotification | Unexpected error | |
17039 | AquirePartialWakeLockEx | Unexpected error | |
17040 | CurrentNotificationIcon | Unexpected error | |
17041 | CurrentNotificationText | Unexpected error | |
17042 | CurrentNotificationTitle | Unexpected error | |
17043 | ChannelDescription | Unexpected error | |
17044 | ChannelName | Unexpected error | |
17045 | ReleaseWakeLock | Unexpected error | |
17046 | AquireScreenBrightWakeLock | Unexpected error | |
17047 | AquireScreenDimWakelock | Unexpected error | |
17048 | AquirePartialWakelock | Unexpected error | |
17049 | OpenBatteryOptimizationSettings | Unexpected error | |
17050 | IsIgnoringBattelyOptimizations | Unexpected error | |
17051 | AquireWifilock | Unexpected error | |
17052 | EnableShowOnLockScreen | Unexpected error | |
17053 | AquireFullWakeLock | Unexpected error | |
17054 | AquirePartialWakeLock AquirePartialWakeLockEX AquirePartialWakeLockFromChannel AquirePartialWakeLockFromNotification |
Multiple PartialWakeLock requests. | |
17055 | AquirePartialWakeLockFromChannel | Unexpected error |
Die Fehler-Codes der UrsAI2Notifier-Extension können ebenfalls auftreten.
Eine kleine Beispiel-App zeigt die Verwendung der Extension (s. Download). Das Beispiel sendet in einem 10-Sekunden-Abstand die aktuelle Zeit per UDP. So kann man auch bei verdunkelten Display auf einem externen Gerät kontrollieren, ob die App aktiv ist. Die Schaltflächen starten und stoppen den Service. Angezeigt wird außerdem wie der aktuelle Status des Services ist und mit welchem Startwert der Screen geöffnet wurde. |
|
Screenshot der App. | |
Screenshot der Benachrichtigung. |
Das Bespiel enthält außerdem eine Projekt-Datei für einen einfachen UDP-Receiver. Mit einem zweiten Android-Gerät kann man so kontrollieren, ob die Test-App noch aktiv ist. | |
Screenshot des einfachen UDP-Empfängers. |
Das Bespiel enthält außerdem eine Projekt-Datei mit der man die Interaktion zwischen KeepAwake, einer Notification und der App testen kann. | |
Screenshot der erstellten App. | |
Erzeugte Benachrichtigung. |
Für die Erstellung eigener Extensions habe ich einige Tipps zusammengestellt: AI2 FAQ: Extensions entwickeln.