Controlling play or pause button using eventbus

1.1k Views Asked by At

If we open our app the news fragment is loaded and the news automatically starts to play. We are using Exoplayer for playing the news. Notification is created by Exoplayer via PlayerNotificationManager. The problem is that the play pause button doesn't follow the notification. We have implemented eventbus & it only changes the drawable. So, if we click on pause button on the notification, the button on fragment is seen as paused but when we click on it works as a pause button (instead of working as a play button).

What we intend to do is: If the notification says paused the button on fragment will be paused & then if we click on it the content will start to play.

Codes:

NewsReaderFragment.java

     public static NewsReaderFragment newInstance() {
        return new NewsReaderFragment();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        rootView = inflater.inflate(R.layout.fragment_news_reader, container, false);
        bPlay = rootView.findViewById(R.id.button_play);
        unbinder = ButterKnife.bind(this, rootView);
        NetworkInfoUtility networkInfoUtility = new NetworkInfoUtility();
        boolean net = networkInfoUtility.isNetWorkAvailableNow(getContext());
        if (!net) {
            Toast.makeText(getContext(), CHECKNET, Toast.LENGTH_LONG).show();
        }
        exoHelper = new ExoHelper(getContext(), new Player.EventListener() {
            @Override
            public void onPlayerError(ExoPlaybackException error) {
                Crashlytics.logException(error);
                Toast.makeText(getContext(), rootView.getContext().getString(R.string.server_off), Toast.LENGTH_LONG).show();
                exoHelper.ToggleButton(false);
            }
        }, bPlay, "NewsReader");

        isPlaying = true;
        setButton();
        exoHelper.startExo(rootView.getContext().getString(R.string.bbc_news));

        return rootView;
    }

    private void setButton() {
        bPlay.setOnClickListener(view -> {

            if (!isPlaying) {
                exoHelper.startExo(rootView.getContext().getString(R.string.bbc_news));
            } else {
                exoHelper.stopExo();
            }

            isPlaying = !isPlaying;
        });

    } 

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

        EventBus.getDefault().register(this);
    }

    @Override
    public void onStop() {
        
        EventBus.getDefault().unregister(this);
        super.onStop();
    }


    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEvent(ButtonEvent event)
    {

      exoHelper.ToggleButton(event.isState());

    }

Exophelper.java

    public void stopExo() {
        if (exoPlayer != null) { //if exo is running
            Log.d(TAG, "Stopping exo....");
            exoPlayer.stop();
            //playerNotificationManager.setPlayer(null);
            customPlayerNotificationManager.setPlayer(null);
            exoPlayer.release();
            exoPlayer = null;
            ToggleButton(false);

        } else {
            Log.d(TAG, "Can't stop because No exoplayer is running");
        }
    }

    public void startExo(String newUrl) {
        if (newUrl == null || newUrl.isEmpty()) {
            Log.d(TAG, "startExo: empty url");
            Toast.makeText(context, R.string.server_off, Toast.LENGTH_SHORT).show();
            ToggleButton(false); // show pause button
            return;
        }

        if (exoPlayer != null) {
            Log.d(TAG, "startExo: Exo is already running now");
            return;
        }

        iceURL = newUrl;

        BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
        final ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();

        TrackSelection.Factory trackSelectionFactory =
                new AdaptiveTrackSelection.Factory(bandwidthMeter);
        TrackSelector defaultTrackSelector =
                new DefaultTrackSelector(trackSelectionFactory);
        DefaultBandwidthMeter defaultBandwidthMeter = new DefaultBandwidthMeter();
        DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(
                context,
                Util.getUserAgent(context, context.getApplicationInfo().name),
                defaultBandwidthMeter);

        MediaSource mediaSource = new ExtractorMediaSource(
                Uri.parse(iceURL),
                dataSourceFactory,
                extractorsFactory,
                new Handler(), error -> {
        });

        exoPlayer = ExoPlayerFactory.newSimpleInstance(context, defaultTrackSelector);

        if (eventListener != null) {
            exoPlayer.addListener(eventListener);
        }
        exoPlayer.prepare(mediaSource);
        exoPlayer.setPlayWhenReady(true);

        //EventStatus(true);
          ToggleButton(true);
        //setPlayerNotificationManager(exoPlayer);
        createCustomPlayerNotificationManger(exoPlayer);


    }

public void ToggleButton(boolean state) {
        if (state) {
            Drawable img = button.getContext().getResources().getDrawable(R.drawable.play_button);
            button.setCompoundDrawablesWithIntrinsicBounds(img, null, null, null);
            button.setText(R.string.now_playing);
        } else {
            Drawable img1 = button.getContext().getResources().getDrawable(R.drawable.pause_button);
            button.setCompoundDrawablesWithIntrinsicBounds(img1, null, null, null);
            button.setText(R.string.server_off);
        }
    }

PlayerNotificationManager.java


It's a big file, so we are attaching only the receiver where we use eventbus:

public class NotificationBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Player player = PlayerNotificationManager.this.player;
        if (player == null
                || !isNotificationStarted
                || intent.getIntExtra(EXTRA_INSTANCE_ID, instanceId) != instanceId) {
            return;
        }
        String action = intent.getAction();
        if (ACTION_PLAY.equals(action)) {
            if (player.getPlaybackState() == Player.STATE_IDLE) {
                if (playbackPreparer != null) {
                    playbackPreparer.preparePlayback();
                }
            } else if (player.getPlaybackState() == Player.STATE_ENDED) {
                controlDispatcher.dispatchSeekTo(player, player.getCurrentWindowIndex(), C.TIME_UNSET);
            }
            controlDispatcher.dispatchSetPlayWhenReady(player, /* playWhenReady= */ true);

            EventBus.getDefault().post(new ButtonEvent(true));
            Log.d(TAG, "ButtonEvent: True");


        } else if (ACTION_PAUSE.equals(action)) {
            controlDispatcher.dispatchSetPlayWhenReady(player, /* playWhenReady= */ false);

            if (player.getPlaybackState() == Player.STATE_READY)
            {
                EventBus.getDefault().post(new ButtonEvent(false));
                Log.d(TAG, "ButtonEvent: False");
            }


        } else if (ACTION_STOP.equals(action)) {
            controlDispatcher.dispatchStop(player, /* reset= */ true);
        } else if (ACTION_DISMISS.equals(action)) {
            stopNotification(/* dismissedByUser= */ true);
        } else if (action != null
                && customActionReceiver != null
                && customActions.containsKey(action)) {
            customActionReceiver.onCustomAction(player, action, intent);
        }
    }
}

ButtonEvent.java

public class ButtonEvent {

public boolean state;

public ButtonEvent(boolean state) {
    this.state = state;
}

public boolean isState() {
    return state;
}

public void setState(boolean state) {
    this.state = state;
}

}

1

There are 1 best solutions below

4
JakeB On

Is it correct that isPlaying is true in this scenario, executing a second pause?

private void setButton() {
        bPlay.setOnClickListener(view -> {

            if (!isPlaying) {
                exoHelper.startExo(rootView.getContext().getString(R.string.bbc_news));
            } else {
                exoHelper.stopExo();
            }
            isPlaying = !isPlaying;
        });
    } 

Is there a reason why the state of whether it is playing it tied to the Fragment and not ExoHelper?

Maybe this can be remedied easily by re-assigning isPlaying with exoplayers event listener...

player.addListener(eventListener);

...

@Override
public void onIsPlayingChanged(boolean isPlaying) {
  if (isPlaying) {
      // player is playing
  } else {
      // player is paused
  }
}

UPDATE

Or query exoplayer directly for state:

private void setButton() {
        bPlay.setOnClickListener(view -> {
            if (!isPlaying()) {
        exoHelper.startExo(rootView.getContext().getString(R.string.bbc_news));
            } else {
                exoHelper.stopExo();
            }
        });
    } 

// this method might belong in ExoHelper?
private boolean isPlaying() {
    return player.getPlaybackState() == Player.STATE_READY && player.getPlayWhenReady();
}

Further reading https://exoplayer.dev/listening-to-player-events.html