Media Session Compat 未在 Pre-Lollipop 上显示锁屏控件
Posted
技术标签:
【中文标题】Media Session Compat 未在 Pre-Lollipop 上显示锁屏控件【英文标题】:Media Session Compat not showing Lockscreen controls on Pre-Lollipop 【发布时间】:2015-09-05 16:01:23 【问题描述】:我正在使用来自 AppCompat Support Library Revision 22 的MediaSessionCompat
。在 Lollipop 上,我收到了通知,而且锁屏的背景是专辑封面。一切都很好。
在 Pre-Lollipop 设备上,锁屏上的音乐控件根本不显示。这很奇怪,我尝试了一切,但没有出现,甚至背景都没有变化。
我希望有人能解决这个问题。
注意:RemoteControlClient
曾在 Lollipop 和 KitKat 工作
/**
* Initializes the remote control client
*/
private void setupMediaSession()
/* Activate Audio Manager */
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mAudioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
ComponentName mRemoteControlResponder = new ComponentName(getPackageName(),
MediaButtonReceiver.class.getName());
final Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
mediaButtonIntent.setComponent(mRemoteControlResponder);
mMediaSessionCompat = new MediaSessionCompat(getApplication(), "JairSession", mRemoteControlResponder, null);
mMediaSessionCompat.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
PlaybackStateCompat playbackStateCompat = new PlaybackStateCompat.Builder()
.setActions(
PlaybackStateCompat.ACTION_SEEK_TO |
PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS |
PlaybackStateCompat.ACTION_SKIP_TO_NEXT |
PlaybackStateCompat.ACTION_PLAY |
PlaybackStateCompat.ACTION_PAUSE |
PlaybackStateCompat.ACTION_STOP
)
.setState(
isPlaying() ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED,
getCurrentPosition(),
1.0f)
.build();
mMediaSessionCompat.setPlaybackState(playbackStateCompat);
mMediaSessionCompat.setCallback(mMediaSessionCallback);
mMediaSessionCompat.setSessionActivity(retrievePlaybackActions(5));
mMediaSessionCompat.setActive(true);
updateMediaSessionMetaData();
mTransportController = mMediaSessionCompat.getController().getTransportControls();
这是updateMediaSessionMetaData()
:
/**
* Updates the lockscreen controls, if enabled.
*/
private void updateMediaSessionMetaData()
MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
builder.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, getArtistName());
builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, getAlbumName());
builder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, getTrackName());
builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, getDuration());
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, MusicUtils.getArtwork(this, getAlbumID(), true));
mMediaSessionCompat.setMetadata(builder.build());
媒体会话回调方法
private final MediaSessionCompat.Callback mMediaSessionCallback = new MediaSessionCompat.Callback()
@Override
public boolean onMediaButtonEvent(Intent mediaButtonEvent)
final String intentAction = mediaButtonEvent.getAction();
if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intentAction))
if (PrefUtils.isHeadsetPause(getBaseContext()))
Log.d(LOG_TAG, "Headset disconnected");
pause();
else if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction))
final KeyEvent event = mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (event == null) return super.onMediaButtonEvent(mediaButtonEvent);
final int keycode = event.getKeyCode();
final int action = event.getAction();
final long eventTime = event.getEventTime();
if (event.getRepeatCount() == 0 && action == KeyEvent.ACTION_DOWN)
switch (keycode)
case KeyEvent.KEYCODE_HEADSETHOOK:
if (eventTime - mLastClickTime < DOUBLE_CLICK)
playNext(mSongNumber);
mLastClickTime = 0;
else
if (isPlaying())
pause();
else resume();
mLastClickTime = eventTime;
break;
case KeyEvent.KEYCODE_MEDIA_STOP:
mTransportController.stop();
break;
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
if (isMediaPlayerActive())
if (isPlaying()) mTransportController.pause();
else mTransportController.play();
break;
case KeyEvent.KEYCODE_MEDIA_NEXT:
mTransportController.skipToNext();
break;
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
mTransportController.skipToPrevious();
break;
case KeyEvent.KEYCODE_MEDIA_PAUSE:
mTransportController.pause();
break;
case KeyEvent.KEYCODE_MEDIA_PLAY:
mTransportController.play();
break;
return super.onMediaButtonEvent(mediaButtonEvent);
@Override
public void onPlay()
super.onPlay();
resume();
@Override
public void onPause()
super.onPause();
pause();
@Override
public void onSkipToNext()
super.onSkipToNext();
playNext(mSongNumber);
@Override
public void onSkipToPrevious()
super.onSkipToPrevious();
playPrevious(mSongNumber);
@Override
public void onSeekTo(long pos)
super.onSeekTo(pos);
seekTo(pos);
@Override
public void onStop()
super.onStop();
pause();
commitMusicData();
updatePlayingUI(STOP_ACTION);
stopSelf();
;
媒体按钮接收器清单条目
<!-- Media button receiver -->
<receiver android:name=".receiver.MediaButtonReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
<action android:name="android.media.AUDIO_BECOMING_NOISY" />
</intent-filter>
</receiver>
几周以来我一直在尝试解决这个问题,但没有成功,迫切需要帮助。
编辑:MediaSessionCompat 的教程或示例也可以
【问题讨论】:
修订版 22.0 还是 22.2?您能否包含用于创建MediaSessionCompat
的代码以及setActive()
的位置。
@ianhanniballake 你确定,我会添加代码
@ianhanniballake 添加了代码
您能否确认您使用的是 v4-support 库的 22.2.0 版?出于调试目的,您能否在您发布的所有代码运行之后,包括mMediaSessionCompat.isActive()
是否返回true
以及mMediaSessionCompat.getRemoteControlClient()
在您的Kitkat 设备上是否返回非空值?
@ianhanniballake 感谢您的建议。我在 Lollipop 上这样做了,它给出了mMediaSessionCompat.isActive()
返回true
,如果mMediaSessionCompat.getRemoteControlClient()
返回null
。我会尽快检查 KitKat
【参考方案1】:
虽然MediaSession
不严格要求,但在 API14-19 设备上使用的RemoteControlClient
确实需要audio focus,并且 100% 强烈建议所有媒体播放。
添加行如:
AudioManager audioManager = (AudioManager)
getSystemService(Context.AUDIO_SERVICE);
int result = audioManager.requestAudioFocus(this,
AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
if (result != AudioManager.AUDIOFOCUS_GAIN)
return; //Failed to gain audio focus
在播放任何媒体之前,应获得音频焦点并显示控件。
【讨论】:
我已经在使用它了,但是我在MediaSessionCompat
下面使用它,我将AudioManager
代码移到它上面。但它似乎不适用于模拟器
那么您需要在问题中包含更多代码,理想情况下是您的整个服务和媒体按钮接收器的清单条目
面临同样的问题。有人可以帮忙吗?
@RisingUp 我觉得,我是唯一面临这个问题的人。希望我们能解决它
您的代码在 API 16 模拟器上运行良好 - 查看为我显示锁定屏幕控件的 this super minimal example。【参考方案2】:
最后我想出了一个解决方案。感谢@ianhanniballake & @user1549672
-
按照@ianhanniballake 的建议添加Audio Focus
添加音乐意图
BroadcastReceiver
可以在 Google 和 Android 官方文档上搜索找到
写上面我的问题中给出的setupMediaSession()
非常重要正确提及Flags
上面写MediaSessionCallbacks
也可以
非常重要更新MediaSession
MediaPlayer#onPause()
、MediaPlayer#onStart()
和最后当新歌播放时(还包括下一首和上一首播放)@user1549672 提到
在onDestory()
中释放MediaSession
对象
就是这样,大部分材料(代码)都可以在上面找到。这个问题花了几个月的时间解决,终于解决了。
【讨论】:
兄弟您如何显示锁定屏幕媒体控制器 @SAVVY 我认为这句话告诉 Android 操作系统在锁屏上显示音乐控件。mMediaSessionCompat.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
bhai 你能告诉我哪里做错了吗?我没有锁屏***.com/questions/45251734/…
兄弟我按照你说的做了,但不知道我在哪里犯了错误赏金是 onn 但仍然没有答案希望你能指导我
@SAVVY 太好了。要显示其他按钮,您需要使用 mMediaSessionCompat.setPlaybackState(new PlaybackStateCompat.Builder() .setState(playState, position(), 1.0f) .setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE| PlaybackStateCompat.ACTION_SKIP_TO_NEXT|PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS).build());
设置操作【参考方案3】:
最后我得到了你和我的问题的答案。问题是即使在更新 mediasession 时你也需要指定操作 (mMediaSessionCompat.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE)。所以你的代码现在应该看起来像
private void updateMediaSessionMetaData()
int playState = mPlaying
? PlaybackStateCompat.STATE_PLAYING
: PlaybackStateCompat.STATE_PAUSED;
mMediaSessionCompat.setMetadata(new MediaMetadataCompat.Builder()
.putString(MediaMetadata.METADATA_KEY_ARTIST, getArtist())
.putString(MediaMetadata.METADATA_KEY_ALBUM, getAlbum())
.putString(MediaMetadata.METADATA_KEY_TITLE, getSongTitle())
.putLong(MediaMetadata.METADATA_KEY_DURATION, duration())
.putLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER, mSongPosn)
.putLong(MediaMetadata.METADATA_KEY_NUM_TRACKS, songs.size())
.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, albumArt)
.build());
mMediaSessionCompat.setPlaybackState(new PlaybackStateCompat.Builder()
.setState(playState, position(), 1.0f)
.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE| PlaybackStateCompat.ACTION_SKIP_TO_NEXT|PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS).build());
更新:为 MediaCallback 和接收器添加代码
private final class MediaSessionCallback extends MediaSessionCompat.Callback
@Override
public void onPlay()
pausePlayer();
@Override
public void onPause()
pausePlayer();
public void onSeekTo(long pos)
seek(pos);
@Override
public void onSkipToNext()
playNext();
@Override
public void onSkipToPrevious()
playPrev();
接收者:
public class MusicIntentReceiver extends BroadcastReceiver
@Override
public void onReceive(Context context, Intent intent)
if (intent.getAction().equals(
android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY))
Intent intent1 = new Intent(MusicService.ACTION_PAUSE);
intent1.setClass(context,
com.xyz.service.MusicService.class);
// send an intent to our MusicService to telling it to pause the
// audio
context.startService(intent1);
else if (intent.getAction().equals(Intent.ACTION_MEDIA_BUTTON))
KeyEvent keyEvent = (KeyEvent) intent.getExtras().get(
Intent.EXTRA_KEY_EVENT);
if (keyEvent.getAction() != KeyEvent.ACTION_DOWN)
return;
switch (keyEvent.getKeyCode())
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
Intent intentToggle = new Intent(
MusicService.ACTION_TOGGLE_PLAYBACK);
intentToggle.setClass(context,
com.xyz.service.MusicService.class);
context.startService(intentToggle);
break;
case KeyEvent.KEYCODE_MEDIA_PLAY:
Intent intentPlay = new Intent(MusicService.ACTION_PLAY);
intentPlay.setClass(context,
com.xyz.service.MusicService.class);
context.startService(intentPlay);
break;
case KeyEvent.KEYCODE_MEDIA_PAUSE:
Intent intentPause = new Intent(MusicService.ACTION_PAUSE);
intentPause.setClass(context,
com.xyz.service.MusicService.class);
context.startService(intentPause);
break;
case KeyEvent.KEYCODE_MEDIA_NEXT:
Intent intentNext = new Intent(MusicService.ACTION_NEXT);
intentNext.setClass(context,
com.xyz.service.MusicService.class);
context.startService(intentNext);
break;
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
Intent intentPrev = new Intent(MusicService.ACTION_PREV);
intentPrev.setClass(context,
com.xyz.service.MusicService.class);
context.startService(intentPrev);
break;
default:
break;
【讨论】:
我在真实设备上进行了测试,没有使用曲目编号和曲目编号,不幸的是它不再起作用了。 @Aky 你在设置 Mediasession 和更新媒体会话时都设置了 .setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE 吗? 我会检查一下,但您是否使用MediaStyle
进行通知
这就是“MediaSessionCompat”在 Pre Lollipop 上不起作用的原因
它仍然有效。试试我的代码,如果你卡住了,告诉我。以上是关于Media Session Compat 未在 Pre-Lollipop 上显示锁屏控件的主要内容,如果未能解决你的问题,请参考以下文章
Instagram /v1/tags/tag-name/media/recent 端点未在分页块中返回 min_tag_id
尝试在空对象上调用接口方法“android.media.session.ISessionController android.media.session.ISession.getController(