这是indexloc提供的服务,不要输入任何密码
Skip to content

API to allow manual refresh of notification, and making MediaNotification.Provider aware of manual refresh #1833

@nift4

Description

@nift4

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:

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

  1. Add a new API to MediaSessionService that allows me to manually trigger an update, akin to onUpdateNotificationInternal(session, false).
  2. 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.
  3. Expose a way to intercept assembled MediaNotification in DefaultMediaNotificationProvider for both the return value of createNotification() and the value passed to onNotificationChangedCallback.

Alternatives considered

Keep the current pile of hacks :)

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions