如何修改ExoPlayer中PlayerNotificationManager的操作图标及图标颜色?
Got it! Let's walk through how to customize the playback control icons (play/pause/stop) and their colors for ExoPlayer's PlayerNotificationManager. Here's a step-by-step breakdown:
Step 1: Prepare Custom Icon Resources
First, add your custom vector or raster icons to the res/drawable directory (e.g., ic_custom_play.xml, ic_custom_pause.xml, ic_custom_stop.xml). Make sure they're sized appropriately for notifications (24dp is standard for control icons).
Step 2: Implement a Custom MediaDescriptionAdapter
To replace the default play/pause/stop actions, override the getActions() method in MediaDescriptionAdapter—this lets you define your own notification actions with custom icons:
import android.app.Notification; import android.content.Context; import android.content.Intent; import android.support.v4.media.session.MediaButtonReceiver; import androidx.core.app.NotificationCompat; import androidx.core.content.ContextCompat; import androidx.core.app.PendingIntentCompat; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.ui.PlayerNotificationManager; import android.support.v4.media.session.PlaybackStateCompat; private class CustomMediaDescriptionAdapter implements PlayerNotificationManager.MediaDescriptionAdapter { private final Context context; public CustomMediaDescriptionAdapter(Context context) { this.context = context; } // Required core methods @Override public CharSequence getCurrentContentTitle(Player player) { return "Your Media Title"; // Replace with your dynamic title logic } @Override public PendingIntent createCurrentContentIntent(Player player) { // Replace with intent to open your app's playback screen Intent intent = new Intent(context, PlaybackActivity.class); return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); } @Override public CharSequence getCurrentContentText(Player player) { return "Your Media Subtitle"; // Replace with your dynamic subtitle logic } // Override to use custom action icons @Override public Notification.Action[] getActions(Player player, PlayerNotificationManager.TimeBar timeBar) { // Build play/pause action with custom icon PendingIntent playPausePendingIntent = MediaButtonReceiver.buildMediaButtonPendingIntent( context, player.isPlaying() ? PlaybackStateCompat.ACTION_PAUSE : PlaybackStateCompat.ACTION_PLAY ); NotificationCompat.Action playPauseAction = new NotificationCompat.Action.Builder( player.isPlaying() ? R.drawable.ic_custom_pause : R.drawable.ic_custom_play, player.isPlaying() ? "Pause" : "Play", playPausePendingIntent ).build(); // Build stop action with custom icon PendingIntent stopPendingIntent = MediaButtonReceiver.buildMediaButtonPendingIntent( context, PlaybackStateCompat.ACTION_STOP ); NotificationCompat.Action stopAction = new NotificationCompat.Action.Builder( R.drawable.ic_custom_stop, "Stop", stopPendingIntent ).build(); // Return custom actions (order defines their position in the notification) return new Notification.Action[]{playPauseAction, stopAction}; } }
Step 3: Attach the Adapter to PlayerNotificationManager
When initializing your PlayerNotificationManager, set the custom adapter to apply your icons:
private static final int NOTIFICATION_ID = 1234; private static final String CHANNEL_ID = "playback_control_channel"; // Initialize PlayerNotificationManager PlayerNotificationManager playerNotificationManager = new PlayerNotificationManager.Builder( context, NOTIFICATION_ID, CHANNEL_ID ) .setMediaDescriptionAdapter(new CustomMediaDescriptionAdapter(context)) .build(); // Attach your ExoPlayer instance playerNotificationManager.setPlayer(exoPlayer);
You have a few flexible options to adjust icon colors, depending on your needs:
Option 1: Direct Icon Tinting (Recommended for Vector Icons)
If using vector drawables, apply a tint directly to each action icon using setIconTint() in the Action Builder. This gives you per-icon control:
// Inside the getActions() method, when building playPauseAction NotificationCompat.Action playPauseAction = new NotificationCompat.Action.Builder( player.isPlaying() ? R.drawable.ic_custom_pause : R.drawable.ic_custom_play, player.isPlaying() ? "Pause" : "Play", playPausePendingIntent ) .setIconTint(ContextCompat.getColorStateList(context, R.color.notification_icon_tint)) .build();
Create a color state list res/color/notification_icon_tint.xml to handle different states (e.g., enabled/disabled):
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="@color/white" android:state_enabled="true"/> <item android:color="@color/gray_600" android:state_enabled="false"/> </selector>
Option 2: Global Notification Accent Color
Set a global color for the entire notification, which will tint all compatible icons (like media controls) and elements:
PlayerNotificationManager playerNotificationManager = new PlayerNotificationManager.Builder( context, NOTIFICATION_ID, CHANNEL_ID ) .setMediaDescriptionAdapter(new CustomMediaDescriptionAdapter(context)) .setColor(ContextCompat.getColor(context, R.color.notification_accent)) .build();
Note: This affects the time bar and other notification accents alongside icons.
Option 3: Post-Notification Modification via Listener
For full control, use a NotificationListener to adjust the notification after it's built:
playerNotificationManager.setNotificationListener(new PlayerNotificationManager.NotificationListener() { @Override public void onNotificationPosted(int notificationId, Notification notification, boolean ongoing) { // Rebuild the notification with custom color adjustments NotificationCompat.Builder updatedBuilder = NotificationCompat.Builder.from(context, notification) .setColor(ContextCompat.getColor(context, R.color.notification_icon_tint)); // Update the active notification NotificationManagerCompat.from(context).notify(notificationId, updatedBuilder.build()); } @Override public void onNotificationCancelled(int notificationId, boolean dismissedByUser) { // Handle cleanup logic if needed } });
Key Notes for Android 12+
For Android 12 and above, ensure your notification channel's color is set correctly if relying on inherited tinting:
NotificationChannel channel = new NotificationChannel( CHANNEL_ID, "Playback Controls", NotificationManager.IMPORTANCE_LOW ); channel.setDescription("Media playback control notifications"); channel.setLightColor(ContextCompat.getColor(context, R.color.notification_accent)); NotificationManager notificationManager = context.getSystemService(NotificationManager.class); notificationManager.createNotificationChannel(channel);
内容的提问来源于stack exchange,提问作者P A Gosai

