notification icon android android-mediaplayer android-5.0-lollipop lockscreen

android - icon - api level 26



Media Session Compat no muestra los controles de Lockscreen en Pre-Lollipop (3)

Estoy usando MediaSessionCompat desde AppCompat Support Library Revisión 22. Y en Lollipop recibo notificación y también el fondo de lockscreen es la portada del álbum. Y todo funciona genial.

Mientras está en dispositivos Pre-Lollipop, los controles de música en la pantalla de bloqueo no se muestran en absoluto. Es raro y lo intenté todo, pero no aparece, ni siquiera el fondo cambia.

Espero que alguien tenga una solución a este problema.

Nota: RemoteControlClient solía trabajar en Lollipop y 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();

Aquí está la 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());

}

Los métodos de devolución de llamada de Media Session

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 Manifest Entry

<!-- 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>

Desde hace un par de semanas trato de resolver este problema sin éxito y con una necesidad desesperada de ayuda.

Editar: Un tutorial o ejemplo de MediaSessionCompat también estaría bien


Finalmente recibí una respuesta a su problema y el mío. De todas formas, debe especificar las acciones (mMediaSessionCompat.setActions (PlaybackStateCompat.ACTION_PLAY_PAUSE) incluso mientras actualiza la sesión media. Por lo tanto, su código debería verse ahora como

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());

ACTUALIZACIÓN: código agregado para MediaCallback & Receiver

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(); } }

Receptor:

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; } } } }


Finalmente, pensé en una solución para esto. Gracias a ianhanniballake & @user1549672

  1. Agregue Audio Focus según lo sugerido por ianhanniballake
  2. Agregue Music Intent BroadcastReceiver se puede encontrar si se busca en Google y también en Official Android Docs
  3. Escriba setupMediaSession() dado en mi pregunta anterior
  4. MUY IMPORTANTE Mencione los Flags adecuadamente
  5. Escribir MediaSessionCallbacks también disponible arriba
  6. MUY IMPORTANTE Actualice MediaSession en MediaPlayer#onPause() , MediaPlayer#onStart() y finalmente cuando se reproduzca una nueva canción (también incluye el siguiente y el anterior) mencionado por @user1549672
  7. Libere el objeto onDestory() en onDestory()

Bueno, eso es todo, la mayor parte del material (código) está disponible arriba. Esta pregunta tardó un par de meses en resolverse, finalmente se hizo.


Si bien no es estrictamente necesario para MediaSession , RemoteControlClient utiliza en dispositivos API14-19, requiere un enfoque de audio y es 100% muy recomendable para la reproducción de todos los medios.

Agregar líneas como:

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 }

Antes de reproducir cualquier medio, debe obtener el enfoque de audio y mostrar los controles.