Android:NotificationCompat.MediaStyle 操作按钮不执行任何操作

标签 android android-mediasession mediabrowserservicecompat android-notification.mediastyle

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

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

这是我生成通知的代码(抱歉,这是在 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 中设置适当的操作
  • 我正确设置了 session token 。
  • 我愿意 不是 将任何内容设置为 MediaButtonReceiver在我的 list 中,我也没有设置任何东西来处理android.intent.action.MEDIA_BUTTON ,因为我的目标是 Android 5.0 及更高版本并使用 *Compat类,我的理解是,这不再是必要的。

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

    我将不胜感激任何指示。

    更新:
    我让它工作了。我需要在 <application> 中添加以下内容 list 节点:
    <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>
    

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

    If you already have a MediaBrowserServiceCompat in your app, MediaButtonReceiver will deliver the received key events to the MediaBrowserServiceCompat by default. You can handle them in your MediaSessionCompat.Callback.



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

    但是,对于它的值(value),这对我有用。

    最佳答案

    可能您尚未设置操作。查看下面的代码,它显示了如何将按钮与 Intent 绑定(bind)。请为需要 channel 的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);
        }
    }
    

    关于Android:NotificationCompat.MediaStyle 操作按钮不执行任何操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60941269/

    相关文章:

    android - Android 媒体 Controller 与传输控件的区别

    android - AbstractMethodError : abstract method "void android. 媒体.RemoteController$OnClientUpdateListener.onClientSessionEvent

    PHP 脚本不工作,除了连接

    ubuntu下安卓模拟器没有声音

    android - VLC : Cant Play Video from getExternalStorageDirectory()

    java - 在哪里创建音乐播放器服务 w.r.t.媒体浏览器服务兼容

    安卓小部件 : skip_to_next and skip_to_previous buttons don't work

    android - 如何在android中制作圆弧

    android - MediaMetadataCompat METADATA_KEY_ART 仅在第一次设置图像

    android - 重新将服务附加到 Activity ?