1

我的 Android 应用程序用于远程控制媒体播放器(PC 上的 Winamp)。为了让用户即使在 Android 应用当前未处于活动状态时也能控制远程播放器,它使用了与后台服务和系统通知相关联的 MediaSession。系统通知使用 DecoratedMediaCustomViewStyle 样式,我使用 setCustomContentView() 和 setCustomBigContentView() 方法设置自定义视图。我使用 VolumeProviderCompat 在 MediaSession 上调用 setPlaybackToRemote()。这是一个重要的区别,因为媒体不是在 Android 设备上播放,而是在远程设备上播放。不,它不是 Chromecast,完全不同的东西(PC 上的 Winamp 使用自定义协议)。

这一切都适用于 11 (API 30) 之前的 Android 版本。但在 Android 11 上,自定义视图(“常规”和“大”)被完全忽略。以下是“大”通知的屏幕截图,位于 API 27 顶部(与 API 28 和 29 相同),然后是 API 30。

Ampwifi 通知 API 27

Ampwifi 通知 API 30

请注意,顶部没有两次提及“Ampwifi”,右侧有一个“X”按钮。这个“X”按钮很重要,因为它允许用户关闭通知并关闭后台服务。

我搜索了文档和 Android 11 更改日志,但没有找到任何相关信息。我还有一个来自 Android “R” 预发行版的旧 AVD 图像,它也像在 API 29 和更早版本中一样工作。我想知道这是否确实是Android的错误?如果没有,是否有其他人遇到过这个问题,并且有人对如何解决这个问题有任何建议?

我尝试过的一件事就是不将 MediaSession 与通知相关联。这实际上恢复了自定义视图,但我失去了 MediaSession 的所有好处(蓝牙/谷歌助手集成和通知操作按钮的自动着色)。所以解决这个问题真的很好。

这是一些代码:

/////

final ConnectionProfile profile = mSettings.getActiveConnectionProfile();
final String profileName = profile != null ? profile.name : "";
final RemoteViews contentView = getContent(profileName);
final RemoteViews bigContentView = getBigContent(profileName);

final NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(ServiceBackgroundMediapPlayer.this, NotificationChannelBackgroundMediaPlayerServiceId)
        .setColorized(true)
        .setOngoing(true)
        .setAutoCancel(false)
        .setContentIntent(getDefaultIntent())
        .setDeleteIntent(getDeleteIntent())
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setSmallIcon(R.drawable.ic_notification)
        .setLargeIcon(getBitmap())
        .setContentTitle("Ampwifi")
        .setContentText(profileName)
        .addAction(R.drawable.ic_media_previous, null, MediaButtonReceiver.buildMediaButtonPendingIntent(ServiceBackgroundMediapPlayer.this, PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS))
        .addAction(R.drawable.ic_media_play, null, MediaButtonReceiver.buildMediaButtonPendingIntent(ServiceBackgroundMediapPlayer.this, PlaybackStateCompat.ACTION_PLAY))
        .addAction(R.drawable.ic_media_pause, null, MediaButtonReceiver.buildMediaButtonPendingIntent(ServiceBackgroundMediapPlayer.this, PlaybackStateCompat.ACTION_PAUSE))
        .addAction(R.drawable.ic_media_stop, null, MediaButtonReceiver.buildMediaButtonPendingIntent(ServiceBackgroundMediapPlayer.this, PlaybackStateCompat.ACTION_STOP))
        .addAction(R.drawable.ic_media_next, null, MediaButtonReceiver.buildMediaButtonPendingIntent(ServiceBackgroundMediapPlayer.this, PlaybackStateCompat.ACTION_SKIP_TO_NEXT))
        .setStyle(getStyle())
        .setCustomContentView(contentView)
        .setCustomBigContentView(bigContentView)
        .setOnlyAlertOnce(true);

mNotification = notificationBuilder.build();

NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

notificationManager.notify(R.id.ServiceBackgroundMediapPlayerNotification, mNotification);


/////

public NotificationCompat.Style getStyle() {
    return new androidx.media.app.NotificationCompat.DecoratedMediaCustomViewStyle()
        .setShowCancelButton(true)
        .setCancelButtonIntent(getDeleteIntent())
        .setShowActionsInCompactView(1, 2, 4)
        .setMediaSession(getMediaSessionToken());
}

public RemoteViews getContent(String title) {
    final RemoteViews layout = new RemoteViews("com.blitterhead.ampwifi", R.layout.notification_media);

    if (layout != null) {
        layout.setTextViewText(R.id.title, title);
    }

    return layout;
}


public RemoteViews getBigContent(String title) {
    final RemoteViews layout = new RemoteViews("com.blitterhead.ampwifi", R.layout.notification_media_big);

    if (layout != null) {
        layout.setTextViewText(R.id.title, title);
        layout.setOnClickPendingIntent(R.id.dismiss, getDeleteIntent());
    }

    return layout;
}

private MediaSessionCompat.Token getMediaSessionToken() {
    if (_mediaSessionToken == null) {
        PlaybackStateCompat playbackState = mPlaybackStateBuilder
                .setActiveQueueItemId(1)
                .setActions(PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_STOP | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS | PlaybackStateCompat.ACTION_SKIP_TO_NEXT)
                .setState(PlaybackStateCompat.STATE_PLAYING, 0, 1.0f)
                .build();

        ComponentName mediaButtonReceiver = new ComponentName(getApplicationContext(), MediaButtonReceiver.class);
        mMediaSession = new MediaSessionCompat(ServiceBackgroundMediapPlayer.this, MediaSessionTag, mediaButtonReceiver, null);
        mMediaSession.setPlaybackState(playbackState);
        mMediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
        mMediaSession.setMetadata(getMetaData());
        mMediaSession.setCallback(getMediaSessionCallback());
        mMediaSession.setActive(true);

        if (mSettings.getBackgroundMediaVolume()) {
            mMediaSession.setPlaybackToRemote(getVolumeProvider());
        }

        _mediaSessionToken = mMediaSession.getSessionToken();

        setSessionToken(_mediaSessionToken);
    }

    return _mediaSessionToken;
}
4

0 回答 0