在安卓系统中设置锁屏背景(像Spotify一样)

25

我知道这个话题已经在这里这里这里讨论过了,答案似乎是不可能的。

但是,我最近在我的Nexus 4(4.4.2)上安装了Spotify,它似乎是可能的。当我在Spotify中听歌时,锁屏背景会随着我正在听的专辑封面而改变(请参见截屏)。

我的理论是: 当手机被锁定时,他们更改手机壁纸,用专辑封面来改变锁屏背景,然后当手机被解锁时,他们将其设置回之前的状态。但是这不是他们的做法,因为在Spotify的权限列表中没有“android.permission.SET_WALLPAPER”...:(

他们是如何做到的?有什么理论吗?

截屏锁屏 截屏锁屏

6个回答

12

编辑: 下面的解决方案仅适用于已将自身注册为媒体控制器的应用程序,因此不播放音频的应用程序不能/不应使用此机制更改锁屏壁纸。


可以使用 Android 自 ICS 以来的 RemoteControlClient 完成此操作。如果您想要一个可用的示例,请下载 VLC for Android 并查看 org.videolan.vlc.AudioService

这部分代码是拦截媒体控件。

/**
 * Set up the remote control and tell the system we want to be the default receiver for the MEDIA buttons
 * @see http://android-developers.blogspot.fr/2010/06/allowing-applications-to-play-nicer.html
 */
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public void setUpRemoteControlClient() {
    Context context = VLCApplication.getAppContext();
    AudioManager audioManager = (AudioManager)context.getSystemService(AUDIO_SERVICE);

    if(Util.isICSOrLater()) {
        audioManager.registerMediaButtonEventReceiver(mRemoteControlClientReceiverComponent);

        if (mRemoteControlClient == null) {
            Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
            mediaButtonIntent.setComponent(mRemoteControlClientReceiverComponent);
            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.registerMediaButtonEventReceiver(mRemoteControlClientReceiverComponent);
    }
}

此部分用于更新艺术品等信息:

@TargetApi(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(MediaMetadataRetriever.METADATA_KEY_ALBUM, getCurrentMedia().getAlbum());
        editor.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, getCurrentMedia().getArtist());
        editor.putString(MediaMetadataRetriever.METADATA_KEY_GENRE, getCurrentMedia().getGenre());
        editor.putString(MediaMetadataRetriever.METADATA_KEY_TITLE, getCurrentMedia().getTitle());
        editor.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, getCurrentMedia().getLength());
        editor.putBitmap(MetadataEditor.BITMAP_KEY_ARTWORK, getCover());
        editor.apply();
    }
}

有没有一种方法可以更新图片的大小,使其不是全屏显示? - jmnwong
1
@canistr 我不能百分之百确定,但由于应用程序仅提供位图而无法提供相关参数,我认为答案是否定的。 - Kai
有没有办法在歌曲没有封面的情况下清除封面图像并设置手机默认锁屏?我的问题是上一首歌曲的旧封面仍然显示。 - AndrewS
@AndrewS 当前歌曲没有封面时,您可以提供一个默认的位图,这基本上就是Google音乐正在做的事情。 - Kai
工具类在哪里? - Bipin Bharti
显示剩余2条评论

1

好的,经过尝试,我有一个简单的代码在这里; 尝试使用这种方法;

private void updateMetaData() {
    mediaSession =new MediaSessionCompat(context,"BXPlayer");

    Bitmap cover = BitmapFactory.decodeResource(context.getResources(),
            R.drawable.cover2); 

   mediaSession.setMetadata(new MediaMetadataCompat.Builder()
            .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, cover)
            .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, mSelectedSong.getArtist())
            .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, mSelectedSong.getAlbum())
            .putString(MediaMetadataCompat.METADATA_KEY_TITLE, mSelectedSong.getTitle())
            .build());
}

然后在您的通知中,您需要将样式设置为android.support.v4.media.app.NotificationCompat.MediaStyle()并将媒体会话令牌设置为使用当前元数据。 请检查下面的代码片段;

builder.setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle()
            .setShowActionsInCompactView(0, 1, 2)
    .setMediaSession(mediaSession.getSessionToken()));
    return builder.build();

要使其正常工作,您必须在应用程序的 build.gradle 中包含 implementation "com.android.support:support-v4:$latest_version"。 然后,您就可以开始了。

mediasession.getSessionToken 实际上我不理解如何设置这种类型的通知,请查看链接 https://stackoverflow.com/questions/54633202/how-to-set-mediaplayer-notification-with-mediasession-and-notificationcompat-med?noredirect=1#comment96070177_54633202 - Vipul Chauhan
@VipulChauhan,我已将我的项目迁移到Kotlin,但我重新创建了一段代码,涵盖了你在另一个测验中所要求的内容。请在此处检查此代码:https://github.com/carloscj6/MusicPlayerService/blob/master/MediaPlayerService.java。 - Carlos Anyona
你的代码对于新开发人员来说太难理解了,请你能否提供适当的解释,例如:在哪里使用这些方法?如何展示和处理操作? 先行致谢。 - Vipul Chauhan
1
@VipulChauhan 自从我将我的初始项目迁移到Kotlin后,我又用Java编写了另一个项目,并在此处上传了整个源代码:https://github.com/carloscj6/SampleMusicPlayer。同时,我正在努力发布一份详细的教程,希望这能对你有所帮助。干杯! - Carlos Anyona
这对我有用,但并没有完全解决我的问题,因为它需要最低SDK 21,仍然无法在锁屏界面上显示控件,也无法更改锁屏背景,请添加一些SDK问题的代码。 - Vipul Chauhan
显示剩余4条评论

1

对我来说,最有启示性的例子是随机音乐播放器,它被提及在Android 4.0 API文档中:

"要查看示例实现,请参见随机音乐播放器,它提供了兼容逻辑,使其在Android 4.0设备上启用远程控制客户端的同时,继续支持从Android 2.1开始的设备。"

此外,我将文本转换为位图以将文本作为专辑艺术品。


这应该是新的被接受的答案,因为远程控制客户端现在已经过时了。 - JoshuaTree

0

此处所解释的那样,关键是将MediaMetadata对象传递给您的MediaSession。如果这些术语对您来说很陌生,最好从链接的教程顶部开始。

我发现.putBitmap(MediaMetadata.METADATA_KEY_ART, bitmap)行是用于加载图像到锁屏背景的代码行。但一定要填充.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, bitmap)


0

这里是新的“官方文档”

底部描述了锁屏细节

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

作为一种替代方案,一旦我理解了所有术语和行话,这个教程帮助我概述了MediaSessionCompat服务的一般结构。

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

最终,在Nougat及更高版本中,有一个锁屏壁纸的API。为什么这不支持库,目前我还不清楚。


0
我知道这有点晚了,但仍需要完美的答案。要在Android中设置锁屏背景(就像Spotify一样),我们必须执行以下步骤。
1. 设置媒体会话活动状态 mSession.setActive(true)。如果会话未处于活动状态,则不会显示。
2. 设置播放状态。
playBackStateBuilder = new PlaybackStateCompat.Builder()
            .setActions(PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_SKIP_TO_NEXT
                    | PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
                    | PlaybackStateCompat.ACTION_STOP | PlaybackStateCompat.ACTION_PLAY_PAUSE);`

`mSession.setPlaybackState(playBackStateBuilder.setState(PlaybakStateCompate.STATE_PLAYING, 0, 0).build());

注意:当第一次播放状态设置为播放时,锁屏图像会显示,然后可以切换到其他状态。

3. 设置元数据

mSession.setMetadata(new MediaMetadataCompat.Builder()
                .putString(MediaMetadataCompat.METADATA_KEY_TITLE, title)
                .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist)
                .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap)
                .build());

在编程中,KEY_ALBUM_ART是必需的,因为它是在锁屏界面上显示的图片。

通过设置以上三个内容,它已经在我的Galaxy设备上显示了,但在Pixel设备上没有显示,因此需要遵循最后一个步骤。

4. 使用媒体样式显示通知

NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, CHANNEL_ID);
    builder.setStyle(
            new androidx.media.app.NotificationCompat.MediaStyle()
    );
    
    mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.notify(121, builder.build());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接