Version | Adjustments |
---|---|
1.0 (2024-10-28) | Initial Version |
1.1 (2024-11-03) | Internal adjustments |
Notice:
The lifespan of the device battery will be significantly reduced by using this extension. Do not set WakeLocks if you do not really need them, use them as rarely as possible and release them as soon as possible.
If actions are to be performed only occasionally, it is not necessary for the CPU to be constantly active. Instead, an alarm can be used (see UrsAI2Alarm ).
For some projects it is necessary to prevent the associated app from being deactivated by the operating system. A typical example would be that sensor data should be sent regularly to an MQTT broker.
With version 6.0 ( Marshmallow), Android introduced Doze mode to optimize battery life. This function gradually turns everything off (display, CPU, WiFi, etc.) when no app is being used. With the extension described here, you can ensure that the CPU is not turned off and the app remains active for a long period of time.
A lot of useful background information can be found in the ZEBRA Developer Portal: Keeping your Android application running when the device wants to sleep .
The UrsAI2KeepAwake ZIP archive is available for download. The archive contains the source code, the compiled binary for uploading to App Inventor and a sample application.
Note: The extension does not work in the Companion. The WAKE_LOCK permission is missing there. You may be able to work around it by doing this: Patching the AI2 Companion - additional permissions .
It is not guaranteed that the latest versions of the extensions are used in all examples. When trying out the examples, you should therefore download the latest version if necessary.
The test program was tested on several devices:
Device | Result |
---|---|
Smartphone Samsung A02s, Android 12 | Works as intended |
Tablet Yestel T13_EEA, Android 13 | Works as intended |
Smartphone ZTE Blade A73, Android 13 | Works as intended |
Smartphone Redmi 5 Plus, Android 8.1 | Works as intended |
In principle, there are three use cases:
Android offers the following solutions for these cases:
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).
Android has changed its power management
policy several times. In addition, the various device manufacturers implement these functions differently in some cases.
It is therefore essential to test whether the information provided here applies to your own project. The behavior of
the WakeLocks described above has been tested with various devices (see
Test results).
A Wakelock does not protect against the network connection being cut after a certain time. There is the WifiLock for this purpose. It enables an application to keep the WiFi connection active. Normally, the WiFi hardware is switched off if the user has not used the device for a longer period of time. If a WifiLock is set, the hardware remains switched on until the lock is removed.
Battery optimization usually works in the following way:
Although battery optimization is beneficial in most cases, it can sometimes lead to problems with certain apps. If an app is not working properly, it can be helpful to (temporarily) deactivate battery optimization for this app.
Services are used to execute longer-lasting functions in the background. This keeps the app remaing reactive. The special feature of a ForegroundService is the display of a Notification. Hence the name Foreground. The displayed notification informs the user about the status of the background activity and gives the user the option of influencing the background activity.
A PARTIAL_WAKE_LOCK prevents the device from switching to standby mode when inactive to conserve battery power. According to Android guidelines, this must not happen without the user being informed. Therefore, a ForegroundService must be set up in addition to WakeLock. Its visible notification shows the user that the app is still active and consuming power.
In this extension, the ForegroundService has no special function. The sole purpose of this service is to activate the WakeLock and inform the user that battery optimization is deactivated and the device will not switch to standby mode.
The ForegroundService is only necessary when using a PARTIAL-WAKE-LOCK. With the other WakeLock types, the user can recognize the missing switch-off function by the fact that the screen is not switched off.
Note:
Services must be declared in the manifest file. This declaration is missing in the Companion (App Inventor and also Kodular). UrsAI2KeepAwake therefore does not work in the Companion.
There are different methods for setting the various locks. AquireFullWakeLock, AquireScreenBrightWakeLock and AquireScreenDimWakeLock acquire the WakeLock designated in the name. When setting the PARTIAL_WAKE_LOCK lock, the notification associated with the ForegroundService must be taken into account:
Only one WakeLock can be requested per instance of the extension. If a second is requested, any lock already in use will be cleared first.
The AcquireCausesWakeup, OnAfterRelease and EnableShowOnLockScreen properties affect the behaviour of the application when a lock is set or cleared.
A WakeLock, of any type, is released using the ReleaseWakeLock function.
The IsWakeLockActive property can be used to query whether a WakeLock lock has been set up. The WakeLockType property provides information about the type of lock that is currently active.
In rare cases, if a FULL_WAKE_LOCK, SCREEN_BRIGHT_WAKE_LOCK or FULL_WAKE_LOCK lock is set, it may be necessary for the CPU to continue running even if the user wants to put the device into standby mode, i.e. turn off the screen with the power button. Unfortunately, it is not possible to simply detect the shutdown process and it is not possible to pass tasks to the ForegroundService in App Inventor.
In this case it makes sense to use two instances of the extension and set a FULL_WAKE_LOCK lock on one and a PARTIAL_WAKE_LOCK lock on the other. Note that the extension can only install a single shared foreground service for all instances, even across multiple screens. A PARTIAL_WAKE_LOCK can therefore only be requested by one instance at a time! Requesting a PARTIAL_WAKE_LOCK when one is already active will result in an error.
In newer versions of Android, a notification must be assigned to a NotificationChannel. When the ForegroundService is started, the extension creates a simple notification and a notification channel if required.
When using the AquirePartialWakeLock or AquirePartialWakeLockFromNotification functions, a notification channel is created by the extension. The properties of the channel visible to the user are defined by the ChannelName and ChannelDescription properties. The channel is created for the first time when one of these two functions is called.
There is no separate function for updating the channel data. A change to the properties is immediately reflected in the channel. Both properties (ChannelName and ChannelDescription) are also available in the designer. This means that this data is checked and updated every time the application is started1). So if the ChannelName or ChannelDescription needs to be changed, it is sufficient to adjust the data in the designer and recompile the app. Once the application has been updated on the device, the channel details are automatically updated the next time the application is launched. ChannelImportance defines, among other things, the conditions under which a notification is displayed (see Importance, IMPORTANCE_DEFAULT and following).
If you no longer want the application to handle notifications via the internally created channel, you can delete it using the DeleteChannel function.
The ID of the internally created channel (ChannelId) is the constant KEEPAWAKE.
1) When the application is started, the instances of the extension are initialised. This also means that the information entered in the designer is transferred to the instances, i.e. the property functions are called. This triggers the update of the channel data (see also Sequence of events when starting the application).
If the simple options of the extension are not sufficient to define the notification properties, the UrsAI2Notifier extension can also be integrated. The UrsAI2NotificationChannel extension provides advanced options for designing notification channels. Details can be found in the documentation of this extension. The channel data is then managed using the properties and functions of the UrsAI2NotificationChannel extension. The AquirePartialWakeLockEx and AquirePartialWakeLockFromChannel functions allow the channel to be specified via an UrsAI2NotificationChannel object.
Note:
The way in which notifications are displayed depends very much on the implementation of this feature by the device manufacturer. For example, on my TE Blade A73 running Android 13, it was not possible to set or change the icon. The app launcher icon was always displayed.
When a PARTIAL_WAKE_LOCK lock is requested, a notification visible to the user must be generated. When using the AquirePartialWakeLock or AquirePartialWakeLockFromChannel functions, a simple notification is generated by this extension. The NotificationTitle, NotificationText and NotificationIcon or NotificationIconAsset properties define the appearance of this notification.
There are two ways to define the icon for the notification to be created. The NotificationIconAsset property can be used to integrate an uploaded image file (Media section in App Inventor). Alternatively, you can use one of the system icons. To do this, set the NotificationIcon property to the name of the system icon resource. A list of icons can be found here. The NotificationIconAsset property overrules the NotificationIcon property.
Changing these properties has no effect on an already active notification. They only serve as specifications for the creation of a new notification by this extension, i.e. when a new request for a corresponding WakeLock lock is made (see also below: Modifying the current notification).
The UrsAI2Notifier extension can be integrated if the simple options of the extension are not sufficient to define the notification properties. The UrsNotification and UrsIntent extensions provide advanced options for designing notifications and associated actions. Details can be found in the documentation of these extensions. The notification data is then managed using the properties and functions of the UrsNotification extension.
The AquirePartialWakeLockEx and AquirePartialWakeLockFromNotification methods accept an instance of the UrsNotifiaction and UrsIntent extensions respectively to define the notification properties and the actions to be performed. All functionalities can be used (BigPicture, LargeIcon, AddActionButton, Create (for modification), etc.). The notification properties are then managed by the objects passed.
You can mess up the backstack with notifications. This can cause problems with flow control in App Inventor (see About the BackStack (Activity Stack)).
For a notification that is already actively displayed, whether generated internally or defined by an UrsNotifiaction object, the properties title, text and icon can be read and modified using the properties CurrentNotificationTitle, CurrentNotificationText and CurrentNotificationIcon. These changes do not affect the NotificationTitle, NotificationTitle and NotificationIcon properties that are used to create a new notification.
Notifications are usually associated with an action that is performed when the user clicks on it. The ScreenToOpen property can be used to specify which action is performed. The options are
Leave the field blank | The notification is not linked to any action. Clicking on the notification has no effect. |
A Screen name of the app | Clicking the notification opens the specified Screen of the
application. If the field value is Screen1,
Screen1 of the application will open. The last state of the Screen
is restored. The Screen.initialize event is not fired. If another Screen of the application is accessed, the Screen.initialize event is fired with a new start value (see Control.get start value and Control.get plain start text). However, if this screen is the currently active screen of the application, the OnResume event will fire. If the specified screen does not exist, no ForegroundService is created and the Screen.ErrorOccured event is fired with error code 17034. |
A fully qualified Activity name | The specified Activity is started. The package name and class name must be specified. |
The battery optimisation setting can be queried using the IsIgnoringBatteryOptimizations property. OpenBatteryOptimizationSettings opens a dialogue which can be used to manually maintain the whitelist. The design of the dialogue and its operation is highly dependent on the Android version and the implementation by the device manufacturer. Not every user will be able to use the battery optimisation dialog successfully.
A WiFi-Lock can be requested with the AquireWifiLock function and released with the ReleaseWifiLock function.
I have read several times that some developers use the Player component to keep the CPU active. The advantage of this is that you don't have to worry about updates for new versions of Android. The disadvantage is that the power consumption of the device remains relatively high and the battery life is significantly reduced. Here are the results for my smartphone:
State | WakeLock | Player | Divergence |
---|---|---|---|
Display bright | 170 mA | 230 mA | +35% |
Display off | 30 mA | 90 mA | +200% |
The extension writes messages to the Android Log, especially in the event of unexpected errors (exceptions). All messages are written with the level DEBUG (Log.d). The LOG_TAG is KEEPAWAKE.
The notifications created by AquirePartialWakeLock have the ID 13477.
The WakeLocks have the tag URS::WakeLock.
The ChannelID of the notification channel created by this extension is KEEPAWAKE (see AquirePartialWakeLock and AquirePartialWakeLockFromNotification).
If the user presses the power button, then the
FULL_WAKE_LOCK will be implicitly released by the system, causing both the screen and the CPU to be
turned off. Contrast with PARTIAL_WAKE_LOCK.
If a
WakeLock has already been set, it is released first.
This function has
been obsolete since API level 17 (Android 4.2, Jelly Bean).
Code | Funktion | Fehlertext | Bedeutung |
---|---|---|---|
17031 | AquirePartialWakeLockEx AquirePartialWakeLockFromChannel |
Invalid value at UrsChannelObject | Incorrect type for parameter UrsChannelObject. |
17032 | AquirePartialWakeLockEx AquirePartialWakeLockFromNotification |
Invalid value at UrsNotificationObject | Incorrect type for parameter UrsNotificationObject. |
17033 | AquirePartialWakeLockEx AquirePartialWakeLockFromNotification |
Invalid value at UrsIntentObject | Incorrect type for parameter UrsIntentObject. |
17034 | AquirePartialWakeLockEx AquirePartialWakeLockFromChannel |
Screen not found | The specified screen does not exist in the app. |
17035 | AquirePartialWakeLock AquirePartialWakeLockEx AquirePartialWakeLockFromChannel AquirePartialWakeLockFromNotification |
Cannot start ForeGroundService | The ForeGroundService could not be started. |
17036 | AquirePartialWakeLock | Unexpected error | |
17037 | AquirePartialWakeLock AquirePartialWakeLockEx AquirePartialWakeLockFromChannel AquirePartialWakeLockFromNotification |
Unexpected error | Error when starting the 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 |
The error codes of the UrsAI2Notifier extension can also occur.
A small example application shows how to use the extension (see Download).
|
|
Screenshot of the app. | |
Screenshot of the notification. |
The example also contains a project file for a simple UDP receiver. Using a second Android device, you can check whether the test app is still active. | |
Screenshot of the simple UDP receiver. |
The example also contains a project file that can be used to test the interaction between KeepAwake , a notification and the app. | |
Screenshot of the created app. | |
Notification generated. |
I have put together some tips for creating your own extensions: AI2 FAQ: Developing extensions .