German Version   German Version


Version Adjustments
1.0 (2021-05-05) Initial Version
1.1 (2021-07-11)
1.2 (2021-09-12)

If the extension is used in several apps, tapping an action button triggers the associated event in all apps at the same time. This is due to the global nature of the broadcast receivers used. Solution: The intents for the action buttons are individualized with the app name. When a broadcast is received, the name is checked and only the appropriate messages are processed.

Kodular now also provides many Androidx functions. Only "androidx.media.jar" has to be integrated.

The Foreground service is now declared via UsesServices annotaion in the source and manually in the broadcastReceivers section in the generated .aix file.

With these changes it is no longer necessary to have two different versions of the extension for App Inventor and Kodular.


Adaptation of existing Kodular projects :

Internal names are identical. Therefore the old version can be replaced by the new one. However, this is only possible by exporting the project and reimporting it .

  • Create a backup copy of the project .
  • Export the project.
  • In the .aia file (is a ZIP archive), in the assets/external_comps directory delete de.ullisroboterseite.ursai2medianotificationk directory.
  • Copy the de.ullisroboterseite.ursai2medianotification directory from the extension (.aix file, also a ZIP archive) to this point in the .aia file.
  • Re-import the project (.aia file) into Kodular.
1.3 (2021-09-15) As above. Now also for clicking the notification and deleting it individualized intents are used to prevent overlaps when using the extension in several apps at the same time.
1.4 (2022-10-10) Adapted for SDK31 (Android 12):
All PendingIntents get the FLAG_IMMUTABLE flag.
The service receives the attribute exported = "true".
Global exception is caught and written to the log.
2023-04-19 Update of the TaifunPlayer extension used in the example. The old version no longer works on Android 11+.
2023-08-15 Since Android 12 (even earlier?), the app no longer opens automatically when you click on the notification. Fabio told me what needed to be changed.
1.6 (2023-11-23) Adapted to Android 14: Broadcast receiver requires additional flags
1.7 (2024-09-04) Adapted to Android 14: Foreground service types are required
2.0 (2024-10-24

The extension has been completely revised:

  • Unnecessary ForegroundService and the ForegroundService property removed .
  • Functions GetChannelID and HideChannel added.
  • Properties ClickAble and the OnClick event removed.
    In the newer Android versions, it is no longer permitted for an app to overlay another app by program instruction. The only way to bring an app to the foreground is for the user to click on a notification belonging to the app. The extension has been modified so that clicking on the notification reliably brings the associated app to the foreground.
  • The notification channel is checked with each call to methods ShowNotification and ShowWithProgressBar and updated if necessary.
  • Method SetActionIcon added.
  • Property Density added.
2.1 (2024-12-17) Although many players set a WakeLock, this is not sufficient in newer Android versions to keep this active. The UseForegroundService and UseWakeLock properties have been added.

Download

Test results

Usage

About notification channels

Keeping the device active

Configuration

Buttons inside media notification

Activate events

Meta data and appearance

ProgressBar (since Android 10, API Level 29)

How to

Error handling

Reference

Properties

Methods

Events

Example

The user interface

Controls

Options

Implementation hints

Tools

 

Download

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

Test results

Device Test result
Smartphone Redmi 5 Plus, Android 8.1 Companion version 2.6.1 results in an error. Not all necessary classes are available in the Companion.
Compiled APK works perfectly (no progress bar, which is only available from Android 10.
Smartphone Samsung A02s, Android 12 Both the Companion and APK work as intended.
Tablet Yestel T13_EEA, Android 13 Both the Companion and APK work as intended.
Smartphone ZTE Blade A73, Android 13 No progress bar is displayed either in the Companion or in the APK. The app icon is always displayed as the SmallIcon (the icon in the taskbar).
The other features work as intended.

Usage

Since API level 21 (LolliPop 5.0) there is a special type of notification that was specially developed to control media players. External playback devices like headphones can control the media player via this notification too.

This extension is only intended for the administration of media notifications. If you want to create regular notifications, you should use the extension UrsAI2Notifier.

About notification channels

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 to such a channel up from API level 26. Up to and including API Level 25, all information and functions relating to the notification channel are irgnored.

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. importance (see Importance, IMPORTANCE_DEFAULT etc.), are defined at the channel level. These properties are set by the app when the channel is created. With the help of the Android app Settings, the user has full access to most of the channel attributes and can modify them as required. The modifications made by the user should not be overwritten. This is why the channel properties can no longer be changed later via a program. Even if a channel is deleted and then created again, it is created with the last settings. "Erasing" is practically just "hiding". Only the properties Name and Descriptionof can be changed later. Eliminating spelling mistakes would otherwise be impossible.

So you should think carefully about which properties are assigned to a channel.

The extension offers the properties ChannelID, ChannelName, ChannelDescription and ChannelImportance as channel properties. ChannelImportance defines, among other things, the conditions under which a notification is displayed (see Importance, IMPORTANCE_DEFAULT etc.).The channel is created automatically  when ShowNotification is called for the first time.

If you want to change other properties, a new channel (new ChannelID) must be used. You should hide the existing channel when starting the app with HideChannel .

Keeping the device active

Many media player components use a WakeLock to keep the device active while playing a sound file. This was sufficient in older versions. Since Android 8.0 (Oreo, API level 26), the Android policy has changed to the effect that an app that prevents the device from switching to standby mode (doze mode) must visibly indicate this to the user. Since then, it has been necessary to start a ForegroundService in addition to the WakeLock. This service implies a notification informing the user that battery optimization is being prevented.

The Designer property UseForegroundService can be used to set the extension to start a Foreground service and display the MediaNotification. In the event that the media player itself does not set a WakeLock, this can also be done via the extension using the UseWakeLock property. The use of UseWakeLock implies UseForegroundService, i.e. the MediaNotification is displayed via a foreground service.

Configuration

All changes have no immediate effect. They are applied the next time ShowNotification is called.

Buttons inside media notification

The button with the play () or the pause () symbol is always displayed. Which of them is displayed can be set using the SetStatePaused (shows ) and SetStatePlaying (shows ) methods.

Depending on which functions the app wants to supports, the other buttons can be switched on and off by the Support... functions.

Über die Methode SetActionIcon lassen sich die auf den Schaltflächen der Benachrichtigung angezeigten Symbole anpassen. Es können entweder die Bezeichnung eines System-Icons oder der Name einer hochgeladen Grafik-Datei angegeben werden. So kann man z.B. die Symbole für Previous und Next durch Like und Dislike ersetzen. Insgesamt ist die Benachrichtigung in der Lage bis zu fünf Aktionsschaltflächen anzuzeigen.

The icons displayed on the notification buttons can be customised using the SetActionIcon method. Either the name of a system icon or the name of an uploaded graphic file can be specified. For example, the icons for Previous and Next can be replaced with Like and Dislike. In total, the notification can display up to five action buttons.

Activate events

If DeleteAble is set, the user can delete the notification, for example by swiping. If the notification is deleted by the user, the UserCanceled event is triggered

Meta data and appearance

The background color is not programmatically adjustable. It is automatically determined by Android from the album image colors.

The SetMetaData and SetMetaDataEx functions can be used to specify the title, artist and the image (AlbumImage) that will be shown on the notification.

AlbumImage

You can specify AlbumImage as follows:

Type Prefix Example
URL http or https https://ullisroboterseite.de/android-AI2-MediaNotification/MediaNotification.png
Asset // or nothing //MediaNotification.png or simply MediaNotification.png
File, relative path / /data/user/0/appinventor.ai_bienonline.UrsMediaNotificationAI2/MediaNotification.png
File, absolute path file:///  file:///Android/data/appinventor.ai_bienonline.UrsMediaNotificationAI2/MediaNotification.png

When specifying a URL, notice that the image is loaded synchronously. This can take some time with large files or slow connections. Another option is to use an extension that enables an asynchronous (concurrent) download of the file ( e.g. the ImageLoader extension ).

To simplify the file acces you can use:

Small Icon

The option of including your own graphics for the SmallIcon (SmallIconImage property ) is available up from API Level 23. The SmallSystemIcon property to allows to select a system icon for older versions (for possible options see: System Notification Icons). The selection rule is as follows:

Condition Selection
API Level SmallIconImage SmallSystemIcon
≥ 23 specified X SmallIconImage
empty specified SmallSystemIcon
empty empty no icon
< 23 X specified SmallSystemIcon
X empty no icon

ProgressBar (since Android 10, API Level 29)

Since Android 10, the media notification can display a progress bar and a seek bar. To do this, the duration of the media object and the current position of the player must be known.

SetMetaDataEx allows the specification of the playing time, which is required for the display of a progress bar. Some media players, such as the TaifunPlayer (used in the example) provide this information. To get the necessary ininformations the player must be initialized accordingly.

The ShowWithProgressBar function shows a progress bar. It starts at the position that is specified with the CurrentPosition  parameter. Then it continues to run independently. If you change the playback position programmatically, you have to synchronize the progress bar with ShowWithProgressBar.

With versions older than Android 10, SetMetaDataE and ShowWithProgressBar also work, but no progress bar is displayed.

How to

You set the initial properties of the component, transfer the media metadata ( SetMetaData or SetMetaDataEx) and then call ShowNotification or ShowWithProgressBar. From now on you prectically need to react to the events. Depending on the event, you set the media player appropriately, adjust the properties of the component and call ShowNotification again .

Usually the media player is not only controlled by the media notification. The app also contains controls that are supposed to control the player. To make the blocks in the project simple, there are the functions Play, Pause, Rewind, etc., which trigger the same events as the notification does. So there is no need for double the code for the controls on the user interface. All you have to do is call the appropriate function.

Error handling

Errors are reported via the Screen.ErrorOccurred event.

Code Text Meaning Comment
17500 Album image not found. The specified album image could not be loaded. Affected functions are SetMetaData und SetMetaDataEx
17501 SmallSystemIcon invalid. The specification for the SmallSystemIcon parameter cannot be resolved. Affected function is ShowNotification. The notification is shown without an icon.
17502 SmallIconImage invalid. The graphic file for the SmallIconImage parameter cannot be loaded. Affected function is ShowNotification. The notification is shown without an icon.
17503 Image file name invalid. The IconName parameter cannot be resolved. Affected function is SetActionIcon. The symbol is not changed.
17504 ActioNo invalid. The action number must be in the range 1..6. Affected function is SetActionIcon. No symbol is changed.
17505 Not an UrsMediaHelper component. The specified component is not of type UrsMediaHelper. Affected function is SetMetaDataFromMH.

Reference

Properties

ChannelDescription
Description of the NotificationChanel that is visible to the user. This property can be changed later.
ChannelID
The ID of the NotificationChanel (cannot be changed later).
ChannelImportance
The importance of the channel. The default is NotificationManager.IMPORTANCE_LOW.
ChannelName
Name of the NotificationChanel visible to the user. This property can be changed later.
DeleteAble
The notification can be deleted by the user, for example by swiping.
Note:
- Changing this property will take effect with the next call to ShowNotification.
Density
The logical density of the display. This is a scaling factor for the Density Independent Pixel unit, where one DIP is one pixel on an approximately 160 dpi screen (for example a 240x320, 1.5"x2" screen), providing the baseline of the system's display. Thus on a 160dpi screen this density value will be 1; on a 120 dpi screen it would be .75; etc. (see DisplayMetrics.density).
IsRunningInCompanion
Returns whether the application is currently running in the Companion.
SmallIconImage
Since API level 23! Asset name (category Media in the App Inventor) of the file for the icon in the status bar (see Notification.Builder.setSamallIcon). This information is ignored for versions up to API Level 22. See also Metadata and appearance.
Whether the icon is displayed depends on the Android version, the device manufacturer and the level of importance of the notification channel.
Note: Changing this property will take effect with the next call to ShowNotification.
SmallSystemIcon
Icon for Android versions up to API level 22. For possible options see: System Notification Icons. See also Metadata and appearance.
Whether the icon is displayed depends on the Android version, the device manufacturer and the level of importance of the notification channel.
Note: Changing this property will take effect with the next call to ShowNotification.
StateIsPlaying
Returns the status of the notification. true: The pause symbol () is displayed. false: the play symbol () is displayed.
SupportFastForward
The Fast Forward icon (>>) is shown in the notification.
Note: Changing this property will take effect with the next call to ShowNotification.
SupportRewind
The Rewind icon (<<) is shown in the notification.
Note: Changing this property will take effect with the next call to ShowNotification.
SupportSkipToNext
The Skip to next icon (>|) is shown in the notification.
Note: Changing this property will take effect with the next call to ShowNotification.
SupportSkipToPrevious
The Skip to previous icon (|<) is shown in the notification.
Note: Changing this property will take effect with the next call to ShowNotification.
UseForegroundService
The MediaNotification is displayed via a Foreground service.
UseWakeLock
When the MediaNotification is displayed, a WakeLock is automatically set and the MediaNotification is displayed via a ForegroundService.
Version
Version name of the extension.
VersionSDK
The API level of the currently running Android instance.

Methods

FastForward ()
Triggers the OnFastForward event . Buttons on the user interface can thus trigger the same event (and therefore the same code) as tapping the media button Fast Forward.
GetAppDataDir ()
Returns the path for the app sepcific directory. Calling GetAppDataDir()on my test device (in the example below) returns the following result:
     /data/user/0/appinventor.ai_bienonline.UrsMediaNotificationAI2/
GetChannelID ()
Returns the name of the current notification channel.
GetDownloadDir (Prefix)
Returns the path for the download directory. Prefix is placed in front of the name. Calling GetDownloadDir("file://") on my test device (in the example below) returns the following result:
     file:///storage/emulated/0/Download/
GetVolumes (Prefix)
Returns a list of the installed volumes. The internal memory can usually be found under index 1, the external SD card under index 2. Prefix is placed in front of the name. Calling getVolumes("file://) on my test device returns the following items :
     file:///storage/emulated/
     file:///storage/F277-0260/
HideChannel ()
Hides the channel. Since API level 26!
If a new channel is created with the same ID, the deleted channel will be restored with all the settings it had before it was deleted.
Pause ()
Triggers the OnPause event . Buttons on the user interface can thus trigger the same event (and therefore the same code) as tapping the media button Pause.
Play ()
Triggers the OnPlay event . Buttons on the user interface can thus trigger the same event (and therefore the same code) as tapping the media button Play.
Rewind ()
Triggers the OnRewind event . Buttons on the user interface can thus trigger the same event (and therefore the same code) as tapping the media button Rewind.
SetActionIcon (ActionNo, IconName)
Changes the icon of the action buttons in the MediaNotification (see Buttons inside media notification).
ActionNo: Number of the button 1: Previous, 2: Rewind, 3: Play, 4: Pause, 5: Fast forward, 6: Next
IconName: The name of an asset file or the name of a system icon (see System Notification Icons).
Note: Changing this data will take effect with the next call to ShowNotification.
SetMetaData (Title, Artist, AlbumImage)
The metadata is applied to the notification. How the parameter AlbumImage can be fielld is explained in more detail in the section Metadata and Appearance. If the album image cannot be loaded, the Screen.ErrorOccurred event is triggered with the error number 17500. The meta data is created without an album image
Note: Changing this data will take effect with the next call to ShowNotification.
SetMetaDataEx (Title, Artist, AlbumImage, Duration)
The metadata is applied to the notification. How the parameter AlbumImage can be fielld is explained in more detail in the section Metadata and Appearance. If the album image cannot be loaded, the Screen.ErrorOccurred event is triggered with the error number 17500. The meta data is created without an album image
Note: Changing this data will take effect with the next call to ShowNotification.
SetMetaDataFromMH (MediaHelper)
The metadata are loaded from an UrsMediaHelper component.
If the specified component is not of type UrsMediaHelper, the Screen.ErrorOccurred event is triggered with the error number 17500.
Note:
Changing this data will take effect with the next call to ShowNotification.
SetStatePaused ()
The notification state is set to Pause. The play symbol () is displayed.
Note: Changing this data will take effect with the next call to ShowNotification.
SetStatePlaying ()
The notification state is set to Play. The pause symbol () is displayed.
Note: Changing this data will take effect with the next call to ShowNotification.
ShowNotification ()
The notification is created / displayed.
ShowWithProgressBar (CurrentPosition)
The notification is created / displayed. Since Android 10 and if duration is set via SetMetaDataEx a progress bar is diaplayed. The position of the progress marker is determined from the information on CurrentPosition in relation to Duration.
SkipToNext ()
Triggers the OnSkipToNext event. Buttons on the user interface can thus trigger the same event (and therefore the same code) as tapping the media button Skip to next.
SkipToPrevious ()
Triggers the SkipToPrevious event. Buttons on the user interface can thus trigger the same event (and therefore the same code) as tapping the media button Skip to previous.
Stop ()
Cancels the notification.

Events

OnFastForward (FromNotification)
The Fast Forward symbol (>>) in the notification was clicked (FromNotification = true) or the FastForward function was called (FromNotification = false).
OnPause (FromNotification)
The Pause symbol () in the notification was clicked (FromNotification = true) or the Pause function was called (FromNotification = false).
OnPlay (FromNotification)
The Play symbol () in the notification was clicked (FromNotification = true) or the Play function was called (FromNotification = false).
OnRewind (FromNotification)
The Rewind symbol (<<) in the notification was clicked (FromNotification = true) or the Rewind function was called (FromNotification = false).
OnSkipToNext (FromNotification)
The Skip to next symbol (>|) in the notification was clicked (FromNotification = true) or the SkipToNext function was called (FromNotification = false).
OnSkipToPrevious (FromNotification)
The Skip to previous  symbol (|<) in the notification was clicked (FromNotification = true) or the SkipToPrevious function was called (FromNotification = false).
OnStop (FromNotification)
The Stop function was called ( FromNotification = false ).
UserCanceled ()
The user has canceled the notification. Only active if the DeleteAble property is set.

Example

The download archive contains a sample project:

   UrsMediaNotification

The download ZIP archive contains a sample project file for App Inventor (UrsMediaNotification.aia) and one for Kodular (UrsMediaNotificationK.aia) in the example directory

The example demonstrates how a media player can be controlled with the extension. The TaifunPlayer is used as the player . Four different pieces of music can be played.

In Kodular the fonts of the buttons can be set individually. Among other things, the Material Icons Font with many useful symbols from Google is available there. The MyFonts extension from Anke is used for the App Inventor

The user interface

Controls

The controls are enabled or disabled depending on the current state of the app. Effect:

The associated MediaNotification duplicates these controls. Only the supported elements are displayed (Off Broadway is the last track in the playlist, SkipToNext is therefore not shown):

  (Screenshot Xiaomi Redmi 5 Plus, Android Oreo 8.1)

The display of a stop symbol is unfortunately not available in the Android media notification

In Android 10, the background color is automatically calculated from the color of the album picture.

(Screenshot Google Pixel 2 XL API 30 Emulator)

A progress bar (since Android 10) is displayed when you open the notification:

Options

Implementation hints

The buttons on the screen do not perform a direct action. Instead, they call the corresponding method in the extension. This in turn triggers the corresponding event, which would also have been triggered if the action button of the notification had been clicked. This means that both user actions, clicking in the notification and clicking the button on the app screen, are handled by the same code.

The SetMusic procedure fills the extension with the metadata (title, artist, album image). The MP3 files in the sample project already contain all the necessary metadata so that they can be easily extracted using the UrsMediaHelper extension. The metadata can be viewed and edited with the Mp3tag program, for example.

During initialization, it is ensured that the app works correctly right from the start. SetMusic sets the metadata and the music source for the TainfunPlayer to the first track of the playlist. The combination of MediaPlayer.Start and MediaPlayer.Pause ensures that the Duration and CurrentPosition properties of the media player can be called without the player starta playing. MediaNotification.SetStatePaused and MediaNotification.ShowNotification create the notification in the pause state (symbol ).

 

When skipping to the next song (SkipToNext) or the previous (SkipToPrevious), the current state of the media player is temporarily stored in a local variable. This should be restored after switching. Then the player is stopped. The next (the previous) song is determined and the buttons corresponding to the state of the playlist are enabled or disabled. The blocks are fed with the metadata of the newly selected song via the SetMusic procedure . Finally, the OnPlay or OnPause events are triggered according to the saved player state. . In the events it is ensured that the media player and the media notification are set correctly.

Tools

For developing own extensions I gathered some tips: AI2 FAQ: Develop Extensions. On the site you can find further informations.