锁定屏幕播放器控件和元数据

时间:2015-11-17 15:53:04

标签: java android android-mediasession

我正在尝试使用MediaSessionCompat为我的应用添加锁屏播放器控件和元数据。我试过的一切都行不通。锁定屏幕在播放时不显示任何控件或元数据。请参阅下面的当前代码,我们非常感谢您的帮助。

StreamService.java:

public class StreamService extends Service implements MediaPlayer.OnCuePointReceivedListener, MediaPlayer.OnStateChangedListener,
        MediaPlayer.OnInfoListener, AudioManager.OnAudioFocusChangeListener {

    private WifiManager.WifiLock wifiLock;
    private static String LOG_TAG = "StreamService";
    public static final String BROADCAST_PLAYER_STATE = "com.test.BROADCAST_PLAYER_STATE";
    public static final String BROADCAST_PLAYER_META = "com.test.BROADCAST_PLAYER_META";
    public static final String BROADCAST_PLAYER_ALBUM = "com.test.BROADCAST_PLAYER_ALBUM";
    public static final int NOTIFICATION_ID = 999999;
    private MediaSessionCompat mediaSession;
    private boolean audioInterrupted = false;

    public StreamService() {
    }

    @Override
    public void onCreate(){
        super.onCreate();

        setupMediaPlayer();

        setupMediaSession();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public boolean onUnbind(Intent intent){
        releasePlayer();
        return false;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_NOT_STICKY;
    }

    private void setupMediaPlayer() {
        // Recreate player
        Bundle playerSettings = (BrandedApplication.getContext().getmTritonPlayer() == null) ? null : BrandedApplication.getContext().getmTritonPlayer().getSettings();
        Bundle inputSettings = createPlayerSettings();

        if (!Utility.bundleEquals(inputSettings, playerSettings)) {
            releasePlayer();
            createPlayer(inputSettings);
        }

        // Start the playback
        play();
    }

    private void setupMediaSession() {
        ComponentName receiver = new ComponentName(getPackageName(), RemoteReceiver.class.getName());
        mediaSession = new MediaSessionCompat(this, "StreamService", receiver, null);
        mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
                MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
        mediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
                .setState(PlaybackStateCompat.STATE_PAUSED, 0, 0)
                .setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE)
                .build());
        mediaSession.setMetadata(new MediaMetadataCompat.Builder()
                .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, "Test Artist")
                .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, "Test Album")
                .putString(MediaMetadataCompat.METADATA_KEY_TITLE, "Test Track Name")
                .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, 10000)
                .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART,
                        BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                //.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, "Test Artist")
                .build());

        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        audioManager.requestAudioFocus(new AudioManager.OnAudioFocusChangeListener() {
            @Override
            public void onAudioFocusChange(int focusChange) {
                // Ignore
            }
        }, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);

        mediaSession.setActive(true);
    }

    synchronized private void play() {
        audioInterrupted = false;
        BrandedApplication.getContext().getmTritonPlayer().play();
        if(wifiLock != null) {
            wifiLock.acquire();
        }

        if(mediaSession != null) {
            mediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
                    .setState(PlaybackStateCompat.STATE_PLAYING, 0, 1.0f)
                    .setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE).build());
        }
    }

    synchronized private void stop() {
        BrandedApplication.getContext().getmTritonPlayer().stop();
        if(wifiLock != null) {
            wifiLock.release();
        }

        if(mediaSession != null) {
            mediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
                    .setState(PlaybackStateCompat.STATE_PAUSED, 0, 0.0f)
                    .setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE).build());
        }
    }

    private void createPlayer(Bundle settings)
    {
        BrandedApplication.getContext().setmTritonPlayer(new TritonPlayer(this, settings));
        wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
                .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");
        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
                AudioManager.AUDIOFOCUS_GAIN);
        BrandedApplication.getContext().getmTritonPlayer().setOnCuePointReceivedListener(this);
        BrandedApplication.getContext().getmTritonPlayer().setOnInfoListener(this);
        BrandedApplication.getContext().getmTritonPlayer().setOnStateChangedListener(this);
    }


    protected void releasePlayer() {
        if (BrandedApplication.getContext().getmTritonPlayer() != null) {
            if(BrandedApplication.getContext().isPlaying()) {
                stop();
            }
            BrandedApplication.getContext().getmTritonPlayer().release();
            BrandedApplication.getContext().setmTritonPlayer(null);
        }
        stopForeground(true);
    }

    protected Bundle createPlayerSettings() {
        // Player Settings
        Bundle settings = new Bundle();
        // AAC
        settings.putString(TritonPlayer.SETTINGS_STATION_MOUNT, getResources().getString(R.string.station_stream_mount) + "AAC");
        // MP3
        //settings.putString(TritonPlayer.SETTINGS_STATION_MOUNT, mountID);
        settings.putString(TritonPlayer.SETTINGS_STATION_BROADCASTER, getResources().getString(R.string.app_name));
        settings.putString(TritonPlayer.SETTINGS_STATION_NAME, getResources().getString(R.string.app_name));
        return settings;
    }

    @Override
    public void onCuePointReceived(MediaPlayer mediaPlayer, Bundle bundle) {
        //System.out.println("TRITON PLAYER BUNDLE " + bundle);
        String trackName = "";
        String artistName = "";
        if(bundle != null) {
            if(bundle.containsKey("cue_title") && bundle.containsKey("track_artist_name")) {
                if (!bundle.getString("cue_title").isEmpty()) {
                    trackName = bundle.getString("cue_title");
                }
                if (!bundle.getString("track_artist_name").isEmpty()) {
                    artistName = bundle.getString("track_artist_name");
                }
            }
        }
        // broadcast out the meta data
        Intent i = new Intent(BROADCAST_PLAYER_META);
        i.putExtra("trackName", trackName);
        i.putExtra("artistName", artistName);
        sendBroadcast(i);

        // send notification and start as foreground service
        PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0, new Intent(getApplicationContext(), MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
        Bitmap icon = BitmapFactory.decodeResource(getResources(),
                R.drawable.logo);
        String tickerString = "";
        String contentString = "Playing";
        if(!artistName.isEmpty() && !trackName.isEmpty()) {
            tickerString = artistName + " - " + trackName;
            contentString += ": " + artistName + " - " + trackName;
        }

        Intent pauseIntent = new Intent(BROADCAST_PLAYER_PAUSE);
    PendingIntent pausePendingIntent = PendingIntent.getBroadcast(this, 0, pauseIntent, 0);

    NotificationCompat.Builder notification = new NotificationCompat.Builder(this)
            .setContentTitle(getResources().getString(R.string.app_name))
            .setTicker(tickerString)
            .setContentText(contentString)
            .setSmallIcon(R.drawable.ic_launcher)
            //.setAutoCancel(true)
            //.setLargeIcon(
            //        Bitmap.createScaledBitmap(icon, 128, 128, false))
            .addAction(R.drawable.ic_media_pause, "Pause", pausePendingIntent)
            .setContentIntent(pi)
            .setStyle(new android.support.v7.app.NotificationCompat.MediaStyle()
                    //.setShowActionsInCompactView(0)
                    .setMediaSession(mediaSession.getSessionToken()))
            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
            .setOngoing(true);
    //notification.setPriority(Notification.PRIORITY_MIN);
    notification.setPriority(Notification.PRIORITY_DEFAULT);
    startForeground(NOTIFICATION_ID, notification.build());
    }

    @Override
    public void onInfo(MediaPlayer mediaPlayer, int i, int i1) {

    }

    @Override
    public void onStateChanged(MediaPlayer mediaPlayer, int state) {
        Log.i(LOG_TAG, "onStateChanged: " + TritonPlayer.debugStateToStr(state));
        // broadcast out the player state
        Intent i = new Intent(BROADCAST_PLAYER_STATE);
        i.putExtra("state", state);
        sendBroadcast(i);
    }

    @Override
    public void onAudioFocusChange(int focusChange) {
        switch (focusChange) {
            case AudioManager.AUDIOFOCUS_GAIN:
                // resume playback
                System.out.println("AUDIO FOCUS GAIN");
                if(audioInterrupted) {
                    audioInterrupted = false;
                    if (BrandedApplication.getContext().getmTritonPlayer() == null) {
                        setupMediaPlayer();
                    } else if (!BrandedApplication.getContext().isPlaying()) {
                        setupMediaPlayer();
                    }
                }
                break;

            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
            case AudioManager.AUDIOFOCUS_LOSS:
                System.out.println("AUDIO FOCUS LOSS");
                // Lost focus for an unbounded amount of time: stop playback and release media player
                if (BrandedApplication.getContext().isPlaying()) {
                    audioInterrupted = true;
                    releasePlayer();
                }
                break;
        }
    }

    @Override
    public void onDestroy() {
        System.out.println("SERVICE STOPPED");
        releasePlayer();
        mediaSession.release();
    }
}

这是RemoteReceiver.java:

public class RemoteReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
            final KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);

            if (event != null && event.getAction() == KeyEvent.ACTION_DOWN) {
                switch (event.getKeyCode()) {
                    case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
                        context.startService(new Intent(context, StreamService.class));
                        break;
                }
            }
        }
    }
}

2 个答案:

答案 0 :(得分:3)

好的,根据您提供的其他信息,我相信我知道问题所在。在Android 5.0中,锁定屏幕控件已被删除。它们现在通过Notification API实现。因此,请尝试将以下内容添加到通知构建器中。

notification.setStyle(new NotificationCompat.MediaStyle()
                .setShowActionsInCompactView(0)
                .setMediaSession(mediaSession));
            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)

应将它放在锁定屏幕上。我还建议您更改Notification.PRIORITY_DEFAULT以及在通知中添加操作,否则您将无法控制播放。

答案 1 :(得分:0)

我知道这篇文章很晚但是如果有人仍然面临这个问题。这也会出现在你的锁定屏幕上。

以下是通知构建器类的代码 -

      import android.annotation.SuppressLint;
        import android.app.NotificationChannel;
        import android.app.NotificationManager;
        import android.app.PendingIntent;
        import android.app.Service;
        import android.content.Context;
        import android.content.Intent;
        import android.graphics.BitmapFactory;
        import android.media.MediaPlayer;
        import android.media.session.MediaSessionManager;
        import android.os.Build;
        import android.os.IBinder;
        import android.os.RemoteException;
        import android.support.annotation.RequiresApi;
        import android.support.v4.app.NotificationCompat;
        import android.support.v4.media.session.MediaControllerCompat;
        import android.support.v4.media.session.MediaSessionCompat;
        import android.util.Log;



        import org.json.JSONException;


        public class MediaPlayerService extends Service {


            private static final String  CHANNEL_ID = "my_channel_01";

            public static final String ACTION_PLAY = "action_play";
            public static final String ACTION_PAUSE = "action_pause";
            public static final String ACTION_NEXT = "action_next";
            public static final String ACTION_PREVIOUS = "action_previous";
            public static final String ACTION_STOP = "action_stop";
            public static final String ACTION_NOTHING = "action_previous";


            private NotificationManager notificationManager;
            NotificationManager mNotificationManager;

            private MediaPlayer mMediaPlayer;
            private MediaSessionManager mManager;
            private MediaSessionCompat mSession;
            private MediaControllerCompat mController;



            private MediaPlayerService mService;

            String title = null; 
            String description = null; 

            @Override
            public IBinder onBind(Intent intent) {
                return null;
            }

            private void handleIntent(Intent intent) {
                if (intent == null || intent.getAction() == null)
                    return;

                String action = intent.getAction();

                if (action.equalsIgnoreCase(ACTION_PLAY)) {
                    mController.getTransportControls().play();
                } else if (action.equalsIgnoreCase(ACTION_PAUSE)) {
                    mController.getTransportControls().pause();
                } else if (action.equalsIgnoreCase(ACTION_PREVIOUS)) {
                    mController.getTransportControls().skipToPrevious();
                } else if (action.equalsIgnoreCase(ACTION_NEXT)) {
                    mController.getTransportControls().skipToNext();
                } else if (action.equalsIgnoreCase(ACTION_STOP)) {
                    mController.getTransportControls().stop();
                }


            }

            private NotificationCompat.Action generateAction(int icon, String title, String intentAction) {
                Intent intent = new Intent(getApplicationContext(), MediaPlayerService.class);
                intent.setAction(intentAction);
                PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 1, intent, 0);
                return new NotificationCompat.Action.Builder(icon, title, pendingIntent).build();

            }



            @SuppressLint("ServiceCast")
            private void buildNotification(NotificationCompat.Action action) {




                    title = ""; // add variable to get current playing song title here 


                    description =""; // add variable to get current playing song description  here


                Intent notificationIntent = new Intent(getApplicationContext(), HomeActivity.class); //specify which activity should be opened when widget is clicked (other than buttons)

                PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0);

                notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

                // Notification channels are only supported on Android O+.
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) 
                {
                    //method to create channel if android version is android. Descrition below
                    createNotificationChannel();
                }

                Intent intent = new Intent(getApplicationContext(), MediaPlayerService.class);
                intent.setAction(ACTION_STOP);
                PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 1, intent, 0);
                final NotificationCompat.Builder builder;

                //condition to check if music is playing
                //if music is playing widget cant be dismissed on swipe

                if(<add your method to check play status here>)
                {
                    builder = new NotificationCompat.Builder(this, CHANNEL_ID)
                            .setSmallIcon(R.drawable.logo2b)
                            .setLargeIcon(BitmapFactory.decodeResource(getApplication().getResources(), R.mipmap.ic_launcher))
                            .setContentTitle(title)
                            .setContentText(description)
                            .setDeleteIntent(pendingIntent)
                            .setContentIntent(contentIntent)
                            .setChannelId(CHANNEL_ID)
                            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                            .setOnlyAlertOnce(true)
                            .setColor(getResources().getColor(R.color.colorPrimary))
                            .setOngoing(true) //set this to true if music is playing widget cant be dismissed on swipe
                            .setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle()
                                    // show only play/pause in compact view
                                    .setShowActionsInCompactView(0, 1, 2));
                }
                //else if music is not playing widget can be dismissed on swipe
                else
                {
                    builder = new NotificationCompat.Builder(this, CHANNEL_ID)
                            .setSmallIcon(R.drawable.logo2b)
                            .setLargeIcon(BitmapFactory.decodeResource(getApplication().getResources(), R.mipmap.ic_launcher))
                            .setContentTitle(title)
                            .setContentText(description)
                            .setDeleteIntent(pendingIntent)
                            .setContentIntent(contentIntent)
                            .setChannelId(CHANNEL_ID)
                            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                            .setOnlyAlertOnce(true)
                            .setColor(getResources().getColor(R.color.colorPrimary))
                            .setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle()
                                    // show only play/pause in compact view
                                    .setShowActionsInCompactView(0, 1, 2));
                }



                builder.addAction(generateAction(R.drawable.ic_skip_previous_white_24dp, "Previous", ACTION_PREVIOUS));
                builder.addAction(action);
                builder.addAction(generateAction(R.drawable.ic_skip_next_white_24dp, "Next", ACTION_NEXT));
                //style.setShowActionsInCompactView(0,1,2);

                //   builder.setColor(getResources().getColor(R.color.app_orange_color));


                notificationManager.notify(1, builder.build());

            }

            @Override
            public int onStartCommand(Intent intent, int flags, int startId) {
                if (mManager == null) {
                    try {
                        initMediaSessions();
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }

                handleIntent(intent);
                return super.onStartCommand(intent, flags, startId);
            }

            private void initMediaSessions() throws RemoteException {
                mMediaPlayer = new MediaPlayer();
                mSession = new MediaSessionCompat(getApplicationContext(), "simple player session");
                mController = new MediaControllerCompat(getApplicationContext(), mSession.getSessionToken());



                mSession.setCallback(new MediaSessionCompat.Callback() {
                                         @Override
                                         public void onPlay() {
                                             super.onPlay();


                                             //add you code for play button click here

   //replace your drawable id that shows pauseicon                                              buildNotification(generateAction(R.drawable.uamp_ic_pause_white_24dp, "Pause", ACTION_PAUSE));




                                         }

                                         @Override
                                         public void onPause() {
                                             super.onPause();

                                              //add you code for pause button click here
         //replace your drawable id that shows play icon                                    buildNotification(generateAction(R.drawable.uamp_ic_play_arrow_white_24dp, "Play", ACTION_PLAY)); 

                                         }

                                         @Override
                                         public void onSkipToNext() {

                                             super.onSkipToNext();

                                             //add you code for next button click here
                                             buildNotification(generateAction(R.drawable.uamp_ic_pause_white_24dp, "Pause", ACTION_PAUSE));


                                         }

                                         @Override
                                         public void onSkipToPrevious() {
                                             super.onSkipToPrevious();

                                             //add you code for previous button click here

                                             buildNotification(generateAction(R.drawable.uamp_ic_pause_white_24dp, "Pause", ACTION_PAUSE));

                                         }

                                         @Override
                                         public void onStop() {
                                             super.onStop();
                                             Log.e("MediaPlayerService", "onStop");
                                             //Stop media player and dismiss widget here
                                             NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
                                             notificationManager.cancel(1);
                                             Intent intent = new Intent(getApplicationContext(), MediaPlayerService.class);
                                             stopService(intent);
                                         }

                                         @Override
                                         public void onSeekTo(long pos) {
                                             super.onSeekTo(pos);
                                         }


                                     }
                );
            }



            @Override
            public boolean onUnbind(Intent intent) {
                mSession.release();
                return super.onUnbind(intent);
            }



            //method to create notification channel on android Oreo and above
            @RequiresApi(Build.VERSION_CODES.O)
            private void createNotificationChannel() {
                int notifyID = 1;

                CharSequence name = "Player Widget";// The user-visible name of the channel. This channel name will be shown in settings.
                if (notificationManager.getNotificationChannel(CHANNEL_ID) == null) {
                    NotificationChannel notificationChannel =
                            new NotificationChannel(CHANNEL_ID, name, NotificationManager.IMPORTANCE_LOW);


                    notificationManager.createNotificationChannel(notificationChannel);
                }
            }

 }

当应用程序中的播放状态发生变化时,触发这些意图以更新小部件:

播放 -

//to change widgets current action button to play
 Intent intent = new Intent(getApplicationContext(), MediaPlayerService.class);
                intent.setAction(MediaPlayerService.ACTION_PAUSE);
                startService(intent);

暂停 -

 //to change widgets current action button to pause
        Intent intent = new Intent(getApplicationContext(), MediaPlayerService.class);
                        intent.setAction(MediaPlayerService.ACTION_PLAY);
                        startService(intent);

如果有任何不需要的导入,请原谅。一切顺利。