The OEM MeiZu has implemented so-called "status bar lyrics" in their Flyme OS. It works by setting the lyric text in the Notification using setTicker() and using MeiZu-specific flags in the Notification object to show the ticker as lyrics. They have added two flags:
private const val FLAG_ALWAYS_SHOW_TICKER = 0x01000000
private const val FLAG_ONLY_UPDATE_TICKER = 0x02000000
To enable the lyric mode, I modified MediaNotification.Provider to set the lyric text with setTicker() and apply these flags to the created notification object:
notification.apply {
// Keep the status bar lyrics scrolling
flags = flags.or(FLAG_ALWAYS_SHOW_TICKER)
// Only update the ticker (lyrics), and do not update other properties
if (onlyUpdateTicker)
flags = flags.or(FLAG_ONLY_UPDATE_TICKER)
}
To avoid needless animations in the notification, when only the currently active lyric line changes, FLAG_ONLY_UPDATE_TICKER should be set. This requires distigushing updates generated by media3 (where the notification content always changes) and manually generated updates (which are for lyric changes).
However, media3 currently does not support manually triggering a notification update. The API for this is package-private, and I had to create a new file in the androidx.media3.session package containing some affordances for updating the notification:
var isManualNotificationUpdate = false
private set
// onUpdateNotificationInternal is package-private
fun MediaSessionService.doUpdateNotification(session: MediaSession) {
if (Looper.myLooper() != session.player.applicationLooper)
throw UnsupportedOperationException("wrong looper for doUpdateNotification")
isManualNotificationUpdate = true
onUpdateNotificationInternal(session, false)
isManualNotificationUpdate = false
}
This is pretty ugly.
Another problem I had was that NotificationCompat.Builder does not have a generic setFlag() method public so these OEM-specific flags had to be set in created Notification object. There however isn't any API in DefaultMediaNotificationProvider to intercept assembled Notification object before it's sent out to callees. I had to create a wrapper MediaNotification.Provider that intercepts the return value of createNotification() and the bitmap loading callback and adds the required flags.
(For setting the ticker value, I override addNotificationActions() which provides access to the Builder object. I think that's enough for intercepting the builder.)
Proposed solution
Add a new API to MediaSessionService that allows me to manually trigger an update, akin to onUpdateNotificationInternal(session, false).
Edit MediaNotification.Provider.createNotification() to add a new boolean parameter which is true if the update was triggered manually with the API from point 1.
Expose a way to intercept assembled MediaNotification in DefaultMediaNotificationProvider for both the return value of createNotification() and the value passed to onNotificationChangedCallback.
Use case description
The OEM MeiZu has implemented so-called "status bar lyrics" in their Flyme OS. It works by setting the lyric text in the Notification using setTicker() and using MeiZu-specific flags in the Notification object to show the ticker as lyrics. They have added two flags:
To enable the lyric mode, I modified MediaNotification.Provider to set the lyric text with setTicker() and apply these flags to the created notification object:
To avoid needless animations in the notification, when only the currently active lyric line changes, FLAG_ONLY_UPDATE_TICKER should be set. This requires distigushing updates generated by media3 (where the notification content always changes) and manually generated updates (which are for lyric changes). However, media3 currently does not support manually triggering a notification update. The API for this is package-private, and I had to create a new file in the
androidx.media3.session
package containing some affordances for updating the notification:This is pretty ugly.
Another problem I had was that NotificationCompat.Builder does not have a generic setFlag() method public so these OEM-specific flags had to be set in created Notification object. There however isn't any API in DefaultMediaNotificationProvider to intercept assembled Notification object before it's sent out to callees. I had to create a wrapper MediaNotification.Provider that intercepts the return value of createNotification() and the bitmap loading callback and adds the required flags. (For setting the ticker value, I override addNotificationActions() which provides access to the Builder object. I think that's enough for intercepting the builder.)
Proposed solution
onUpdateNotificationInternal(session, false)
.MediaNotification.Provider.createNotification()
to add a new boolean parameter which is true if the update was triggered manually with the API from point 1.Alternatives considered
Keep the current pile of hacks :)