German version   German version


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 ).

Motivation

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 .


Table of contents

Download

Test results

WakeLock

WifiLock

Battery optimization

Foreground service

Usage

Request WakeLock

Multiple WakeLocks

Notification / Notification Channels

NotificationChannel

Notification

Notification actions (Intent)

Battery optimization

Request WiFi Lock

Alternatives

Implementation details for debugging

Reference

Properties

Functions

Events

Error codes

Example

Tools

Download

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.

Test results

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

WakeLock

In principle, there are three use cases:

  1. At a certain point in time (also periodically) certain actions should run, e.g. measured values ​​should be recorded and saved.
  2. The app should react to external events, e.g. pay attention to an incoming MQTT message.
  3. The display should not dim, e.g. when a recipe is displayed.

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).

WifiLock

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

Battery optimization usually works in the following way:

When should you deactivate battery optimization?

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.

Foreground-Service

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.

Usage

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.

Request WakeLock

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.

Multiple WakeLocks

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.

Notification / Notification Channels

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.

NotificationChannel

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.

Notification

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)).

Modifying the current notification

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.

Notification actions (Intent)

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.

Battery optimization

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.

Request WiFi-Lock

A WiFi-Lock can be requested with the AquireWifiLock function and released with the ReleaseWifiLock function.

Alternatives

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%

Implementation details for debugging

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).

Reference

Properties

AcquireCausesWakeup
Turn the screen on when the wake lock is acquired.
ChannelDescription
Description of the notification channel that is visible to the user (NotificationChanel). This property can be changed later.
ChannelImportance
Defines the significance (Importance) of the channel. The default setting is NotificationManager.IMPORTANCE_LOW.
ChannelName
Name of the notification channel visible to the user (NotificationChanel). This property can be changed later. Default value is URS KeepAwake.
An empty name is ignored.
CurrentNotificationIcon
The small icon that represents this notification in the status bar and in the Contents view. You can specify a system icon (System Notification Icons) or the name of an asset file. Changing this property will affect the notification currently displayed.
CurrentNotificationText
The text of the notification currently displayed. If no notification is currently displayed, an empty text will be returned. Changing this property will affect the notification currently displayed.
CurrentNotificationTitle
The title of the notification currently displayed. If no notification is currently displayed, an empty text will be returned. Changing this property will affect the notification currently displayed.
IsIgnoringBatteryOptimizations
Indicates whether the app is on the whitelist.
Since SDK version 23 (Marshmallow 6.0.1). Previous versions return false.
IsRunningInCompanion
True if the app is running in the companion.
IsWakeLockActive
true, if a WakeLock is active (WakeLockType != 0).
NotificationIcon
Name of the system icon for the notification. The options are listed on the System Notification Icons page. The icon of the currently displayed notification can be changed using the CurrentNotificationIcon method.

This property does not affect an existing notification.

This information is only relevant if the notification is generated by this extension, not if an UrsNotification object is used (see AquirePartialWakeLock, AquirePartialWakeLockFromChannel and the Notification section).
NotificationIconAsset
Name of an uploaded file that contains the icon to be displayed. A size of 96x96 pixels² is recommended for the icon. This specification has priority over the NotificationIcon property.

This property does not affect an existing notification. See CurrentNotificationIcon.

This information is only relevant if the notification is generated by this extension, not if an UrsNotification object is used (see AquirePartialWakeLock, AquirePartialWakeLockFromChannel and the Notification section).
NotificationText
The text that the notification should be given when it is created by this extension. This property does not affect an existing notification. See CurrentNotificationText.

This information is only relevant if the notification is generated by this extension, not if an UrsNotification object is used (see AquirePartialWakeLock, AquirePartialWakeLockFromChannel and the Notification section).
NotificationTitle
The text that the notification should be given when it is created by this extension. This property does not affect an existing notification. See CurrentNotificationTitle.

This information is only relevant if the notification is generated by this extension, not if an UrsNotification object is used (see AquirePartialWakeLock, AquirePartialWakeLockFromChannel and the Notification section).
OnAfterRelease
When this WakeLock is released, poke the user activity timer so the screen stays on for a little longer.
ScreenToOpen
Action that is triggered when the Notification is clicked:
- empty: no action
- name of a Screen o the app (eg "Screen1"): The screen is opened.
- Full name of an Activity (PackageName + ClassName): Start of the Activity.
If the activity to be started cannot be found, no action is stored and the Screen.ErrorOccurred event is triggered (see below).

This information is only relevant if the notification is generated by this extension, not if an UrsNotification object is used (see AquirePartialWakeLock, AquirePartialWakeLockFromChannel and the Notification section).
Startvalue
AI2 start value, if ScreenToOpen contains a Screen name.

This information is only relevant if the notification is generated by this extension, not if an UrsNotification object is used (see AquirePartialWakeLock, AquirePartialWakeLockFromChannel and the Notification section).
Version
Version of the extension.
VersionSDK
Gets the running Android SDK version.
WakeLockType
Returns the type of the currently set WakeLocks: 0: no WakeLock active, 1: PARTIAL_WAKE_LOCK, 2: SCREEN_DIM_WAKE_LOCK, 3: SCREEN_BRIGHT_WAKE_LOCK, 4: FULL_WAKE_LOCK

Functions

AquireFullWakeLock()
Requests a FULL_WAKE_LOCK lock. It ensures that the CPU remains in operation and that the screen and the keyboard backlight are on at full brightness and cannot be switched off by the system.

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).

AquirePartialWakeLock ()
Requests a PARTIAL_WAKE_LOCK. The lock ensures that the CPU remains operational. The screen can be turned off by the user or the system.  A Notification notification and NotificationChanel for this block is generated by the extension. This is determined by the properties ChannelName, ChannelDescription, NotificationTitle, NotificationText and NotificationIcon. See also section Notification / Notification Channels. As a PARTIAL_WAKE_LOCK is ineffective without a ForegroundService, a ForegroundService is automatically started when the WakeLock is created.

If a WakeLock has already been set, it is released first.
AquirePartialWakeLockEx(UrsChannelObject, UrsNotificationObject, UrsIntentObject))
Requests a PARTIAL_WAKE_LOCK. The lock ensures that the CPU remains operational. The screen can be turned off by the user or the system. A mandatory Notification for this lock and the associated notification channel are defined by the transferred UrsChannel object and the UrsNotification object. See also section Notification / Notification Channels. As a PARTIAL_WAKE_LOCK is ineffective without a ForegroundService, a ForegroundService is automatically started when the WakeLock is created.

If a WakeLock has already been set, it is released first.
AquirePartialWakeLockFromChannel(UrsChannelObject)
Requests a PARTIAL_WAKE_LOCK. The lock ensures that the CPU remains operational. The screen can be turned off by the user or the system. A mandatory Notification for this lock is generated by the extension. The NotificationTitle, NotificationText and NotificationIcon properties are decisive for this. The associated NotificationChanel is defined by the UrsChannel object passed. See also section Notification / Notification Channels. As a PARTIAL_WAKE_LOCK is ineffective without a ForegroundService, a ForegroundService is automatically started when the WakeLock is created.

If a WakeLock has already been set, it is released first.
AquirePartialWakeLockFromNotification(UrsNotificationObject, UrsIntentObject)
Requests a PARTIAL_WAKE_LOCK. The lock ensures that the CPU remains operational. The screen can be turned off by the user or the system. A Notification obliging this lock is defined by the transferred UrsNotification object. The associated NotificationChanel is generated by the extension. The properties ChannelName, ChannelDescriptionare decisive for this. See also section Notification / Notification Channels. As a PARTIAL_WAKE_LOCK is ineffective without a ForegroundService, a ForegroundService is automatically started when the WakeLock is created.

If a WakeLock has already been set, it is released first.
AquAquireScreenBrightWakeLock ()
Requests aSCREEN_BRIGHT_WAKE_LOCK lock. It ensures that the CPU remains in operation. The screen cannot be switched off by the system.
AquireScreenDimWakeLock ()
Requests a SCREEN_DIM_WAKE_LOCK lock. It ensures that the CPU remains in operation. The screen cannot be switched off by the system, but can be dimmed.
AquireWifiLock ()
Sets a WifiLock. Ensures that the WiFi is not switched off.
DeleteChannel ()
Deletes an existing channel that was created with this extension.
EnableShowOnLockScreen ()
Ensures that the window is displayed on the lock screen without entering the PIN. Should be called in the Screen.Initialize event.
OpenBatteryOptimizationSettings ()
Opens a dialog that can be used to manually maintain the whitelist.
Since SDK version 23 (Marshmallow 6.0.1). Has no function in previous versions (see Android documentation: Optimize for Doze and App Standby).
ReleaseWakeLock ()
Deletes an active WakeLock. If no WakeLock is active, this method will have no effect. Multiple calls to this function are not critical.
ReleaseWifiLock ()
Releases the WifiLock. Multiple calls to this function are not critical.

Ereignisse/h2>
onResume ()
The screen with the instance of the extension comes to the foreground. See Understand the Activity Lifecycle

Fehler-Codes

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.

Example

Test-App

A small example application shows how to use the extension (see Download).


The example sends the current time every 10 seconds via UDP. This allows you to check if the application is active on an external device, even if the screen is dark. The buttons start and stop the service. The current status of the service and the start value from which the screen was opened are also displayed.

Screenshot of the app.
Screenshot of the notification.

UDP-Receiver

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.

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.

tools

I have put together some tips for creating your own extensions: AI2 FAQ: Developing extensions .