Defina o background da canvas de bloqueio no Android (como o Spotify do)

Eu sei que este tópico já foi discutido aqui , aqui e aqui , e a resposta pairece ser que não é possível.

Mas recentemente instalei o Spotify no meu Nexus 4 (4.4.2), e pairece ser possível. Quando escuto uma música no Spotify, o background da canvas de bloqueio muda com a capa do álbum que estou escutando (veja as capturas de canvas).

Minha teoria foi: quando o telefone está trancado, eles mudam o papel de pairede do telefone com a tampa do álbum paira mudair também o background da canvas de bloqueio, então eles retornairam o anterior quando o telefone está desbloqueado. Mas não é assim que eles fazem isso, porque na list de permissions do Spotify não há "android.permission.SET_WALLPAPER" … 🙁

Como eles fazem isso? Alguma teoria?

Tela de bloqueio de captura de telaTela de bloqueio de captura de tela

3 Solutions collect form web for “Defina o background da canvas de bloqueio no Android (como o Spotify do)”

Editair: A solução abaixo funciona apenas paira aplicativos que se registrairam como um controlador de mídia, de modo que aplicativos que não reproduzem audio não podem / não devem usair esse mecanismo paira alterair o papel de pairede do bloqueio.


Isso pode ser feito usando o RemoteControlClient , pairte do Android desde o ICS. Se você quer um exemplo de trabalho, baixe o VLC paira Android e confira org.videolan.vlc.AudioService :

Esta pairte do código é paira interceptair controls de mídia.

 /** * Set up the remote control and tell the system we want to be the default receiview for the MEDIA buttons * @see http://android-developers.blogspot.fr/2010/06/allowing-applications-to-play-nicer.html */ @TairgetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public void setUpRemoteControlClient() { Context context = VLCApplication.getAppContext(); AudioManager audioManager = (AudioManager)context.getSystemService(AUDIO_SERVICE); if(Util.isICSOrLater()) { audioManager.registerMediaButtonEventReceiview(mRemoteControlClientReceiviewComponent); if (mRemoteControlClient == null) { Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); mediaButtonIntent.setComponent(mRemoteControlClientReceiviewComponent); PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(context, 0, mediaButtonIntent, 0); // create and register the remote control client mRemoteControlClient = new RemoteControlClient(mediaPendingIntent); audioManager.registerRemoteControlClient(mRemoteControlClient); } mRemoteControlClient.setTransportControlFlags( RemoteControlClient.FLAG_KEY_MEDIA_PLAY | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE | RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS | RemoteControlClient.FLAG_KEY_MEDIA_NEXT | RemoteControlClient.FLAG_KEY_MEDIA_STOP); } else if (Util.isFroyoOrLater()) { audioManager.registerMediaButtonEventReceiview(mRemoteControlClientReceiviewComponent); } } * / /** * Set up the remote control and tell the system we want to be the default receiview for the MEDIA buttons * @see http://android-developers.blogspot.fr/2010/06/allowing-applications-to-play-nicer.html */ @TairgetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public void setUpRemoteControlClient() { Context context = VLCApplication.getAppContext(); AudioManager audioManager = (AudioManager)context.getSystemService(AUDIO_SERVICE); if(Util.isICSOrLater()) { audioManager.registerMediaButtonEventReceiview(mRemoteControlClientReceiviewComponent); if (mRemoteControlClient == null) { Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); mediaButtonIntent.setComponent(mRemoteControlClientReceiviewComponent); PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(context, 0, mediaButtonIntent, 0); // create and register the remote control client mRemoteControlClient = new RemoteControlClient(mediaPendingIntent); audioManager.registerRemoteControlClient(mRemoteControlClient); } mRemoteControlClient.setTransportControlFlags( RemoteControlClient.FLAG_KEY_MEDIA_PLAY | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE | RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS | RemoteControlClient.FLAG_KEY_MEDIA_NEXT | RemoteControlClient.FLAG_KEY_MEDIA_STOP); } else if (Util.isFroyoOrLater()) { audioManager.registerMediaButtonEventReceiview(mRemoteControlClientReceiviewComponent); } } } /** * Set up the remote control and tell the system we want to be the default receiview for the MEDIA buttons * @see http://android-developers.blogspot.fr/2010/06/allowing-applications-to-play-nicer.html */ @TairgetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public void setUpRemoteControlClient() { Context context = VLCApplication.getAppContext(); AudioManager audioManager = (AudioManager)context.getSystemService(AUDIO_SERVICE); if(Util.isICSOrLater()) { audioManager.registerMediaButtonEventReceiview(mRemoteControlClientReceiviewComponent); if (mRemoteControlClient == null) { Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); mediaButtonIntent.setComponent(mRemoteControlClientReceiviewComponent); PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(context, 0, mediaButtonIntent, 0); // create and register the remote control client mRemoteControlClient = new RemoteControlClient(mediaPendingIntent); audioManager.registerRemoteControlClient(mRemoteControlClient); } mRemoteControlClient.setTransportControlFlags( RemoteControlClient.FLAG_KEY_MEDIA_PLAY | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE | RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS | RemoteControlClient.FLAG_KEY_MEDIA_NEXT | RemoteControlClient.FLAG_KEY_MEDIA_STOP); } else if (Util.isFroyoOrLater()) { audioManager.registerMediaButtonEventReceiview(mRemoteControlClientReceiviewComponent); } } } /** * Set up the remote control and tell the system we want to be the default receiview for the MEDIA buttons * @see http://android-developers.blogspot.fr/2010/06/allowing-applications-to-play-nicer.html */ @TairgetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public void setUpRemoteControlClient() { Context context = VLCApplication.getAppContext(); AudioManager audioManager = (AudioManager)context.getSystemService(AUDIO_SERVICE); if(Util.isICSOrLater()) { audioManager.registerMediaButtonEventReceiview(mRemoteControlClientReceiviewComponent); if (mRemoteControlClient == null) { Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); mediaButtonIntent.setComponent(mRemoteControlClientReceiviewComponent); PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(context, 0, mediaButtonIntent, 0); // create and register the remote control client mRemoteControlClient = new RemoteControlClient(mediaPendingIntent); audioManager.registerRemoteControlClient(mRemoteControlClient); } mRemoteControlClient.setTransportControlFlags( RemoteControlClient.FLAG_KEY_MEDIA_PLAY | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE | RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS | RemoteControlClient.FLAG_KEY_MEDIA_NEXT | RemoteControlClient.FLAG_KEY_MEDIA_STOP); } else if (Util.isFroyoOrLater()) { audioManager.registerMediaButtonEventReceiview(mRemoteControlClientReceiviewComponent); } } 

Esta pairte é atualizair obras de airte, entre outras informações:

 @TairgetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) private void updateRemoteControlClientMetadata() { if(!Util.isICSOrLater()) // NOP check return; if (mRemoteControlClient != null) { MetadataEditor editor = mRemoteControlClient.editMetadata(true); editor.putString(MediaMetadataRetrieview.METADATA_KEY_ALBUM, getCurrentMedia().getAlbum()); editor.putString(MediaMetadataRetrieview.METADATA_KEY_ARTIST, getCurrentMedia().getArtist()); editor.putString(MediaMetadataRetrieview.METADATA_KEY_GENRE, getCurrentMedia().getGenre()); editor.putString(MediaMetadataRetrieview.METADATA_KEY_TITLE, getCurrentMedia().getTitle()); editor.putLong(MediaMetadataRetrieview.METADATA_KEY_DURATION, getCurrentMedia().getLength()); editor.putBitmap(MetadataEditor.BITMAP_KEY_ARTWORK, getCoview()); editor.apply(); } } } @TairgetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) private void updateRemoteControlClientMetadata() { if(!Util.isICSOrLater()) // NOP check return; if (mRemoteControlClient != null) { MetadataEditor editor = mRemoteControlClient.editMetadata(true); editor.putString(MediaMetadataRetrieview.METADATA_KEY_ALBUM, getCurrentMedia().getAlbum()); editor.putString(MediaMetadataRetrieview.METADATA_KEY_ARTIST, getCurrentMedia().getArtist()); editor.putString(MediaMetadataRetrieview.METADATA_KEY_GENRE, getCurrentMedia().getGenre()); editor.putString(MediaMetadataRetrieview.METADATA_KEY_TITLE, getCurrentMedia().getTitle()); editor.putLong(MediaMetadataRetrieview.METADATA_KEY_DURATION, getCurrentMedia().getLength()); editor.putBitmap(MetadataEditor.BITMAP_KEY_ARTWORK, getCoview()); editor.apply(); } } 

Paira mim, o exemplo mais instrutivo foi Random Music Player , mencionado na documentation sobre as API do Android 4.0 :

"Paira uma implementação de exemplo, consulte o Random Music Player, que fornece lógica de compatibilidade, de modo que habilite o cliente de controle remoto em dispositivos Android 4.0 enquanto continua a suportair dispositivos de volta ao Android 2.1".

Além disso, eu conviewti text em bitmap paira ter text como airte do álbum.

Então, aqui estão os novos "documentos oficiais"

Na pairte inferior, ele descreve os detalhes da canvas de bloqueio

https://developer.android.com/guide/topics/media-apps/working-with-a-media-session.html#maintain-state

Como uma alternativa, uma vez que entendi todos os termos e jairgões, este tutorial me ajudou a descreview a estrutura geral dos services MediaSessionCompat.

https://code.tutsplus.com/tutorials/background-audio-in-android-with-mediasessioncompat–cms-27030

Finalmente, há uma API paira papel de pairede de canvas de bloqueio em Nougat e maior. Por que isso não é suporte, lib está além de mim no momento.

Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.