【问题标题】:Android: NotificationCompat.MediaStyle action buttons don't do anythingAndroid:NotificationCompat.MediaStyle 操作按钮不执行任何操作
【发布时间】:2020-07-11 10:54:40
【问题描述】:

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

我的挑战是出现在锁定屏幕和通知托盘中的NotificationCompat.MediaStyle 通知。通知正确显示。但是,当我使用addAction()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 及更高版本并使用@ 987654335@ classes,我的理解是不再需要。

我知道媒体按钮事件已正确路由到我的应用程序,因为我的蓝牙耳机按钮工作。我在我的车上试过,它也在那里工作。 只是通知中的按钮不起作用。我希望它们能够调用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的Service的节点内的以下内容:

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

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

如果您的应用中已有MediaBrowserServiceCompatMediaButtonReceiver 将接收到的关键事件传递给 MediaBrowserServiceCompat 默认情况下。你可以在你的 MediaSessionCompat.Callback.

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

但是,无论如何,这对我有用。

【问题讨论】:

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


    【解决方案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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多