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.
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. |
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
Rules for the activity to be started
Additional permissions since Android 10 and on Xiaomi devices
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.
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.
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.
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:
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:
Note: Users of Xiaomi devices with Android 10 and newer must grant both permissions!
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:
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".
Type has the values 0..3. These methods are called depending on Type:
If the current API level is not sufficient, the type is adapted : 1→0; 2→0; 3→1→0;
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.
Type has the values 0..3. These methods are called depending on Type:
If the current API level is not sufficient, the type is adapted : 1→0; 2→0; 3→1→0;
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.
Type has the values 0..3. These methods are called depending on Type:
If the current API level is not sufficient, the type is adapted : 1→0; 2→0; 3→1→0;
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.
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" |
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.
For developing own extensions I gathered some tips: AI2 FAQ: Develop Extensions.