Android Notification.MediaStyle 未响应 MediaSession 更新
Android Notification.MediaStyle not responding to MediaSession updates
根据 Notification.MediaStyle
文档,将 MediaSession.Token
附加到给定的 MediaStyle 应该将其挂接到关联的 MediaSession
对象。
引用如下:
Finally, if you attach a MediaSession.Token using setMediaSession(MediaSession.Token), the System UI can identify this as a notification representing an active media session and respond accordingly (by showing album artwork in the lockscreen, for example).
然后文档给出了在通知中使用MediaStyle的代码片段如下:
Notification noti = new Notification.Builder()
.setSmallIcon(R.drawable.ic_stat_player)
.setContentTitle("Track title") // these three lines are optional
.setContentText("Artist - Album") // if you use
.setLargeIcon(albumArtBitmap)) // setMediaSession(token)
.setStyle(new Notification.MediaStyle()
.setMediaSession(mySession))
.build();
清楚地说明(来自 optional 一词)当与令牌对象(可能由 MediaStyle 实例自动填充)一起使用时,ContentTitle/ContentText 参数不是必需的.
在尝试将此 MediaStyle 实施到我当前正在构建的音乐播放器时,我注意到尽管音乐播放器在整个过程中反复更新元数据和播放状态,但使用 MediaStyle 设置样式的通知根本没有更新。唯一存在的是带有通知 "small icon" 的空白通知,当视图展开时,它会拉伸得超出大图标的比例。
为了说明这个问题,我在下面创建了一个包含两个按钮的小型测试应用程序。一键更新通知(使用 MediaStyle 创建一个新通知并发送到通知管理器)。另一个按钮生成元数据和假播放状态来模拟播放。我注意到无论我按什么顺序按下什么按钮组合,通知都不会更新为我希望它更新的样式。
以下表示activity class代表我的测试用例。大多数是样板 Activity 代码,最后两个方法 updateNotification()
和 updateState()
链接到两个按钮的 onClick 属性并作为 OnClickListeners 提供便利。
public class MediaStyleTestActivity extends Activity {
private MediaSession mSession;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_media_style_test);
mSession = new MediaSession(this, "TestSession");
mSession.setActive(true);
}
@Override
protected void onDestroy() {
super.onDestroy();
mSession.release();
}
@Override
public boolean onCreateOptionsMenu(Menu menu){
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_media_style_test, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void updateState(View v){
MediaMetadata.Builder mMetaBuilder = new MediaMetadata.Builder();
mMetaBuilder.putText(MediaMetadata.METADATA_KEY_TITLE, "Blue Jeans");
mMetaBuilder.putText(MediaMetadata.METADATA_KEY_ALBUM, "Born to Die");
mMetaBuilder.putText(MediaMetadata.METADATA_KEY_ARTIST, "Lana Del Rey");
mMetaBuilder.putText(MediaMetadata.METADATA_KEY_ALBUM_ARTIST, "Lana Del Rey");
mMetaBuilder.putLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER, 3);
mMetaBuilder.putLong(MediaMetadata.METADATA_KEY_NUM_TRACKS, 15);
mMetaBuilder.putLong(MediaMetadata.METADATA_KEY_DISC_NUMBER, 1);
Bitmap albumArt = BitmapFactory.decodeResource(getResources(), R.drawable.album_art);
mMetaBuilder.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, albumArt);
PlaybackState.Builder stateBuilder = new PlaybackState.Builder();
stateBuilder.setActiveQueueItemId(MediaSession.QueueItem.UNKNOWN_ID);
long actions = PlaybackState.ACTION_PLAY_PAUSE | PlaybackState.ACTION_STOP | PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS;
stateBuilder.setActions(actions);
stateBuilder.setState(PlaybackState.STATE_PLAYING, 0, 1.0f);
mSession.setMetadata(mMetaBuilder.build());
mSession.setPlaybackState(stateBuilder.build());
}
public void updateNotification(View v){
Notification.Builder nBuilder = new Notification.Builder(this);
nBuilder.setOngoing(true);
nBuilder.setShowWhen(false);
nBuilder.setVisibility(Notification.VISIBILITY_PUBLIC);
nBuilder.setSmallIcon(android.R.drawable.ic_media_play);
nBuilder.setStyle(new Notification.MediaStyle().setMediaSession(mSession.getSessionToken()));
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(100, nBuilder.build());
}
}
此处MediaSession的不当使用请忽略,仅供演示。
我设备上的应用程序:
我确实注意到锁屏正在更新专辑封面,但仅此而已:
如前所述,无论我尝试哪种 MediaSession/MediaStyle/Notification 更新组合,none 似乎都会导致通知的内容视图填充提供的元数据(包括设置有效的 MediaSession.QueueItem
示例中未显示)。 Logcat 即使在通知不顺利或失败的情况下,也不会显示任何内容。
除非我在这里遗漏了一些非常明显的东西,否则我做错了什么?
作为附加信息,我没有使用任何通知和 MediaSession 的兼容性库。我的应用程序的这个组件仅适用于 API 21+,因此不需要向后兼容支持。
在我的生产代码中,实际的 MediaSession 保存在前台服务中,我尝试从各种线程更新(UI/whatever 媒体线程 android uses/my 自己的自定义线程)无济于事。
你是对的。从今天开始,需要 setContentTitle
、setContextText
和 setLargeIcon
才能显示通知标题、文本和图像。 (正在解决的文档问题)
旁白:另请注意,您应该调用 mediaSession.setActive(true)
根据 Notification.MediaStyle
文档,将 MediaSession.Token
附加到给定的 MediaStyle 应该将其挂接到关联的 MediaSession
对象。
引用如下:
Finally, if you attach a MediaSession.Token using setMediaSession(MediaSession.Token), the System UI can identify this as a notification representing an active media session and respond accordingly (by showing album artwork in the lockscreen, for example).
然后文档给出了在通知中使用MediaStyle的代码片段如下:
Notification noti = new Notification.Builder()
.setSmallIcon(R.drawable.ic_stat_player)
.setContentTitle("Track title") // these three lines are optional
.setContentText("Artist - Album") // if you use
.setLargeIcon(albumArtBitmap)) // setMediaSession(token)
.setStyle(new Notification.MediaStyle()
.setMediaSession(mySession))
.build();
清楚地说明(来自 optional 一词)当与令牌对象(可能由 MediaStyle 实例自动填充)一起使用时,ContentTitle/ContentText 参数不是必需的.
在尝试将此 MediaStyle 实施到我当前正在构建的音乐播放器时,我注意到尽管音乐播放器在整个过程中反复更新元数据和播放状态,但使用 MediaStyle 设置样式的通知根本没有更新。唯一存在的是带有通知 "small icon" 的空白通知,当视图展开时,它会拉伸得超出大图标的比例。
为了说明这个问题,我在下面创建了一个包含两个按钮的小型测试应用程序。一键更新通知(使用 MediaStyle 创建一个新通知并发送到通知管理器)。另一个按钮生成元数据和假播放状态来模拟播放。我注意到无论我按什么顺序按下什么按钮组合,通知都不会更新为我希望它更新的样式。
以下表示activity class代表我的测试用例。大多数是样板 Activity 代码,最后两个方法 updateNotification()
和 updateState()
链接到两个按钮的 onClick 属性并作为 OnClickListeners 提供便利。
public class MediaStyleTestActivity extends Activity {
private MediaSession mSession;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_media_style_test);
mSession = new MediaSession(this, "TestSession");
mSession.setActive(true);
}
@Override
protected void onDestroy() {
super.onDestroy();
mSession.release();
}
@Override
public boolean onCreateOptionsMenu(Menu menu){
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_media_style_test, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void updateState(View v){
MediaMetadata.Builder mMetaBuilder = new MediaMetadata.Builder();
mMetaBuilder.putText(MediaMetadata.METADATA_KEY_TITLE, "Blue Jeans");
mMetaBuilder.putText(MediaMetadata.METADATA_KEY_ALBUM, "Born to Die");
mMetaBuilder.putText(MediaMetadata.METADATA_KEY_ARTIST, "Lana Del Rey");
mMetaBuilder.putText(MediaMetadata.METADATA_KEY_ALBUM_ARTIST, "Lana Del Rey");
mMetaBuilder.putLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER, 3);
mMetaBuilder.putLong(MediaMetadata.METADATA_KEY_NUM_TRACKS, 15);
mMetaBuilder.putLong(MediaMetadata.METADATA_KEY_DISC_NUMBER, 1);
Bitmap albumArt = BitmapFactory.decodeResource(getResources(), R.drawable.album_art);
mMetaBuilder.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, albumArt);
PlaybackState.Builder stateBuilder = new PlaybackState.Builder();
stateBuilder.setActiveQueueItemId(MediaSession.QueueItem.UNKNOWN_ID);
long actions = PlaybackState.ACTION_PLAY_PAUSE | PlaybackState.ACTION_STOP | PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS;
stateBuilder.setActions(actions);
stateBuilder.setState(PlaybackState.STATE_PLAYING, 0, 1.0f);
mSession.setMetadata(mMetaBuilder.build());
mSession.setPlaybackState(stateBuilder.build());
}
public void updateNotification(View v){
Notification.Builder nBuilder = new Notification.Builder(this);
nBuilder.setOngoing(true);
nBuilder.setShowWhen(false);
nBuilder.setVisibility(Notification.VISIBILITY_PUBLIC);
nBuilder.setSmallIcon(android.R.drawable.ic_media_play);
nBuilder.setStyle(new Notification.MediaStyle().setMediaSession(mSession.getSessionToken()));
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(100, nBuilder.build());
}
}
此处MediaSession的不当使用请忽略,仅供演示。
我设备上的应用程序:
我确实注意到锁屏正在更新专辑封面,但仅此而已:
如前所述,无论我尝试哪种 MediaSession/MediaStyle/Notification 更新组合,none 似乎都会导致通知的内容视图填充提供的元数据(包括设置有效的 MediaSession.QueueItem
示例中未显示)。 Logcat 即使在通知不顺利或失败的情况下,也不会显示任何内容。
除非我在这里遗漏了一些非常明显的东西,否则我做错了什么?
作为附加信息,我没有使用任何通知和 MediaSession 的兼容性库。我的应用程序的这个组件仅适用于 API 21+,因此不需要向后兼容支持。
在我的生产代码中,实际的 MediaSession 保存在前台服务中,我尝试从各种线程更新(UI/whatever 媒体线程 android uses/my 自己的自定义线程)无济于事。
你是对的。从今天开始,需要 setContentTitle
、setContextText
和 setLargeIcon
才能显示通知标题、文本和图像。 (正在解决的文档问题)
旁白:另请注意,您应该调用 mediaSession.setActive(true)