обрабатывать уведомления мультимедийной кнопки из подшивки в сервисе backrgound - PullRequest
0 голосов
/ 06 января 2019

Я начал разрабатывать приложение для Android, но у меня возникают некоторые трудности с правильным пониманием фоновых служб и уведомлений Android. Здесь я работаю над приложением потоковой передачи музыки и хочу добавить постоянное уведомление, чтобы пользователь мог взаимодействовать (играть stop music) с сервисом, отвечающим за воспроизведение музыки из интернета в фоновом режиме. Я пытался найти пример обработки нажатий кнопок в уведомлении Android, я нашел пример для обработки этих действий в службах переднего плана через onStartCommand, но я использую связыватель в этом проекте. Это хороший способ создания кнопки мультимедиа уведомлений и обработки этих кнопок нажмите в моем случае.

Вот мой код привязки службы потоковой передачи:

StreamingServiceBinder.java

package com.stream.music;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.media.session.PlaybackState;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.media.session.MediaButtonReceiver;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.text.TextUtils;
import android.util.Log;

import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;

import java.io.IOException;

class StreamServiceBinder extends Binder  implements ExoPlayer.EventListener {


    // Save web audio file url.
    private String audioFileUrl = "";

    // Check if stream audio.
    private boolean streamAudio = true;
    private boolean isHls = false;

    // Media player that play audio.
    public static final String NOTIFICATION_CHANNEL = "1337";
    public static final int NOTIFICATION_ID = 1338;

    public static final String STREAM_URI = "STREAM_URI";
    public static final String STREAM_TITLE = "STREAM_TITLE";

    public static final float VOLUME_DUCK = 0.2f;
    public static final float VOLUME_NORMAL = 1.0f;

    private static final int AUDIO_NO_FOCUS_LOST = -1;
    private static final int AUDIO_NO_FOCUS_NO_DUCK = 0;
    private static final int AUDIO_NO_FOCUS_CAN_DUCK= 1;
    private static final int AUDIO_FOCUSED = 2;

    public static final int STATE_PAUSE = 0;
    public static final int STATE_PLAY = 1;
    private int mCurrentAudioFocusState = AUDIO_NO_FOCUS_NO_DUCK;

    private String currentTitle;


    public SimpleExoPlayer mExoPlayer;
    private MediaSessionCompat mMediaSession;
    private MediaControllerCompat mMediaController;
    private MediaSource mediaSource;

    // Caller activity context, used when play local audio file.
    private Context context = null;

    // This Handler object is a reference to the caller activity's Handler.
    // In the caller activity's handler, it will update the audio play progress.
    private Handler playpauseButtonHandler;

    @Override
    public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
        if(playbackState == Player.STATE_READY){
            Log.v("PLAYERSTATE", "isPlaying");
            Message pauseButton = new Message();
            pauseButton.what = STATE_PAUSE;

            // Send the message to caller activity's update audio prgressbar Handler object.
            playpauseButtonHandler.sendMessage(pauseButton);

        }else{
            Log.v("PLAYERSTATE", "isPaused");
            Message startButton = new Message();
            startButton.what = STATE_PLAY;

            // Send the message to caller activity's update audio prgressbar Handler object.
            playpauseButtonHandler.sendMessage(startButton);
        }
    }

    private AudioManager.OnAudioFocusChangeListener mOnAudioFocusChangeListener =
            new AudioManager.OnAudioFocusChangeListener() {
                @Override
                public void onAudioFocusChange(int focusChange) {
                    switch (focusChange) {
                        case AudioManager.AUDIOFOCUS_GAIN:
                            mCurrentAudioFocusState = AUDIO_FOCUSED;
                            break;
                        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                            mCurrentAudioFocusState = AUDIO_NO_FOCUS_CAN_DUCK;
                            break;
                        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                            mCurrentAudioFocusState = AUDIO_NO_FOCUS_NO_DUCK;
                            break;
                        case AudioManager.AUDIOFOCUS_LOSS:
                            mCurrentAudioFocusState = AUDIO_NO_FOCUS_LOST;
                            break;
                    }

                    if (mExoPlayer != null) configurePlayerState();
                }
            };


    private final IntentFilter mAudioNoisyIntentFilter =
            new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);

    private BroadcastReceiver mAudioNoisyReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
//            Log.v("Broadcast", "Action received");
//            Log.v("Broadcast", intent.getAction());
//            int mAction = Integer.parseInt(intent.getAction());
//            if(mAction == PlaybackState.ACTION_PLAY){
//                startAudio();
//
//            }
//            else{
//                stopAudio();
//            }
            mMediaController.getTransportControls().pause();
        }
    };

    private boolean mAudioNoisyReceiverRegistered = false;
    // This is the message signal that inform audio progress updater to update audio progress.



    public Context getContext() {
        return context;
    }

    public void setContext(Context context) {
        this.context = context;
    }

    public String getAudioFileUrl() {
        return audioFileUrl;
    }

    public void setAudioFileUrl(String audioFileUrl) {
        this.audioFileUrl = audioFileUrl;
        Log.i("BINDER", "audio file  set!");
    }

    public void setNotifTitle(String title){
        this.currentTitle = title;
    }

    public boolean isStreamAudio() {
        return streamAudio;
    }

    public void setStreamAudio(boolean streamAudio) {
        this.streamAudio = streamAudio;
    }
    public void setHls(boolean hlsfile){
        this.isHls = hlsfile;
    }


    public void setPlaypauseButtonHandler(Handler playpauseButtonHandler) {
        this.playpauseButtonHandler = playpauseButtonHandler;
    }

    // Start play audio.
    public void startAudio()
    {
        initAudioPlayer();
        if(mExoPlayer!=null) {
            mExoPlayer.setPlayWhenReady(true);
            NotificationManager mNotificationManager
                    = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            assert mNotificationManager != null;
            mNotificationManager
                    .notify(NOTIFICATION_ID, buildNotification(PlaybackStateCompat.ACTION_PAUSE));
        }
    }

    // Pause playing audio.
    public void pauseAudio()
    {
        if(mExoPlayer!=null) {
            mExoPlayer.setPlayWhenReady(false);
        }
    }

    // Stop play audio.
    public void stopAudio()
    {
        if(mExoPlayer!=null) {
            mExoPlayer.stop();
            destroyAudioPlayer();
        }
    }


    public class MediaSessionCallback extends MediaSessionCompat.Callback {
        @Override
        public void onPlay() {
            registerAudioNoisyReceiver();
            mExoPlayer.setPlayWhenReady(true);
            NotificationManager mNotificationManager
                    = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            assert mNotificationManager != null;
            mNotificationManager
                    .notify(NOTIFICATION_ID, buildNotification(PlaybackStateCompat.ACTION_PAUSE));
        }

        @Override
        public void onPause() {
            unregisterAudioNoisyReceiver();
            mExoPlayer.setPlayWhenReady(false);
            NotificationManager mNotificationManager
                    = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            assert mNotificationManager != null;
            mNotificationManager
                    .notify(NOTIFICATION_ID, buildNotification(PlaybackStateCompat.ACTION_PLAY));
        }

        @Override
        public void onStop() {
            unregisterAudioNoisyReceiver();
            mExoPlayer.stop();
            mMediaSession.setActive(false);
            NotificationManager mNotificationManager
                    = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            assert mNotificationManager != null;
            mNotificationManager
                    .notify(NOTIFICATION_ID, buildNotification(PlaybackStateCompat.ACTION_PLAY));
//            mNotificationManager.cancel(NOTIFICATION_ID);
//            stopSelf();
        }
    }
    public void init(){

        AudioManager mAudioManager = (AudioManager)
                context.getSystemService(Context.AUDIO_SERVICE);

        assert mAudioManager != null;
        int result = mAudioManager.requestAudioFocus(
                mOnAudioFocusChangeListener,
                AudioManager.STREAM_MUSIC,
                AudioManager.AUDIOFOCUS_GAIN
        );
        if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
//            initAudioPlayer();
        }
    }

    // Initialise audio player.
    private void initAudioPlayer()
    {

        try {
            if(mExoPlayer != null) {
                mExoPlayer.stop();
                mExoPlayer.release();

            }

            Log.i("SERVICE BACK", "Service started");

                mCurrentAudioFocusState = AUDIO_FOCUSED;
                registerAudioNoisyReceiver();

                mMediaSession = new MediaSessionCompat(context, "Pinstream");
                mMediaSession.setCallback(new MediaSessionCallback());
                mMediaSession.setFlags(
                        MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS);
                mMediaSession.setActive(true);

                try {
                    mMediaController = new MediaControllerCompat(
                            context, mMediaSession.getSessionToken());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }

                BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
                TrackSelection.Factory videoTrackSelectionFactory =
                        new AdaptiveTrackSelection.Factory(bandwidthMeter);
                TrackSelector trackSelector =
                        new DefaultTrackSelector(videoTrackSelectionFactory);
                mExoPlayer = ExoPlayerFactory.newSimpleInstance(context, trackSelector);


                Uri uri = Uri.parse(getAudioFileUrl());
                if(isHls){
                    mediaSource = new HlsMediaSource.Factory(new DefaultHttpDataSourceFactory("Pinstream")).createMediaSource(uri);
//                                mainHandler, null);
                }else {
                    mediaSource = new ExtractorMediaSource.Factory(
                            new DefaultHttpDataSourceFactory("Pinstream"))
                            .createMediaSource(uri);
                }
                mExoPlayer.addListener(this);
                mExoPlayer.prepare(mediaSource);
                mExoPlayer.setPlayWhenReady(true);

                Log.i("BINDER", "audio is playing");



        }catch(Exception ex)
        {
            ex.printStackTrace();
        }
    }

    // Destroy audio player.
    private void destroyAudioPlayer()
    {
        if(mExoPlayer!=null)
        {

            mExoPlayer.release();

            mExoPlayer = null;
        }
    }




    private void configurePlayerState() {
        switch (mCurrentAudioFocusState) {
            case AUDIO_NO_FOCUS_CAN_DUCK:
                mExoPlayer.setVolume(VOLUME_DUCK);
                break;
            case AUDIO_NO_FOCUS_NO_DUCK:
                mMediaController.getTransportControls().pause();
                break;
            case AUDIO_NO_FOCUS_LOST:
                mMediaController.getTransportControls().stop();
                break;
            case AUDIO_FOCUSED:
                mExoPlayer.setVolume(VOLUME_NORMAL);
                break;
        }
    }


    private void registerAudioNoisyReceiver() {
        if (!mAudioNoisyReceiverRegistered) {
            context.registerReceiver(mAudioNoisyReceiver, mAudioNoisyIntentFilter);
            mAudioNoisyReceiverRegistered = true;
        }
    }

    private void unregisterAudioNoisyReceiver() {
        if (mAudioNoisyReceiverRegistered) {
            context.unregisterReceiver(mAudioNoisyReceiver);
            mAudioNoisyReceiverRegistered = false;
        }
    }

    private Notification buildNotification(long action) {
        createNotificationChannel();

        NotificationCompat.Builder builder =
                new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL);

        builder
                .setContentTitle(currentTitle)
                .setContentIntent(mMediaController.getSessionActivity())
                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                .setDeleteIntent(
                        MediaButtonReceiver.buildMediaButtonPendingIntent(
                                context, PlaybackStateCompat.ACTION_STOP));

        builder
                .setSmallIcon(android.R.drawable.ic_media_play)

                .setColor(ContextCompat.getColor(context, R.color.colorPrimaryDark));


        if (action == PlaybackStateCompat.ACTION_PLAY) {
            builder
                    .addAction(new NotificationCompat.Action(
                            R.drawable.play_button, "Play",
                            MediaButtonReceiver.buildMediaButtonPendingIntent(
                                    context, PlaybackStateCompat.ACTION_PLAY)));
        }

        if (action == PlaybackStateCompat.ACTION_PAUSE) {
            builder
                    .addAction(new NotificationCompat.Action(
                            R.drawable.pause_button, "Pause",
                            MediaButtonReceiver.buildMediaButtonPendingIntent(
                                    context, PlaybackStateCompat.ACTION_PAUSE)));
        }

        builder
                .setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle()
                        .setShowActionsInCompactView(0)
                        .setShowCancelButton(true)
                        .setCancelButtonIntent(
                                MediaButtonReceiver.buildMediaButtonPendingIntent(
                                        context, PlaybackStateCompat.ACTION_STOP)));

        return builder.build();
    }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence name = "stream";
            String description = "music stream";
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel =
                    new NotificationChannel("1337", name, importance);
            channel.setDescription(description);

            NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
            assert notificationManager != null;
            notificationManager.createNotificationChannel(channel);
        }
    }

}
...