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 .
|
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:
|
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. |
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.
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. |
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.
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 .
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.
All changes have no immediate effect. They are applied the next time ShowNotification is called.
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.
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
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.
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:
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 |
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.
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.
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. |
GetAppDataDir()
on my test
device (in the example below) returns the following result:GetDownloadDir("file://")
on my test device (in the example below)
returns the following result: getVolumes("file://)
on my test device returns the following items : 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 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:
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.
For developing own extensions I gathered some tips: AI2 FAQ: Develop Extensions. On the site you can find further informations.