Version | Modification |
---|---|
1.0 (2020-09-07) | Initial version |
2.0 (2021-03-08) | Completely revised and extended version |
2.1 (2021-03-16) | Some methods declared public so that
KeepAlive can call them. This has no effect
on the functionality. |
2.2 (2021-03-20) | The intent ID was not correctly passed to the OnClick event. |
2.3 (2021-04-05) | The display of the notification property NumberID did not match the internal
default. Note: The examples are not affected and still contain version 2.2 of the extension. |
2.4 (2021-04-16) |
Note: The examples are not affected and still contain version 2.2 of the extension. |
2.5 (2021-04-17) | Under certain conditions, the UrsNotification.Onclick event was triggered only once. |
2.6 (2021-05-12) | Starting an AI2 app (intent type Screen) did not work with Kodular if the package name was changed. |
2.7 (2021-05-15) | Starting an AI2 app (intent type Screen) did not work with Kodular if
the package name was changed. GetActiveNotifications added. |
2.8 (2021-06-13) | Property FlagNewTask at LauncherIntent
was ignored but is needed since Android 10. Default for property FlagNewTask is true. |
2.9.1 (2022-10-13) | Adapted for SDK31 (Android 12): All PendingIntents get the FLAG_IMMUTABLE flag. android.permission.SCHEDULE_EXACT_ALARM angefordert. Global exception is caught and written to the log. |
2.10 (2023-11-23) | Adapted for SDK33 (Android 13): The POST_NOTIFICATIONS permission is required to output notifications Method AreNotificationsEnabled added Method OpenNotificationSettings added Method AreNotificationsPaused added |
2.11 (2024-09-04) | Adapted to Android 14 |
2.12 (2024-10-26) | Bug fixed when using multiple Intent instances. |
2.13 (2024-11-03) | - Event OnNewIntent added - Property IsRunningInCompanion added - PropertyCategories of designer properties modified, so that the extension works with Kodular - Internal restructuring of some code areas |
Note: The presentation of the notification is heavily dependent on the implementation by the device manufacturer.
Notes (experience with my Redmi 5 Plus, Android Oreo 8.1.0)
General app settings for notifications, e.g. whether tones are allowed, depend on the properties with which the first notification channel for the app was created. These general properties can only be changed manually by the user afterwards. Even after uninstalling and reinstalling, I was unable to get rid of the notification channels I had set up.
With my smartphone, it was not possible to activate tones or vibrations by program, although this should be possible by description. I had to enable both manually.
Tones cannot be set individually with this extension. One of the reasons for this is that the support of ContentProviders by App Inventor is not yet sufficient. However, inspection of the NotficationChannel object showed that the settings are correct. Obviously there are other settings on the device that prevent the vibration.
The UrsAI2Notifier ZIP archive for download. The archive contains the source code, the compiled binary for uploading to the App Inventor and some sample applications.
It is not guaranteed that the latest versions of the extensions are used in all examples. When trying out the examples, you should therefore reload the latest version if necessary.
An overview of the notifications can be found in the Android documentation: Notifications Overview.
Notifications are displayed in a separate window (notification panel), separate of the app. They can be created and deleted. There are no special functions to modify them. Notifications have a unique ID (NumberID). If a second notification is created with the same ID before the previous one has been deleted, the existing one will be updated.
Android does not have a method for getting active notifications. If necessary, the program itself must keep track
of which notifications it has created.
Notifications that can be generated with this extension have the following
structure (it is not necessary to display all elements):
All text elements can be formatted with HTML tags. Which HTML tags can be used varies depending on the implementation of the Android system. There are hints at Mark Murphy's Technical Stuff or Daniel Lew's Coding Thoughts.
With API level 26 (version Oreo 8.0), Android introduced the concept of notification channels (NotificationChannel, also known as notification categories on some devices). All notifications must be assigned a channel.
The notification concept is quite complex. Android allows settings to be made on the device level as well as on the channel level and with the notifications themselves.
Many properties of the notifications, e.g. the importance or the vibration pattern, are set at the channel level. These properties are defined by the app when the channel is created and cannot be changed afterwards. The user has full access to most of the channel attributes and can modify them at will. The modifications made by the user should not be overwritten. Therefore, settings cannot be changed later by the program after creating them. Even if a channel is deleted and then created again, it is created with the last available settings. "Erasing" is practically just hiding. Only the properties Name and Description of a channel can be changed later. Eliminating spelling mistakes would otherwise be impossible.
If you want to change properties, a new channel (new channel ID) must be used. The existing channel could be hidden with UrsAI2NotificationChannel.HideChannel when launching the app.
So you should think carefully about which properties are assigned to a channel.
Android uses Intent objects to send orders to the system. An Intent contains all information that is necessary to execute the designated action. The AI2 ActivityStarter, for example, uses Intents internally to start other apps.
Alarms are actions that are triggered at a specific time (alarm time). They are linked to an
Intent that specifies the action to be executed at the time of the alarm.
An alarm can be created and deleted. There are no special functions to modify it. An alarm has a unique ID (RequestCode). If a second alarm is created with the same ID before the previous one was triggered, the existing one will be updated.
Android does not have a method for getting active alarms. If necessary, the program itself must keep track of which alarms it has created.
Android manages the successively started activities in a stack. In App Inventor, an Activity is either a Screen or another app that is called up via the ActivityStarter component, for example.
The Top Activity is the Screen that is currently displayed on the display of the Android device. The Base Activity is the Screen with which the app was started, i.e. Screen1.
Each time a new Screen is opened via the Contol.open another screen or Contol.open another screen with start; instruction, a new Activity is created and becomes the new Top Activity. If the user presses the Back button (hence the name BackStack) or one of the instructions Contol.close screen, Contol.close screen with plain text or Contol.close screen with value is executed, the Top Activity is removed from the stack and destroyed. The Activity below it becomes the new Top Activity and is displayed on the screen.
The activities in the stack are normally independent of each other. An Activity does not know whether and which activities are above or below it in the stack. As a rule, it also does not know that another activity has been closed. Only via some events it finds out whether it is currently being displayed or entries can be made (see Activity Lifecycle).
This is different in the App Inventor. There is the Screen.OtherScreenClosed event, which tells a Screen that the previously opened Screen has been closed. It works like this:
You can start a new Activity in order to get a service from it, e.g. to take a camera picture. Android provides the startActivityForResult function for this purpose. The result returned by the started Activity is communicated by the operating system via the onActivityResult callback function. Calling this function also indicates that the newly started Activity has ended.
App Inventor always uses this function to create a new Screen and the callback function to trigger the Screen.Screen.OtherScreenClosed event. Internally, App Inventor stores the name of the Screen that was last opened in a variable. Its name is then also provided as an argument in the event.
This works perfectly as long as you do not interfere with the management of the BackStack. However, this is possible and common when using Notifications. When the Notification is created, Android is told in the form of an Intent (see About intent) what should happen when the notification itself or one of the action buttons is clicked. Often a new Activity is to be started or an existing one brought to the foreground. If e.g. the activity is in the middle of the stack, you need to specify what should happen to the rest of the stack. It is easy to imagine that the startActivityForResult-onActivityResult mechanism is then confused. In concrete terms, this means that the Screen.OtherScreenClosed event is not triggered, is no longer triggered reliably or is triggered with incorrect values. You therefore need to think very carefully about how the app interacts with the notification.
If the Notification is used to open a Screen of the app or to bring it to the foreground, the Screen.Initialize event is triggered in the screen if the screen is newly created. The fields of the Screen are given the default values. If the Screen is already open and is only brought to the foreground the UrsNotification.OnNewIntent event is triggered instead.
What exactly should happen is determined by the flags of the intent (Intent.Flags and following). Unfortunately, I cannot explain in detail how the flags have to be set in order to trigger a certain behavior. The documentation for the Intent is quite short and more detailed explanations are widely scattered. Everyone has to read and try it out for themselves. Valera has created the following table, which describes the effect of the flags very well.
Flag | Meaning | Usage |
---|---|---|
FLAG_CLEAR_TASK | Deletes the current task by removing all activities in the stack when an activity is started in a new task. See FLAG_NEW_TASK | Used to create a new task batch if the current screen is to be completely replaced. |
FLAG_CLEAR_TOP | Removes all activities above the specified one if it is already in the stack and makes it the top one. | Useful if you want to return to a specific screen while removing all intermediate screens from the stack. |
FLAG_EXCLUDE_FROM_RECENTS | Excludes the activity from the list of recently used applications. | Used for temporary or confidential screens that should not be displayed in the list of recently used screens. |
FLAG_NEW_TASK | Starts the activity in a new task stack. | Useful if the activity is to exist independently of the current task flow. |
FLAG_NO_ANIMATION | Deactivates the animation when switching to or leaving an activity. | Used when an immediate transition without animation is required, e.g. for confirmation screens. |
FLAG_NO_HISTORY | The activity is not saved in the task stack and is destroyed immediately after leaving. | Applicable to temporary screens such as login windows that do not need to be saved in the history. |
FLAG_PREVIOUS_IS_TOP | *No longer supported * Used to return the previous activity to the top of the stack when closing the current one. | *Was used in earlier Android versions to manage the task stack.* |
FLAG_REORDER_TO_FRONT | Moves an existing activity to the top of the stack without creating a new instance. | Practical for returning to a screen that has already been opened. Its status is retained. |
FLAG_RESET_TASK_IF_NEEDED | If the task is moved to the foreground, the activity is restarted if this is necessary to restore the stack correctly. | Used by the system to manage tasks during transitions between applications. |
FLAG_SINGLE_TOP | Prevents the creation of a new copy of the activity if it is already at the top of the stack. | Useful to avoid duplicating a screen if it is already active, e.g. for a notification screen. |
FLAG_TASK_ON_HOME | Fixes the task as the 'start screen' - moves it to the position of the main task stack. | Used to make a separate task flow behave like the main application screen when the Home button is pressed. |
The App Inventor Extension UrsAi2Notification enables the creation of Android notifications. The extension contains three components:
Android versions older than API Level 26 do not have notification channels. Notifications are created without channels. Functions that relate to channels have no effect.
The (Android) NotificationChannel is automatically created immediately after starting the app. You don't have to worry about it yourself. The properties of the notification channel can be set in the designer window of the App Inventor. Since the properties of the channel cannot be changed after it has been created, there are no methods for modification at runtime.
Particular attention must be paid to the setting of the Importance level. It depends on this which general (channel-independent) settings the notifications get. As already mentioned in the note above, these are determined by that channel that was created first. The site Set the Importance Level at the Android documentation gives the details.
UrsAI2NotificationChannel (Reference) provides the following functions for simply generating notifications:
The download contains the sample project SimpleNotificationTest that shows the application of these three functions.
The download contains the sample project
ExtendedNotificationTest that shows the application
of this function.
The download contains the sample project ProgressBarTest that shows the application of this function.
The download contains the sample project Notification Alarm Test that shows the use of this function. A second example is Remember URS.
You have to be able to cancel notifications:
The HideChannel method hides a notification channel.
It is unusual to change the name (ChannelName) and the description (Description) of a channel by program or by the user. Usually this is only done by updating the app. If the update contains new values for these properties, these channel properties are automatically updated when the program is started.
Notification channel groups and individual notification sounds are not implemented (see above).
Other helpful functions are
1) The function requires the EXPAND_STATUS_BAR permission. This permission is not requested in the standard AI2 companion and does not work there. Chapter AI2 FAQ: Patching the AI2 Companion - Additional Permissions explains how to patch the AI2 Companion and how to obtain the necessary permission.
The UrsNotifiaction (Reference) component is used to summarize the various properties of a Notification. The Notifiction.Builder is used internally to create the notification. Notifications can be modified. If a second notification is created with the same ID (NumberID field) before the previous one has been deleted, this will be updated.
The functions Create and Cancel are identical to those of the notification channel. You generate a notification with the settings of the component or delete the notification with the ID (NumberID) defined in the component
The SetProgress, SetProgressEx, RemoveProgressBar and RemoveProgressBarEx functions modify a progress notification created with the UrsAI2NotificationChannel.CreateProgressNotification function
AddActionButton and RemoveActionButtons are used to add and remove action buttons. Up to three action buttons are supported.
Instead starting of another Activity, the event OnClick can be triggered at the Screen to which the UrsNotification object belongs. To do this, an UrsIntent must be specified with the ActionType Event.
The OnClick event will not be triggered if the associated Screen has been closed. Apps that use this function must ensure that the notification is either closed (CancelOnDestroy property) or modified appropriately. Unfortunately, the App Inventor does not allow the Activity.onDestroy event to be passed to the app. This means that there is no way of changing the notification accordingly. Therefore, a suitable notification which is displayed when the app is closed is registered via the SetOnDestroyAction function. It should be noted that the internally necessary objects are created when this function is called1). If changes are to be made to the passed UrsNotificationObject or UrsIntentObject, the SetOnDestroyAction function must be called again. Otherwise the change would have no effect.
1) If the app is closed from the app overview (history), only a limited time and a limited range of functions are available (test with version Android Oreo, 8.1). This is not suitable to create the objects at the time of closing.
RemoveOnDestroyAction removes the task of displaying a new notification when the Screen is closed.
AreNotificationsEnabled and AreNotificationsPaused provide information on the status of the notification system.
An UrsIntent (Reference) object that is passed to the Create... functions is used to specify which action is to be triggered when the notification is tapped.
This component is a collection of properties. It has neither functions nor events.
The ActionType specifies which action is triggered with the Intent:
The intents for the OnClick event can be differentiated using the ID property. If you want to use the OnClick event for a notification with action buttons, a different UrsIntent instance, which at least differs in ID, must be applied to the actual notification and to each action button. The ID of the associated UrsIntent instance is published by the OnClick event.
Errors are reported via the Screen.ErrorOccurred event. If no handler is implemented for this event, the system displays an error message. The Notifiert.ShowAlert function is used for this purpose. The implementation of Screen.ErrorOccurred prevents the error message from being displayed and it is possible to react to the error programmatically.
Code | Error text | Meaning | Trigger |
---|---|---|---|
17001 | Invalid value at UrsChannelObject. | Wrong type at parameter UrsChannelObject. | UrsNotification.Create, UrsNotification.SetOnDestroyAction |
17002 | Invalid Vibration Pattern | Invalid vibration pattern. | UrsAI2NotificationChannel (beim Start der App) |
17003 | Invalid sound file name | The specified audio file does not exist. | UrsAI2NotificationChannel (beim Start der App) |
17004 | Screen not found: <screen name> | The specified Screen does not exist. |
UrsAI2NotificationChannel.CreateAiNotification |
17005 | Invalid value at UrsNotificationObject. | Wrong type at parameter UrsNotificationObject. | UrsAI2NotificationChannel: CreateNotification, CreateAlarm, CreateAlarmEx, CreateAlarmAt, CreateProgressNotification UrsNotification.SetOnDestroyAction |
17006 | Invalid value at UrsIntentObject | Wrong type at parameter UrsIntentObject. | UrsAI2NotificationChannel: CreateActionNotification, CreateNotification, CreateAlarm, CreateAlarmEx, UrsAI2NotificationChannel.CreateAlarmAt, CreateProgressNotification UrsNotification: AddActionButton, Create, SetOnDestroyAction |
17007 | Invalid Delay value | Delayis less than 1. | UrsAI2NotificationChannel: CreateAlarm, CreateAlarmEx |
17008 | Invalid Millis value | The specification is smaller than the current time. | UrsAI2NotificationChannel.CreateAlarmAt |
17009 | Notification not created yet | The notification has not been created yet. | UrsNotification: SetProgress, SetProgressEx, RemoveProgressBar, RemoveProgressBarEx |
17010 | Must specify Title | The specification for the Title parameter is missing. | UrsNotification.AddActionButton |
Notice: If you try an example, make sure that it contains the latest version of the extension. I have sometimes forgotten to update one of the examples when updating.
Simple Notification TestThis example shows how the UrsNotificationChannel.Create... methods work |
|
Extended Notification TestThe extended options such as symbols, images and action buttons are shown. |
|
Progress Bar TestThe topic is display of progress notifications. |
|
Notification Alarm TestNotifications are delayed or triggered at specific times. |
|
Remember URSA handy application that reminds the user to start the app regularly. |
|
KeepAwake_NotificationThe design of a notification in connection with a ForegroundService, which is necessary for setting a WakeLock. |