MediaSession没有从MediaStyle通知中获得任何回调



我创建了一个扩展MediaBrowserServiceCompat的服务。该服务对我的播放器有一个引用,并通过回调创建了新的传播。每次玩家更改状态时,我都会更新MediaSession的播放状态,并创建媒体风格通知。该通知显示了我开始在玩家中播放某些内容时显示的,但是通知中的按钮并没有触发MediaSession回调,而是什么都不做。我正在在MediaSession中设置正确的标志,我将会话设置为活动,我正在在播放状态下设置正确的操作,我将会话令牌传递给了通知,但仍未从中获得任何回调。我真的不知道我在做什么错。所有这些代码都位于我的应用程序导入的模块内。

我的NotificationHelper类:

private final MusicService mService;
private final NotificationCompat.Action mPlayAction;
private final NotificationCompat.Action mPauseAction;
private final NotificationCompat.Action mNextAction;
private final NotificationCompat.Action mPrevAction;
private final NotificationManager mNotificationManager;
public MediaNotificationManager(MusicService service) {
    mService = service;
    mNotificationManager =
            (NotificationManager) mService.getSystemService(Context.NOTIFICATION_SERVICE);
    mPlayAction =
            new NotificationCompat.Action(
                    R.drawable.exo_icon_play,
                    "Play",
                    MediaButtonReceiver.buildMediaButtonPendingIntent(
                            mService,
                            PlaybackStateCompat.ACTION_PLAY));
    mPauseAction =
            new NotificationCompat.Action(
                    R.drawable.exo_icon_pause,
                    "Pause",
                    MediaButtonReceiver.buildMediaButtonPendingIntent(
                            mService,
                            PlaybackStateCompat.ACTION_PAUSE));
    mNextAction =
            new NotificationCompat.Action(
                    R.drawable.exo_icon_next,
                    "Next",
                    MediaButtonReceiver.buildMediaButtonPendingIntent(
                            mService,
                            PlaybackStateCompat.ACTION_SKIP_TO_NEXT));
    mPrevAction =
            new NotificationCompat.Action(
                    R.drawable.exo_icon_previous,
                    "Previous",
                    MediaButtonReceiver.buildMediaButtonPendingIntent(
                            mService,
                            PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS));
    // Cancel all notifications to handle the case where the Service was killed and
    // restarted by the system.
    mNotificationManager.cancelAll();
}
public Notification getNotification(MediaMetadataCompat metadata,
                                    @NonNull PlaybackStateCompat state,
                                    MediaSessionCompat.Token token) {
    boolean isPlaying = state.getState() == PlaybackStateCompat.STATE_PLAYING;
    MediaDescriptionCompat description = metadata.getDescription();
    NotificationCompat.Builder builder =
            buildNotification(state, token, isPlaying, description);
    return builder.build();
}
private NotificationCompat.Builder buildNotification(@NonNull PlaybackStateCompat state,
                                                     MediaSessionCompat.Token token,
                                                     boolean isPlaying,
                                                     MediaDescriptionCompat description) {
    // Create the (mandatory) notification channel when running on Android Oreo.
    if (isAndroidOOrHigher()) {
        createChannel();
    }
    NotificationCompat.Builder builder = new NotificationCompat.Builder(mService, CHANNEL_ID)
            .setSmallIcon(R.drawable.exo_notification_small_icon)
            .setContentTitle("Track title")
            .setContentText("Artist - Album")
            .setLargeIcon(BitmapFactory.decodeResource(mService.getResources(), R.drawable.exo_notification_small_icon))
            .setStyle(new MediaStyle().setShowActionsInCompactView(0).setMediaSession(token));

    builder.addAction(mPrevAction);
    builder.addAction(isPlaying ? mPauseAction : mPlayAction);
    builder.addAction(mNextAction);
    return builder;
}
// Does nothing on versions of Android earlier than O.
@RequiresApi(Build.VERSION_CODES.O)
private void createChannel() {
    if (mNotificationManager.getNotificationChannel(CHANNEL_ID) == null) {
        // The user-visible name of the channel.
        CharSequence name = "MediaSession";
        // The user-visible description of the channel.
        String description = "MediaSession and MediaPlayer";
        int importance = NotificationManager.IMPORTANCE_LOW;
        NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, importance);
        // Configure the notification channel.
        mChannel.setDescription(description);
        mChannel.enableLights(true);
        // Sets the notification light color for notifications posted to this
        // channel, if the device supports this feature.
        mChannel.setLightColor(Color.RED);
        mChannel.enableVibration(true);
        mChannel.setVibrationPattern(
                new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
        mNotificationManager.createNotificationChannel(mChannel);
        Log.d(TAG, "createChannel: New channel created");
    } else {
        Log.d(TAG, "createChannel: Existing channel reused");
    }
}
private boolean isAndroidOOrHigher() {
    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
}

我的服务课:

public class MusicService extends MediaBrowserServiceCompat {
private static final String TAG = MusicService.class.getSimpleName();
private MediaSessionCompat mSession;
private PlayerManager playerManager;
private MediaSessionCallback mCallback;
private MediaNotificationManager mediaNotificationManager;
@Override
public void onCreate() {
    super.onCreate();
    playerManager = PlayerManager.getInstance(this);
    playerManager.addListener(new PlayerManagerServiceListener());
    mediaNotificationManager = new MediaNotificationManager(this);
    // Create a new MediaSession.
    mSession = new MediaSessionCompat(this, "MusicService");
    mCallback = new MediaSessionCallback();
    mSession.setCallback(mCallback);
    mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
    setSessionToken(mSession.getSessionToken());
    mSession.setActive(true);
}
@Override
public void onDestroy() {
    mSession.release();
    Log.d(TAG, "onDestroy: MediaPlayerAdapter stopped, and MediaSession released");
}
@Override
public BrowserRoot onGetRoot(@NonNull String clientPackageName,
                             int clientUid,
                             Bundle rootHints) {
    return new BrowserRoot("root", null);
}
@Override
public void onLoadChildren(
        @NonNull final String parentMediaId,
        @NonNull final Result<List<MediaBrowserCompat.MediaItem>> result) {
    result.sendResult(null);
}
// MediaSession Callback: Transport Controls -> MediaPlayerAdapter
public class MediaSessionCallback extends MediaSessionCompat.Callback {
    @Override
    public void onPlay() {
        playerManager.play();
    }
    @Override
    public void onPause() {
        playerManager.pause();
    }
    @Override
    public void onStop() {
       playerManager.stop();
    }
    @Override
    public void onSkipToNext() {
        playerManager.next();
    }
    @Override
    public void onSkipToPrevious() {
        playerManager.previous();
    }
    @Override
    public void onSeekTo(long pos) {
        playerManager.seekTo(pos);
    }
}
public class PlayerManagerServiceListener implements PlayerManager.PlayerManagerListener {
    @Override
    public void onError(@Nullable Exception error) {
    }
    @Override
    public void onProgress(long duration, long position) {
    }
    @Override
    public void onPlayerChange(int change) {
    }
    @Override
    public void onTrackChange(TrackVO track) {
    }
    @Override
    public void onListChange(List tracks) {
    }
    @Override
    public void onPlaybackStateChange(int playbackState) {
        PlaybackStateCompat.Builder playbackstateBuilder = new PlaybackStateCompat.Builder();
        int playbackStateCompat = -1;
        switch(playbackState) {
            case PlaybackStateListener.STATE_PLAYING:
                playbackStateCompat = PlaybackStateCompat.STATE_PLAYING;
                //playbackstateBuilder.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_PAUSE);
                break;
            case PlaybackStateListener.STATE_PAUSED:
                playbackStateCompat = PlaybackStateCompat.STATE_PAUSED;
                //playbackstateBuilder.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_PLAY);
                break;
        }
        if (playbackStateCompat == -1) {
            return;
        }
        mSession.setActive(true);
        playbackstateBuilder.setActions(
                PlaybackStateCompat.ACTION_PLAY |
                        PlaybackStateCompat.ACTION_PLAY_PAUSE |
                        PlaybackStateCompat.ACTION_SKIP_TO_NEXT |
                        PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS);
        playbackstateBuilder.setState(playbackStateCompat, PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN, 0);
        PlaybackStateCompat state = playbackstateBuilder.build();
        MediaMetadataCompat mediaMetadata = new MediaMetadataCompat.Builder()
                .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, playerManager.getCurrenTrack().getName())
                .build();
        mSession.setMetadata(mediaMetadata);
        mSession.setPlaybackState(state);
        Notification notification = mediaNotificationManager.getNotification(
                mediaMetadata,
                state,
                getSessionToken()
        );
        Intent intent = new Intent(MusicService.this, MusicService.class);
        ContextCompat.startForegroundService(MusicService.this, intent);
        startForeground(417, notification);
    }
}

}

MediaBrowserHelper初始化服务:

public class MediaBrowserHelper {
private static final String TAG = MediaBrowserHelper.class.getSimpleName();
private final Context mContext;
private final Class<? extends MediaBrowserServiceCompat> mMediaBrowserServiceClass;
private final List<Callback> mCallbackList = new ArrayList<>();
private final MediaBrowserConnectionCallback mMediaBrowserConnectionCallback;
private final MediaControllerCallback mMediaControllerCallback;
private final MediaBrowserSubscriptionCallback mMediaBrowserSubscriptionCallback;
private MediaBrowserCompat mMediaBrowser;
@Nullable
private MediaControllerCompat mMediaController;
public MediaBrowserHelper(Context context,
                          Class<? extends MediaBrowserServiceCompat> serviceClass) {
    mContext = context;
    mMediaBrowserServiceClass = serviceClass;
    mMediaBrowserConnectionCallback = new MediaBrowserConnectionCallback();
    mMediaControllerCallback = new MediaControllerCallback();
    mMediaBrowserSubscriptionCallback = new MediaBrowserSubscriptionCallback();
}
public void onStart() {
    if (mMediaBrowser == null) {
        mMediaBrowser =
                new MediaBrowserCompat(
                        mContext,
                        new ComponentName(mContext, mMediaBrowserServiceClass),
                        mMediaBrowserConnectionCallback,
                        null);
        mMediaBrowser.connect();
    }
    Log.d(TAG, "onStart: Creating MediaBrowser, and connecting");
}
public void onStop() {
    if (mMediaController != null) {
        mMediaController.unregisterCallback(mMediaControllerCallback);
        mMediaController = null;
    }
    if (mMediaBrowser != null && mMediaBrowser.isConnected()) {
        mMediaBrowser.disconnect();
        mMediaBrowser = null;
    }
    resetState();
    Log.d(TAG, "onStop: Releasing MediaController, Disconnecting from MediaBrowser");
}
/**
 * Called after connecting with a {@link MediaBrowserServiceCompat}.
 * <p>
 * Override to perform processing after a connection is established.
 *
 * @param mediaController {@link MediaControllerCompat} associated with the connected
 *                        MediaSession.
 */
protected void onConnected(@NonNull MediaControllerCompat mediaController) {
}
/**
 * Called after loading a browsable {@link MediaBrowserCompat.MediaItem}
 *
 * @param parentId The media ID of the parent item.
 * @param children List (possibly empty) of child items.
 */
protected void onChildrenLoaded(@NonNull String parentId,
                                @NonNull List<MediaBrowserCompat.MediaItem> children) {
}
/**
 * Called when the {@link MediaBrowserServiceCompat} connection is lost.
 */
protected void onDisconnected() {
}
@NonNull
protected final MediaControllerCompat getMediaController() {
    if (mMediaController == null) {
        throw new IllegalStateException("MediaController is null!");
    }
    return mMediaController;
}
/**
 * The internal state of the app needs to revert to what it looks like when it started before
 * any connections to the {@link MusicService} happens via the {@link MediaSessionCompat}.
 */
private void resetState() {
    performOnAllCallbacks(new CallbackCommand() {
        @Override
        public void perform(@NonNull Callback callback) {
            callback.onPlaybackStateChanged(null);
        }
    });
    Log.d(TAG, "resetState: ");
}
public MediaControllerCompat.TransportControls getTransportControls() {
    if (mMediaController == null) {
        Log.d(TAG, "getTransportControls: MediaController is null!");
        throw new IllegalStateException("MediaController is null!");
    }
    return mMediaController.getTransportControls();
}
public void registerCallback(Callback callback) {
    if (callback != null) {
        mCallbackList.add(callback);
        // Update with the latest metadata/playback state.
        if (mMediaController != null) {
            final MediaMetadataCompat metadata = mMediaController.getMetadata();
            if (metadata != null) {
                callback.onMetadataChanged(metadata);
            }
            final PlaybackStateCompat playbackState = mMediaController.getPlaybackState();
            if (playbackState != null) {
                callback.onPlaybackStateChanged(playbackState);
            }
        }
    }
}
private void performOnAllCallbacks(@NonNull CallbackCommand command) {
    for (Callback callback : mCallbackList) {
        if (callback != null) {
            command.perform(callback);
        }
    }
}
/**
 * Helper for more easily performing operations on all listening clients.
 */
private interface CallbackCommand {
    void perform(@NonNull Callback callback);
}
// Receives callbacks from the MediaBrowser when it has successfully connected to the
// MediaBrowserService (MusicService).
private class MediaBrowserConnectionCallback extends MediaBrowserCompat.ConnectionCallback {
    // Happens as a result of onStart().
    @Override
    public void onConnected() {
        try {
            // Get a MediaController for the MediaSession.
            mMediaController =
                    new MediaControllerCompat(mContext, mMediaBrowser.getSessionToken());
            mMediaController.registerCallback(mMediaControllerCallback);
            // Sync existing MediaSession state to the UI.
            mMediaControllerCallback.onMetadataChanged(mMediaController.getMetadata());
            mMediaControllerCallback.onPlaybackStateChanged(
                    mMediaController.getPlaybackState());
            MediaBrowserHelper.this.onConnected(mMediaController);
        } catch (RemoteException e) {
            Log.d(TAG, String.format("onConnected: Problem: %s", e.toString()));
            throw new RuntimeException(e);
        }
        mMediaBrowser.subscribe(mMediaBrowser.getRoot(), mMediaBrowserSubscriptionCallback);
    }
}
// Receives callbacks from the MediaBrowser when the MediaBrowserService has loaded new media
// that is ready for playback.
public class MediaBrowserSubscriptionCallback extends MediaBrowserCompat.SubscriptionCallback {
    @Override
    public void onChildrenLoaded(@NonNull String parentId,
                                 @NonNull List<MediaBrowserCompat.MediaItem> children) {
        MediaBrowserHelper.this.onChildrenLoaded(parentId, children);
    }
}
// Receives callbacks from the MediaController and updates the UI state,
// i.e.: Which is the current item, whether it's playing or paused, etc.
private class MediaControllerCallback extends MediaControllerCompat.Callback {
    @Override
    public void onMetadataChanged(final MediaMetadataCompat metadata) {
        performOnAllCallbacks(new CallbackCommand() {
            @Override
            public void perform(@NonNull Callback callback) {
                callback.onMetadataChanged(metadata);
            }
        });
    }
    @Override
    public void onPlaybackStateChanged(@Nullable final PlaybackStateCompat state) {
        performOnAllCallbacks(new CallbackCommand() {
            @Override
            public void perform(@NonNull Callback callback) {
                callback.onPlaybackStateChanged(state);
            }
        });
    }
    // This might happen if the MusicService is killed while the Activity is in the
    // foreground and onStart() has been called (but not onStop()).
    @Override
    public void onSessionDestroyed() {
        resetState();
        onPlaybackStateChanged(null);
        MediaBrowserHelper.this.onDisconnected();
    }
}

}

清单:

<service android:name="com.amco.playermanager.MusicService">
        <intent-filter>
            <action android:name="android.media.browse.MediaBrowserService"/>
        </intent-filter>
    </service>
    <receiver android:name="android.support.v4.media.session.MediaButtonReceiver">
        <intent-filter>
            <action android:name="android.intent.action.MEDIA_BUTTON"/>
        </intent-filter>
    </receiver>

事实证明,整个问题是由于在我的应用程序的清单中宣布了另一个广播员处理媒体的介质。通过删除接收器,现在一切都起作用。

相关内容

最新更新