Deutsche Version   Deutsche Version


Version Adjustment
1.0 (2021-04-26) Initial version
2.0 (2021-05-15) ScreenToOpen did not work on Kodular when the package name was changed.
2.1 (2021-06-12) - Property FlagNewTask in AlarmIntent was not correctly set. Since Android 10 this flag must be set true to start a new activity from an alarm.
- Default of property FlagNewTask in AlarmIntent was changed to true.
- Parameter WakeUp at methods CreateAlarm... was mot correctly evaluated.
2.2 (2021-07-21)

In the case of longer alarm times when the screen was switched off, the alarm did not reliably wake up the device.

  • The alarm receiver sets a WakeLock in order to have enough time to start the planned activity.
  • The EnableShowOnLockScreen method enables the display on the lock screen.

See section Rules for the activity to be started

2.3 (2022-10-13) Adapted for SDK31 (Android 12):
All PendingIntents get the FLAG_IMMUTABLE flag.
android.permission.SCHEDULE_EXACT_ALARM requested.
Global exception is caught and written to the log.

Motivation

Although the Android documentation strongly recommends working with notifications (see developer.android.com), under certain circumstances it is still necessary for an app to be started at a certain point in time. With this extension, apps can be started at specified times. If you want to generate notifications at time, you have to use the extension UrsAI2Notifier.

Note for users of devices with Android 10  and up:

At the time of the alarm, a class of the extension is started in the background. Since Android 10, an app needs additional permissions (SYSTEM_ALERT_WINDOW) if it wants to start another app while it is running itself in the background (see Restrictions on starting activities from the background, last point). This permission cannot be set by program, but has to be confirmed by the user via a dialog (see Additional permissions since Android 10 and on Xiaomi devices). A possible solution to the problem is presented in the example.

 

In order to start a new activity, the FlagNewTask property in the AlarmIntent must be set to true!

 

Note for users of devices from the manufacturer Xiaomi:

At the time of the alarm, a class of the extension is started in the background. With Xiaomi devices, regardless of the Android version installed, a additional permission is required if an app wants to start another app while it is itself running in the background. This permission cannot be not set by the program, but has to be confirmed by the user via a dialog (see Additional permissions since Android 10 and on Xiaomi devices). The program cannot query whether this permission has already been granted. A possible solution to the problem is presented in the example.

Users of Xiaomi devices with Android 10 and newer must grant both permissions.


Content

Download

Usage

Alarms

Intents

Rules for the activity to be started

Additional permissions since Android 10 and on Xiaomi devices

Android 10

Xiaomi devices

Reference

Properties

Methods

Events

Reference AlarmIntent

Example

Tools

Download

The  UrsAI2Alarm ZIP archive for download. The archive contains the source code, the compiled binary for uploading to the App Inventor and a sample application.

Usage

Note:

The extension does not work in the companion. Alarms are triggered via broadcast messages. In order for an app to receive broadcast messages even when it is closed, the app must provide a broadcast receiver. This receiver must be declared in the app's manifest. This not possible with the Companion.

One possibility would be to patch the companion APK: https://ullisroboterseite.de/android-ai2-faq.html?topic=patchcompanion

Tasks that are to be executed by the operating system are committed via an intent. A intent is an abstract description of an operation to be performed. The operation to be executed at the time of the alarm is specified by such an intent.

The extension contains two blocks:

UrsAI2Alarm: Provides properties and methods that generate alarms.

AlarmIntent: Specifies the operation to be executed when the alarm occurs.

Alarms

The UrsAI2Alarm block can generate and delete alarms. An alarm is uniquely identified by the request code. When creating an alarm, a request code must be specified and can be used to delete an alarm later.

Unfortunately, Android does not offer a way to find out which alarms are still waiting to be triggered. You have to manage this yourself. The Notification Alarm Test example shows how this can be done.

CreateAlarm and CreateAlarmEx generate alarms after a specified delay. The Android AlarmManager executes the stored action even if the app is closed. CreateAlarmAt generates the alarm at a specific point in time.

CancelAlarm cancels an alarm that has not yet been triggered.

Intents

Android uses Intent objects to submit tasks to the system. An Intent contains all information that is necessary to execute the task. The AI2 ActivityStarter, for example, uses Intents internally to start other apps.

An AlarmIntent object that is passed to the CreateAlarm... functions is used to specify which action is to be executed when the alarm is triggered.

This AlarmIntent component is a collection of properties. It has neither functions nor events.

The ActionType specifies which action is triggered with the intent:

Rules for the activity to be started

In order for apps (activities) to reliably wake up the device, the app to be started must be equipped accordingly1). First, the app must have the appropriate permissions. For Xiaomi devices, this must be given by the user in a separate dialog (see following section).

Then the started activity (with App Inventor this is a Screen) must request the display be switched on and the Screen the be displayed on the lock screen. Entering the PIN code must also be switched off too. This can be achieved for AI2 or Kodular apps using the EnableShowOnLockScreen function. In addition, the activity must set a WakeLock, otherwise the device will immediately go back to the lock state.

If an AI2 screen is selected as the target, the following code block is recommended for the Screen.Initialize event:

Additional permissions since Android 10 and on Xiaomi devices

Note: Users of Xiaomi devices with Android 10 and newer must grant both permissions!

Android 10

Since Android 10, an app needs additional permissions (SYSTEM_ALERT_WINDOW) if it wants to start another app while it is running itself in the background (see Restrictions on starting activities from the background, last point). This permission cannot be set by program, but has to be confirmed by the user via a dialog (see Additional permissions since Android 10 and on Xiaomi devices).

The extension provides the CheckBackgroundLaunchPermission method. The method checks whether the installed Android version has an API level of 29 (Android 10) or higher and whether the SYSTEM_ALERT_WINDOW permission has been granted. If it is necessary that this permission is granted, a dialog for granting the permission is opened:

 
German variant   English variant

The result of the permission request is returned via the AfterBackgroundPermssion  event. The new state of the permission is not available immediately after closing the authorization dialog. The event is therefore triggered after a short delay (property PermissionDelay, default 500 ms) after closing the dialog. During this time, the state of the permission is undefined. It is advisable to ensure that no nonsensical data is displayed or problematic entries can be made meanwhile. It is best to put all the concerned screen elements into aVerticalArrangement. This can be temporarily switched invisible or, for example, deactivated via the EnableArrangement method of the UrsAI2ComponentGroup extension ( see example below).

For further detailed handling of this permission you can use:

Xiaomi devices

With Xiaomi devices, regardless of the Android version installed, a additional permission is required if an app wants to start another app while it is itself running in the background. This permission cannot be not set by the program, but has to be confirmed by the user via a dialog (see Additional permissions since Android 10 and on Xiaomi devices). The program cannot query whether this permission has already been granted.

The following elements are available to handle this problem:

The Xiaomi permission editor:

 
German variant   English variant

The sample project shows one way how these permissions can be handled.

You can also get the permision via the Settings app. This blog entry shows how to do it: Enable “display pop-up windows” on new Xiaomi phones. Another access option: Long press the app icon, then select "App-Info".

Reference

Properties

CanDrawOverlays
Returns whether permission SYSTEM_ALERT_WINDOW is granted.
CanLaunchFromBackground
Returns whether you are permitted to lauch apps while in background.
CurrentLanguage
Returns the current language, e.g. 'de' or 'en'." (see List of ISO 639-1 codes).
IsXiaomi
Returns whether this is a Xiaomi device.
Manufacturer
Returns the manufacturer name of the device.
PermissionDelay
Delay for internal request of CanLaunchFromBackground after permission dialog was closed (see Additional permissions since Android 10 and on Xiaomi devices). The default is 500 ms.
Version
Returns the extension's version name.
VersionSDK
Returns running Android SDK version (API level).

Methods

CancelAlarm (RequestCode)
Cancels an alarm that has not yet been triggered. RequestCode: Unique numeric ID for this alarm.
CheckBackgroundLaunchPermission ()
Checks if lauching apps from the background is permitted and if not, asks for the permission.
CreateAlarm (RequestCode, Delay, Type, WakeUp, AlarmIntentObject)
Executes the operation defined by AlarmIntentObject after a delay specified by Delay. RequestCode: Unique numeric ID for this alarm. Delay: Delay in seconds. Type: indication of the accuracy. WakeUp: Wakes up the device when the time has expired. UrsNotificationObject: defines the properties of the notification to be created at the time of the alarm. UrsIntentObject: defines what action is executed when the notification is tapped.

Type has the values 0..3. These methods are called depending on Type:

  • 0: AlarmManager.set (since API Level 1)
    As of API 19, the trigger time passed to this method is treated as imprecise: the alarm is not sent before this time, but can be postponed and sent some time later.
  • 1: AlarmManager.setExact (since API Level 19) The alarm is triggered as close as possible to the desired time.
  • 2: AlarmManager.setAndAllowWhileIdle (ab API Level 23) This alarm is also triggered when the system is in doze mode.
  • 3: AlarmManager.setExactAndAllowWhileIdle (ab API Level 23)
    The alarm is triggered as close as possible to the desired time and is also triggered when the system is in doze mode.

If the current API level is not sufficient, the type is adapted : 10; 20; 310;

If the value for Delay is less than zero, the notification is not created and Screen.ErrorOccurred is triggered with ErrorNumber 17007.

If the object specified in the AlarmIntentObject parameter is not of the AlarmIntent type, the notification is not created and Screen.ErrorOccurred is triggered with ErrorNumber 17006.

CreateAlarmAt (RequestCode, Millis, Type, WakeUp, AlarmIntentObject)
Executes the operation defined by AlarmIntentObject at the time specified by Millis. RequestCode: Unique numeric ID for this alarm. Millis: the time of the alarm in milliseconds since 1.1.1970. Type: indication of the accuracy. WakeUp: Wakes up the device when the time has expired. UrsNotificationObject: defines the properties of the notification to be created at the time of the alarm. UrsIntentObject: defines what action is executed when the notification is tapped.

Type has the values 0..3. These methods are called depending on Type:

  • 0: AlarmManager.set (since API Level 1)
    As of API 19, the trigger time passed to this method is treated as imprecise: the alarm is not sent before this time, but can be postponed and sent some time later.
  • 1: AlarmManager.setExact (since API Level 19) The alarm is triggered as close as possible to the desired time.
  • 2: AlarmManager.setAndAllowWhileIdle (ab API Level 23) This alarm is also triggered when the system is in doze mode.
  • 3: AlarmManager.setExactAndAllowWhileIdle (ab API Level 23)
    The alarm is triggered as close as possible to the desired time and is also triggered when the system is in doze mode.

If the current API level is not sufficient, the type is adapted : 10; 20; 310;

The value for Millis can be obtained from a clock component using the GetMillis method.

If the value for Millis is less than the current system time, the notification is not created and Screen.ErrorOccurred is triggered with ErrorNumber 17008.

If the object specified in the AlarmIntentObject parameter is not of the AlarmIntent type, the notification is not created and Screen.ErrorOccurred is triggered with ErrorNumber 17006.

CreateAlarmEx (RequestCode, Delay, Type, WakeUp, AlarmIntentObject)
Executes the operation defined by AlarmIntentObject after a delay specified by Delay. The time at which the notification is generated is returned. RequestCode: Unique numeric ID for this alarm. Delay: Delay in seconds. Type: indication of the accuracy. WakeUp: Wakes up the device when the time has expired. UrsNotificationObject: defines the properties of the notification to be created at the time of the alarm. UrsIntentObject: defines what action is executed when the notification is tapped.

The return value is the alarm time in milliseconds since 1.1.1970. This value can e.g. be transferred to the MakeInstantFromMillis method of a Clock component to create a readable date-time format.

Type has the values 0..3. These methods are called depending on Type:

  • 0: AlarmManager.set (since API Level 1)
    As of API 19, the trigger time passed to this method is treated as imprecise: the alarm is not sent before this time, but can be postponed and sent some time later.
  • 1: AlarmManager.setExact (since API Level 19) The alarm is triggered as close as possible to the desired time.
  • 2: AlarmManager.setAndAllowWhileIdle (ab API Level 23) This alarm is also triggered when the system is in doze mode.
  • 3: AlarmManager.setExactAndAllowWhileIdle (ab API Level 23)
    The alarm is triggered as close as possible to the desired time and is also triggered when the system is in doze mode.

If the current API level is not sufficient, the type is adapted : 10; 20; 310;

If the value for Delay is less than zero, the notification is not created and Screen.ErrorOccurred is triggered with ErrorNumber 17007.

If the object specified in the AlarmIntentObject parameter is not of the AlarmIntent type, the notification is not created and Screen.ErrorOccurred is triggered with ErrorNumber 17006.

EnableShowOnLockScreen()
Enables the display on the lock screen without entering the PIN code. This is done by calling the methods Activity.setShowWhenLocked, Activity.setTurnScreenOn and KeyguardManager.requestDismissKeyguard or using adequate alternatives for older Android versions.
See section Rules for the activity to be started
OpenMiuiPermissionEditor ()
Opens the MIUI permission editor.

Events

AfterBackgroundPermssion (Result)
Returns the result of CheckBackgroundLaunchPermission. There is a delay of PermissionDelay milliseconds after the permission dialog is closed (see Additional permissions since Android 10 and on Xiaomi devices).

Reference AlarmIntent

Note:

Since Android 10, the FlagNewTask property must be set to true.

There is a problem with the continuous generation of alarms with intents of the type Screen, if this is not Screen1 and the screen closed with control.close application. The reason is internal processes in App Inventor programs. It is best launch Screen1 via the alarm, evaluate the control.get start value parameter and open the requested screen from Screen1 via control.open another screen.

 The ActionType specifies which action is triggered with the Intent:

The column S marks fields that are relevant for the ActionType Screen, the column L those for the ActionType Launcher.

Name Type S L Functionality Default
ActionType choice
(Designer only)
X X Specifies the type of action. Possible values are Screen or Launcher. Different fields are evaluated depending on the ActionType. None
ActivityAction text - X Specifies the action that will be used to start the Activity. -none-
ActivityClass text - X Specifies the class part of the specific component that will be started.
ActivityPackage and ActivityClass define the Activity to be started when the notification is tapped.
-none-
ActivityPackage text - X Specifies the class part of the specific component that will be started.
ActivityPackage and ActivityClass define the Activity to be started when the notification is tapped.
-none-
DataType text - X Specifies the MIME type to pass to the Activity. -none-
DataUri text - X Specifies the data URI that will be used to start the activity. -none-
FlagClearTask boolean X X This flag will cause any existing task that would be associated with the activity to be cleared before the activity is started. false
FlagClearTop boolean X X If set, and the Activity being launched is already running in the current Task, then instead of launching a new instance of that Activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old Activity as a new Intent. false
FlagExcludeFromRecent boolean X X If set, the new Activity is not kept in the list of recently launched activities. false
FlagNewTask boolean X X If set, this Activity will become the start of a new Task on this history stack.
Since Android 10 this flag must be set to true.
false
FlagNoAnimation boolean X X This flag will prevent the system from applying an Activity transition animation to go to the next activity state. false
FlagNoHistory boolean X X If set, the new Activity is not kept in the history stack. As soon as the user navigates away from it, the activity is finished. false
FlagPreviousIsTop boolean X X If set and this Intent is being used to launch a new Activity from an existing one, the current Activity will not be counted as the top Activity for deciding whether the new Intent should be delivered to the top instead of starting a new one. The previous Activity will be used as the top, with the assumption being that the current Activity will finish itself immediately false
FlagReorderToFront boolean X X This flag will cause the launched Activity to be brought to the front of its task's history stack if it is already running. false
FlagResetTaskIfNeeded boolean X X If set, and this Activity is either being started in a new Task or bringing to the top an existing Task, then it will be launched as the front door of the Task. This will result in the application of any affinities needed to have that Task in the proper state (either moving activities to or from it), or simply resetting that task to its initial state if needed. false
FlagSingleTop boolean X X If set, the Activity will not be launched if it is already running at the top of the history stack. false
FlagTaskOnHome boolean X X This flag will cause a newly launching task to be placed on top of the current home activity task (if there is one). That is, pressing back from the task will always return the user to home even if that was not the last activity they saw. This can only be used in conjunction with FLAG_ACTIVITY_NEW_TASK. false
ScreenStartValue text X - The start value to be transferred to the Screen to be opened. Available via Control.getStartValue . -none-
ScreenToOpen text X - The name of the Screen to open when you tap the notification.
See note at the beginning of this section.
"Screen1"

Example

The download archive contains a sample project:

 UrsAlarmTest

Note:

The extension does not work in the companion. Alarms are triggered via broadcast messages. In order for an app to send broadcast messages even when it is closed, the app must provide a broadcast receiver. This receiver must be declared in the app's manifest. This not possible with the Companion.

The screen has two buttons:

The app is closed each time after the alarm is generated. Therefore the alarm is executed when the app is not open.

Unfortunately, Android does not offer a way to determine which alarms are still pending. The Notification Alarm Test example shows how alarms can be managed.

The example for the AppLauncher extension shows how the special authorizations can be requested on Android 10 or Xiaomi devices.

Tools

For developing own extensions I gathered some tips: AI2 FAQ: Develop Extensions.