6

我有一个简单的 Android 应用程序,其中包含一个Activity和一个Service派生自MediaBrowserServiceCompat. 我已经成功地将它设置为通过使用MediaBrowserCompat和播放我的主要活动中的音频MediaControllerCompat。它甚至可以播放和暂停我的蓝牙耳机的音频。都好。

我的挑战涉及NotificationCompat.MediaStyle出现在锁定屏幕和通知托盘中的通知。通知正确显示。addAction()但是,当我使用and添加按钮时MediaButtonReceiver.buildMediaButtonPendingIntent,它们什么都不做。如果我改为添加一个虚拟 PendingIntent 来启动我的主要活动,那效果很好。

这是我生成通知的代码(抱歉,这是在 Xamarin 中运行的 C#,因此大小写和名称将与您的预期略有不同)。这是在我的服务类里面。

var builder = new NotificationCompat.Builder(this, CHANNEL_ID)
    .SetVisibility(NotificationCompat.VisibilityPublic)
    .SetSmallIcon(Resource.Drawable.ic_launcher)
    .SetContentTitle("Title")
    .SetContentText("Content")
    .SetSubText("Subtext")
    .SetLargeIcon(icon)
    .SetColor(Android.Graphics.Color.DarkOrange)

    .SetContentIntent(intent)
    .SetDeleteIntent(MediaButtonReceiver.BuildMediaButtonPendingIntent(this, PlaybackStateCompat.ActionStop))

    .AddAction(new NotificationCompat.Action(
        Resource.Drawable.ic_pause, "Pause",
        MediaButtonReceiver.BuildMediaButtonPendingIntent(this, PlaybackStateCompat.ActionPause)))

    .SetStyle(new Android.Support.V4.Media.App.NotificationCompat.MediaStyle()
        .SetShowActionsInCompactView(0)
        .SetMediaSession(this.mediaSession.SessionToken)
        .SetShowCancelButton(true)
        .SetCancelButtonIntent(MediaButtonReceiver.BuildMediaButtonPendingIntent(this, PlaybackStateCompat.ActionStop))
    );

this.StartForeground(NOTIFICATION_ID, builder.Build());

到目前为止,这是我试图解决这个问题的方法:

  • 当我开始播放时,我使用MediaSession.setActive(true)
  • 每次开始和停止播放时,我都会在PlaybackStateCompat
  • 我正确设置了会话令牌。
  • 我的清单中没有设置MediaButtonReceiver任何东西,也没有设置任何东西来处理android.intent.action.MEDIA_BUTTON,因为我的目标是 Android 5.0 及更高版本并使用这些*Compat类,我的理解是不再需要。

我知道媒体按钮事件正在正确路由到我的应用程序,因为我的蓝牙耳机按钮工作。我在我的车上试过,它也在那里工作。只是通知中的按钮不起作用。我期待他们生成对MediaSessionCompat.Callback. 这是不正确的吗?我在这里做错了什么?

我将不胜感激任何指示。


更新: 我让它工作了。我需要<application>在清单的节点中添加以下内容:

<receiver android:name="android.support.v4.media.session.MediaButtonReceiver">
    <intent-filter>
        <action android:name="android.intent.action.MEDIA_BUTTON" />
    </intent-filter>
</receiver>

...以及实现的服务节点内的以下内容MediaBrowserServiceCompat

<intent-filter>
    <action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>

我仍然有点困惑为什么这是必要的,因为我的蓝牙耳机和汽车信息娱乐系统的按钮按下都很好地路由到了应用程序。更重要的是,谷歌

MediaBrowserServiceCompat如果您的应用程序中 已经有一个,默认情况下MediaButtonReceiver会将接收到的关键事件传递给 MediaBrowserServiceCompat。你可以在你的 MediaSessionCompat.Callback.

他们将此作为选项“服务处理 ACTION_MEDIA_BUTTON”的替代方案,所以我认为这意味着我不需要对清单做更多的事情。如果有人可以在这里启发我,我将不胜感激。

但是,对于它的价值,这对我有用。

4

1 回答 1

1

可能您尚未设置操作。查看下面的代码,它显示了如何将按钮与意图绑定。请为需要频道的android O设备修改它。

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.support.v7.app.NotificationCompat;

/**
 * Keeps track of a notification and updates it automatically for a given MediaSession. This is
 * required so that the music service don't get killed during playback.
 */
public class MediaNotificationManager extends BroadcastReceiver {
    private static final int NOTIFICATION_ID = 412;
    private static final int REQUEST_CODE = 100;

    private static final String ACTION_PAUSE = "com.example.android.musicplayercodelab.pause";
    private static final String ACTION_PLAY = "com.example.android.musicplayercodelab.play";
    private static final String ACTION_NEXT = "com.example.android.musicplayercodelab.next";
    private static final String ACTION_PREV = "com.example.android.musicplayercodelab.prev";

    private final MusicService mService;

    private final NotificationManager mNotificationManager;

    private final NotificationCompat.Action mPlayAction;
    private final NotificationCompat.Action mPauseAction;
    private final NotificationCompat.Action mNextAction;
    private final NotificationCompat.Action mPrevAction;

    private boolean mStarted;

    public MediaNotificationManager(MusicService service) {
        mService = service;

        String pkg = mService.getPackageName();
        PendingIntent playIntent =
                PendingIntent.getBroadcast(
                        mService,
                        REQUEST_CODE,
                        new Intent(ACTION_PLAY).setPackage(pkg),
                        PendingIntent.FLAG_CANCEL_CURRENT);
        PendingIntent pauseIntent =
                PendingIntent.getBroadcast(
                        mService,
                        REQUEST_CODE,
                        new Intent(ACTION_PAUSE).setPackage(pkg),
                        PendingIntent.FLAG_CANCEL_CURRENT);
        PendingIntent nextIntent =
                PendingIntent.getBroadcast(
                        mService,
                        REQUEST_CODE,
                        new Intent(ACTION_NEXT).setPackage(pkg),
                        PendingIntent.FLAG_CANCEL_CURRENT);
        PendingIntent prevIntent =
                PendingIntent.getBroadcast(
                        mService,
                        REQUEST_CODE,
                        new Intent(ACTION_PREV).setPackage(pkg),
                        PendingIntent.FLAG_CANCEL_CURRENT);

        mPlayAction =
                new NotificationCompat.Action(
                        R.drawable.ic_play_arrow_white_24dp,
                        mService.getString(R.string.label_play),
                        playIntent);
        mPauseAction =
                new NotificationCompat.Action(
                        R.drawable.ic_pause_white_24dp,
                        mService.getString(R.string.label_pause),
                        pauseIntent);
        mNextAction =
                new NotificationCompat.Action(
                        R.drawable.ic_skip_next_white_24dp,
                        mService.getString(R.string.label_next),
                        nextIntent);
        mPrevAction =
                new NotificationCompat.Action(
                        R.drawable.ic_skip_previous_white_24dp,
                        mService.getString(R.string.label_previous),
                        prevIntent);

        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_NEXT);
        filter.addAction(ACTION_PAUSE);
        filter.addAction(ACTION_PLAY);
        filter.addAction(ACTION_PREV);

        mService.registerReceiver(this, filter);

        mNotificationManager =
                (NotificationManager) mService.getSystemService(Context.NOTIFICATION_SERVICE);

        // Cancel all notifications to handle the case where the Service was killed and
        // restarted by the system.
        mNotificationManager.cancelAll();
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
        switch (action) {
            case ACTION_PAUSE:
                mService.mCallback.onPause();
                break;
            case ACTION_PLAY:
                mService.mCallback.onPlay();
                break;
            case ACTION_NEXT:
                mService.mCallback.onSkipToNext();
                break;
            case ACTION_PREV:
                mService.mCallback.onSkipToPrevious();
                break;
        }
    }

    public void update(
            MediaMetadataCompat metadata,
            PlaybackStateCompat state,
            MediaSessionCompat.Token token) {
        if (state == null
                || state.getState() == PlaybackStateCompat.STATE_STOPPED
                || state.getState() == PlaybackStateCompat.STATE_NONE) {
            mService.stopForeground(true);
            try {
                mService.unregisterReceiver(this);
            } catch (IllegalArgumentException ex) {
                // ignore receiver not registered
            }
            mService.stopSelf();
            return;
        }
        if (metadata == null) {
            return;
        }
        boolean isPlaying = state.getState() == PlaybackStateCompat.STATE_PLAYING;
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(mService);
        MediaDescriptionCompat description = metadata.getDescription();

        notificationBuilder
                .setStyle(
                        new NotificationCompat.MediaStyle()
                                .setMediaSession(token)
                                .setShowActionsInCompactView(0, 1, 2))
                .setColor(
                        mService.getApplication().getResources().getColor(R.color.notification_bg))
                .setSmallIcon(R.drawable.ic_notification)
                .setVisibility(Notification.VISIBILITY_PUBLIC)
                .setContentIntent(createContentIntent())
                .setContentTitle(description.getTitle())
                .setContentText(description.getSubtitle())
                .setLargeIcon(MusicLibrary.getAlbumBitmap(mService, description.getMediaId()))
                .setOngoing(isPlaying)
                .setWhen(isPlaying ? System.currentTimeMillis() - state.getPosition() : 0)
                .setShowWhen(isPlaying)
                .setUsesChronometer(isPlaying);

        // If skip to next action is enabled
        if ((state.getActions() & PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS) != 0) {
            notificationBuilder.addAction(mPrevAction);
        }

        notificationBuilder.addAction(isPlaying ? mPauseAction : mPlayAction);

        // If skip to prev action is enabled
        if ((state.getActions() & PlaybackStateCompat.ACTION_SKIP_TO_NEXT) != 0) {
            notificationBuilder.addAction(mNextAction);
        }

        Notification notification = notificationBuilder.build();

        if (isPlaying && !mStarted) {
            mService.startService(new Intent(mService.getApplicationContext(), MusicService.class));
            mService.startForeground(NOTIFICATION_ID, notification);
            mStarted = true;
        } else {
            if (!isPlaying) {
                mService.stopForeground(false);
                mStarted = false;
            }
            mNotificationManager.notify(NOTIFICATION_ID, notification);
        }
    }

    private PendingIntent createContentIntent() {
        Intent openUI = new Intent(mService, MusicPlayerActivity.class);
        openUI.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        return PendingIntent.getActivity(
                mService, REQUEST_CODE, openUI, PendingIntent.FLAG_CANCEL_CURRENT);
    }
}
于 2020-03-31T23:36:39.583 回答