Controlling play or pause button using eventbus - android

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;
}
}

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

Related

Exoplayer audio playing background even video was closed

Below is My fragment that contains exoplayer which will inflate with draggable panel in Activity. My problem is while swiping the draggable panel left or right video is closing but audio is still playing in background. If I swipe off the draggable panel audio also needs to closed.Tried many sources couldn't found any solutions.Also In both fragment and Activity while swipping off the draggable panel onPause() method is not triggred. Also public void onClosedToLeft() method also not getting called.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.dragpanelone, container, false);
try {
exoPlayerView = (SimpleExoPlayerView)v.findViewById(R.id.exoplayer);
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelector trackSelector = new DefaultTrackSelector(new AdaptiveTrackSelection.Factory(bandwidthMeter));
exoplayer = ExoPlayerFactory.newSimpleInstance(getActivity(), trackSelector);
Uri uri = Uri.parse(videoURL);
DefaultHttpDataSourceFactory dataSourceFactory = new DefaultHttpDataSourceFactory("exoplayer_video");
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
MediaSource mediaSource = new ExtractorMediaSource(uri, dataSourceFactory, extractorsFactory, null, null);
exoPlayerView.setPlayer(exoplayer);
exoplayer.prepare(mediaSource);
exoplayer.setPlayWhenReady(true);
} catch (Exception e){
e.printStackTrace();
}
return v;
}
#Override
public void onDestroy() {
super.onDestroy();
exoplayer.release();
}
#Override
public void onStop() {
super.onStop();
exoplayer.setPlayWhenReady(false);
}
public void pausePlayback() {
exoplayer.setPlayWhenReady(false); //pauses the playback if it's playing
}
private void releasePlayer() {
if (exoplayer != null) {
exoplayer.release();
exoplayer.setPlayWhenReady(false);
exoplayer = null;
}
}
public static void closePlayer()
{
exoplayer.clearVideoSurface();
}
}
This is my Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeDraggablepanel();
hookDraggablePanelListners();
}
public void initializeDraggablepanel(){
draggablepanel = (DraggablePanel)findViewById(R.id.draggable_panel);
draggablepanel.setFragmentManager(getSupportFragmentManager());
draggablepanel.setTopFragment(new DragpanelFragOne());
draggablepanel.setBottomFragment(new DragPanelTwo());
draggablepanel.setTopViewHeight(550);
draggablepanel.initializeView();
}
private void hookDraggablePanelListners(){
draggablepanel.setDraggableListener(new DraggableListener() {
#Override
public void onMaximized() {
}
#Override
public void onMinimized() {
}
#Override
public void onClosedToLeft() {
DragpanelFragOne.closePlayer();
Intent i = new Intent(MainActivity.this,HomeScreen.class);
startActivity(i);
}
#Override
public void onClosedToRight() {
DragpanelFragOne.closePlayer();
Intent i = new Intent(MainActivity.this,HomeScreen.class);
startActivity(i);
}
});
}
#Override
public void onPause() {
super.onPause();
DragpanelFragOne.closePlayer();
}
#Override
public void onStop() {
super.onStop();
draggablepanel.closeToLeft();
}
#Override
public void onBackPressed() {
draggablepanel.isClickToMinimizeEnabled();
Intent i = new Intent(MainActivity.this,HomeScreen.class);
startActivity(i);
}
}
Solution:
You need to call the method stop() on the exoplayer object whenever you are closing the player, like this:
if (exoPlayer != null) {
exoPlayer.setPlayWhenReady(false);
exoPlayer.stop();
exoPlayer.seekTo(0);
}
Hope this helps.

ExoPlayer recreates after screen rotation in fragment

In my App, I have fragment in which I, alongside with other, play video in ExoPlayer. I set it up as simple as possible and the player itself works flawlessly, even with media session.
But the problem is that on device rotation, the video loads again in background (there seems to be two layers - one standard, functioning normally, loading video and playing it; and second layer in background. I can hear the sound of the video shortly after the activity recreates.
I am stopping and releasing the player and media session, but it didn't help.
MediaFragment.java
public class StepViewFragment extends Fragment implements Player.EventListener{
//vars
public StepViewFragment() {
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
//attach callbacks for buttons
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_step_view, container, false);
//Bind view ButterKnife
ButterKnife.bind(this, rootView);
//get Step from Bundle
Bundle bundle = this.getArguments();
if (bundle != null) {
step = bundle.getParcelable(AppConstants.STEP_BUNDLE_KEY);
recipe = bundle.getParcelable(AppConstants.RECIPE_BUNDLE_KEY);
}
mainHandler = new Handler();
//...
//setup ui
//...
if (step.videoURL.equals("")) {
mediaCard.setVisibility(View.GONE);
} else {
playVideo();
initMediaSession();
}
return rootView;
}
public void initMediaSession (){
mExoPlayer.addListener(this);
mMediaSession = new MediaSessionCompat(getContext(), TAG);
mMediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS);
mMediaSession.setMediaButtonReceiver(null);
mStateBuilder = new PlaybackStateCompat.Builder()
.setActions(
PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_PLAY_PAUSE
);
mMediaSession.setPlaybackState(mStateBuilder.build());
mMediaSession.setCallback(new MySessionCallback());
mMediaSession.setActive(true);
}
public void playVideo() {
if (mExoPlayer == null) {
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
LoadControl loadControl = new DefaultLoadControl();
RenderersFactory renderersFactory = new DefaultRenderersFactory(getContext());
mExoPlayer = ExoPlayerFactory.newSimpleInstance(renderersFactory, trackSelector, loadControl);
mPlayerView.setPlayer(mExoPlayer);
String videoUrl = step.videoURL;
Uri mp4VideoUri = Uri.parse(videoUrl);
String userAgent = Util.getUserAgent(getContext(), "BakingApp");
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(getContext(), userAgent);
ExtractorMediaSource.Factory mediaSource = new ExtractorMediaSource.Factory(dataSourceFactory);
mExoPlayer.prepare(mediaSource.createMediaSource(mp4VideoUri));
mPlayerView.hideController();
mExoPlayer.setPlayWhenReady(true);
}
}
public void releasePlayer() {
mExoPlayer.stop();
mExoPlayer.release();
mExoPlayer = null;
mMediaSession.release();
mPlayerView = null;
}
#Override
public void onStop() {
if (mExoPlayer != null) {
releasePlayer();
}
super.onStop();
}
#Override
public void onDestroyView() {
super.onDestroyView();
if (mExoPlayer != null) {
releasePlayer();
}
}
#Override
public void onPause() {
super.onPause();
if (mExoPlayer != null) {
releasePlayer();
}
}
#Override
public void onDetach() {
super.onDetach();
if (mExoPlayer != null) {
releasePlayer();
}
}
#Override
public void onDestroy() {
super.onDestroy();
if (mExoPlayer != null){
releasePlayer();
}
}
#Override
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
}
#Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
}
#Override
public void onLoadingChanged(boolean isLoading) {
}
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
if ((playbackState == Player.STATE_READY) && playWhenReady) {
mStateBuilder.setState(PlaybackStateCompat.STATE_PLAYING, mExoPlayer.getCurrentPosition(), 1f);
} else if ((playbackState == Player.STATE_READY)){
mStateBuilder.setState(PlaybackStateCompat.STATE_PAUSED, mExoPlayer.getCurrentPosition(), 1f);
}
mMediaSession.setPlaybackState(mStateBuilder.build());
Log.d("HOVNOOOO", "Playback State Changed");
}
#Override
public void onRepeatModeChanged(int repeatMode) {
}
#Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
}
#Override
public void onPlayerError(ExoPlaybackException error) {
}
#Override
public void onPositionDiscontinuity(int reason) {
}
#Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
}
#Override
public void onSeekProcessed() {
}
private class MySessionCallback extends MediaSessionCompat.Callback {
#Override
public void onPlay() {
mExoPlayer.setPlayWhenReady(true);
}
#Override
public void onPause() {
mExoPlayer.setPlayWhenReady(false);
}
}
Solved...
I was using add() to create the Fragment, so on rotation it added new one.
Using replace instead solved the problem.

ExoPlayer resume on same position on rotate screen

I am using ExoPlayer in my activity,What i want is to smoothly play video in portrait and landscape mode.For this purpose what I am doing is in onpause I save the currentPlayerPosition and seek player to that position in onresume but while rotating it face a jerk and video is stopped for a while and played to the saved position.
My code is below please help me how i can smoothly switch the mode portrait and landscape.Thanks
#Override
public void onPause() {
super.onPause();
if (mExoPlayerView != null && mExoPlayerView.getPlayer() != null) {
mResumeWindow = mExoPlayerView.getPlayer().getCurrentWindowIndex();
mResumePosition = Math.max(0, mExoPlayerView.getPlayer().getContentPosition());
mExoPlayerView.getPlayer().release();
}
}
#Override
public void onDestroy() {
super.onDestroy();
if (mExoPlayerView.getPlayer() != null)
mExoPlayerView.getPlayer().release();
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt(STATE_RESUME_WINDOW, mResumeWindow);
outState.putLong(STATE_RESUME_POSITION, mResumePosition);
outState.putBoolean(STATE_PLAYER_FULLSCREEN, mExoPlayerFullscreen);
super.onSaveInstanceState(outState);
}
#Override
protected void onResume() {
super.onResume();
if (mExoPlayerView == null) {
mExoPlayerView = (SimpleExoPlayerView) findViewById(R.id.exoplayer);
videoURL = getIntent().getStringExtra("url");
postID = getIntent().getIntExtra("UserID", 0);
String userAgent = Util.getUserAgent(Vid.this, getApplicationContext().getApplicationInfo().packageName);
DefaultHttpDataSourceFactory httpDataSourceFactory = new DefaultHttpDataSourceFactory(userAgent, null, DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS, DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, true);
DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(Vid.this, null, httpDataSourceFactory);
Uri daUri = Uri.parse(videoURL);
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
if (daUri.toString().startsWith("https://player.vimeo"))
mVideoSource = new HlsMediaSource(daUri, dataSourceFactory, 1, null, null);
else
mVideoSource = new ExtractorMediaSource(daUri, dataSourceFactory, extractorsFactory, null, null);
initExoPlayer();
} else {
resumeExoPlayer();
}
}
private void resumeExoPlayer() {
boolean haveResumePosition = mResumeWindow != C.INDEX_UNSET;
if (haveResumePosition) {
hideKeyboard();
hideProgress();
mExoPlayerView.getPlayer().seekTo(mResumeWindow, mResumePosition);
}
}
private void initExoPlayer() {
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
LoadControl loadControl = new DefaultLoadControl();
SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(new DefaultRenderersFactory(this), trackSelector, loadControl);
mExoPlayerView.setPlayer(player);
boolean haveResumePosition = mResumeWindow != C.INDEX_UNSET;
if (haveResumePosition) {
hideKeyboard();
hideProgress();
mExoPlayerView.getPlayer().seekTo(mResumeWindow, mResumePosition);
}
mExoPlayerView.getPlayer().prepare(mVideoSource);
mExoPlayerView.getPlayer().setPlayWhenReady(true);
mExoPlayerView.getPlayer().addListener(new Player.EventListener() {
#Override
public void onTimelineChanged(Timeline timeline, Object manifest) {
}
#Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
}
#Override
public void onLoadingChanged(boolean isLoading) {
}
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
if (playbackState == ExoPlayer.STATE_ENDED) {
hideProgress();
mExoPlayerView.getPlayer().seekTo(0);
mExoPlayerView.getPlayer().setPlayWhenReady(false);
} else if (playbackState == ExoPlayer.STATE_BUFFERING) {
} else if (playbackState == ExoPlayer.STATE_READY) {
hideProgress();
if (preferenceManager.getLoggedIn()) {
APIGetComment();
}
}
}
#Override
public void onRepeatModeChanged(int repeatMode) {
}
#Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
}
#Override
public void onPlayerError(ExoPlaybackException error) {
hideProgress();
finish();
}
#Override
public void onPositionDiscontinuity(int reason) {
}
#Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
}
#Override
public void onSeekProcessed() {
}
});
}
Finally, After wasting 2 days I found it.
Simple add it in the manifest and will work on all android version ?
android:configChanges="orientation|screenSize|layoutDirection"
cheers!
If you want the video to resume on orientation change, you can add this to your manifest android:configChanges="keyboardHidden|orientation|screenSize"
<activity
<activity
android:name=".MainActivity"
android:name=".MainActivity"
android:label="#string/app_name"
android:label="#string/app_name"
+ android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="#style/AppTheme.NoActionBar"
android:theme="#style/AppTheme.NoActionBar"
android:icon="#mipmap/ic_launcher_2">
android:icon="#mipmap/ic_launcher_2">
<intent-filter>
<intent-filter>
No need of any additional coding, simply add this line
android:configChanges="keyboardHidden|orientation|screenSize"
in your AndroidManifest.xml's activity section.
I also wasted quite a lot time in this. Take a look at it EXO PLAYER 2.11.2
implementation 'com.google.android.exoplayer:exoplayer:2.11.2'
STEP - 1 Make an activity in which string url is passed as intent.
public class VideoPlayerActivity extends Activity {
public static final String sURL_KEY = "STREAMING_URL_KEY";
public static final String sTOAST_TEXT = "Unable to stream, no media found";
static final String LOADING = "PLAYER_LOADING";
static final String STOPPED = "PLAYER_STOPPED";
static final String PAUSED = "PLAYER_PAUSED";
static final String PLAYING = "PLAYER_PLAYING";
static final String IDLE = "PLAYER_IDLE";
private static final String TAG = "StreamMediaActivity";
int orientation;
private Uri streamUrl;
private SimpleExoPlayer mPlayer;
private PlayerView playerView;
private ProgressBar progressBar;
private String mPlayerStatus;
private long mPlaybackPosition = 0L;
private boolean mIsPlayWhenReady = true;
private int mCurrentWindow = 0;
private Display display;
private String STATE_RESUME_WINDOW = "resumeWindow";
private String STATE_RESUME_POSITION = "resumePosition";
private String STATE_PLAYER_FULLSCREEN = "playerFullscreen";
private boolean mExoPlayerFullscreen = false;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fullScreen();
display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
orientation = display.getRotation();
setContentView(R.layout.activity_video_player);
playerView = findViewById(R.id.player_view);
progressBar = findViewById(R.id.progressBar_player);
// Pass a string uri to this class
String urlString = getIntent().getStringExtra(sURL_KEY);
if (urlString != null) {
streamUrl = Uri.parse(urlString);
} else {
Toast.makeText(this, sTOAST_TEXT, Toast.LENGTH_LONG).show();
finish();
}
}
#Override
protected void onStart() {
super.onStart();
initPlayer();
}
#Override
protected void onResume() {
super.onResume();
if (mPlaybackPosition != 0L && mPlayer != null) {
mPlayer.seekTo(mCurrentWindow, mPlaybackPosition);
}
}
#Override
protected void onStop() {
super.onStop();
}
#Override protected void onPause() {
super.onPause();
releasePlayer();
}
private void initPlayer() {
// ESTABLISH THE DATA SOURCE FROM URL
// here i'm playing local video file that's
// why using the DefaultDataSourceFactory but you
//may use DefaultHttpDataSourceFactory to stream
//online videos
DataSource.Factory dataSourceFactory =
new DefaultDataSourceFactory(this, Util.getUserAgent(this, getApplicationInfo().name));
MediaSource mediaSource =
new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(
streamUrl);
// CREATE A NEW INSTANCE OF EXO PLAYER
if (mPlayer == null) {
mPlayer = new SimpleExoPlayer.Builder(this, new DefaultRenderersFactory(this)).build();
playerView.setPlayer(mPlayer);
progressBar.setVisibility(View.VISIBLE);
}
mPlayer.setPlayWhenReady(mIsPlayWhenReady);
mPlayer.seekTo(mCurrentWindow, mPlaybackPosition);
// PREPARE MEDIA PLAYER
mPlayer.prepare(mediaSource, true, false);
mPlayer.addListener(new Player.EventListener() {
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
switch (playbackState) {
case Player.STATE_BUFFERING:
mPlayerStatus = LOADING;
runOnUiThread(() -> progressBar.setVisibility(View.VISIBLE));
break;
case Player.STATE_ENDED:
mPlayerStatus = STOPPED;
break;
case Player.STATE_READY:
mPlayerStatus = (playWhenReady) ? PLAYING : PAUSED;
runOnUiThread(() -> progressBar.setVisibility(View.INVISIBLE));
break;
default:
mPlayerStatus = IDLE;
break;
}
}
#Override
public void onPlayerError(ExoPlaybackException error) {
Toast.makeText(VideoPlayerActivity.this, "Something went wrong", Toast.LENGTH_SHORT).show();
finish();
}
});
}
#Override protected void onSaveInstanceState(Bundle outState) {
mExoPlayerFullscreen = !mExoPlayerFullscreen;
super.onSaveInstanceState(outState);
outState.putInt(STATE_RESUME_WINDOW, mCurrentWindow);
outState.putLong(STATE_RESUME_POSITION, mPlaybackPosition);
outState.putBoolean(STATE_PLAYER_FULLSCREEN, mExoPlayerFullscreen);
super.onSaveInstanceState(outState);
}
public void fullScreen() {
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);
}
private void releasePlayer() {
if (mPlayer != null) {
mPlayer.stop();
mPlaybackPosition = mPlayer.getCurrentPosition();
mCurrentWindow = mPlayer.getCurrentWindowIndex();
mIsPlayWhenReady = mPlayer.getPlayWhenReady();
playerView.setPlayer(null);
mPlayer.release();
mPlayer = null;
}
}
}
Step 2 : Make the XML layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/black">
<FrameLayout
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.exoplayer2.ui.PlayerView
android:id="#+id/player_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
android:keepScreenOn="true"
app:use_controller="true"
app:resize_mode="fit"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="#+id/progressBar_player"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
STEP 3: start VideoPlayerActivity using intent from another activity
Intent streamVideoIntent = new Intent(context, VideoPlayerActivity.class);
streamVideoIntent.putExtra(sURL_KEY, stringUrl);
context.startActivity(streamVideoIntent);
STEP 4 : Lastly add activity to manifest
<activity android:name=".ui.videoplayer.VideoPlayerActivity"
android:configChanges="orientation|screenSize|layoutDirection"
/>

Android VideoView buffering

I'm working on the Android TV app which uses VideoView to play the video from the url. Each time the video is paused and then resumed - it takes some time to pre-download it first (few seconds during which progress bar appears). The goal is to buffer the video during playback so that when I pause it and then resume - it resumes from pre-buffered state immediately without delay. I've also tried videoView.resume() method, but it doesn't help either. Is there a way to do that or am I doing something wrong?
Here is the code which plays/resumes the video:
public void onFragmentPlayPause(final Video video,
final VideoQuality quality,
final int position,
final Boolean play) {
stopSeeking();
videoView.setVideoPath(video.videoUrl(quality));
if (position == 0 || playbackState == LeanbackPlaybackState.IDLE) {
setupCallbacks();
playbackState = LeanbackPlaybackState.IDLE;
}
if (play && playbackState != LeanbackPlaybackState.PLAYING) {
progressBar.setVisibility(View.VISIBLE);
playbackState = LeanbackPlaybackState.PLAYING;
if (position > 0) {
videoView.seekTo(position);
videoView.start();
}
playbackFragment.startProgressObservation(progressFlowable());
} else {
playbackState = LeanbackPlaybackState.PAUSED;
videoView.pause();
playbackFragment.stopProgressObservation();
}
updatePlaybackState(position);
updateMetadata(video);
}
Unfortunately, I've didn't find the way to achieve this with VideoView, only using ExoPlayer, thanks to #pskink for the right direction. The API was returning mp4 videos, so I've used ExtractorMediaSource. The complete demo example with support of multiple formats can be found on ExoPlayer GitHub page.
Here is the final code I've ended up with using ExoPlayer:
private void playPause(final Video video, final int position, final Boolean play) {
if (position == 0 || playbackState == LeanbackPlaybackState.IDLE) {
setupCallbacks();
playbackState = LeanbackPlaybackState.IDLE;
}
if (play && playbackState != LeanbackPlaybackState.PLAYING) {
progressBar.setVisibility(View.VISIBLE);
playbackState = LeanbackPlaybackState.PLAYING;
player.start();
playbackFragment.startProgressObservation(progressFlowable());
} else {
playbackState = LeanbackPlaybackState.PAUSED;
player.pause();
playbackFragment.stopProgressObservation();
}
updatePlaybackState(position);
updateMetadata(video);
}
And Player implementation:
public class Player implements MediaController.MediaPlayerControl, ExoPlayer.EventListener {
private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter();
private final SimpleExoPlayer exoPlayer;
private final Context context;
private OnErrorListener onErrorListener;
private OnPreparedListener onPreparedListener;
private OnCompletionListener onCompletionListener;
private String url;
public interface OnErrorListener {
void onError(final Exception e);
}
public interface OnPreparedListener {
void onPrepared();
}
public interface OnCompletionListener {
void onComplete();
}
public Player(final Context context) {
this.context = context;
final #SimpleExoPlayer.ExtensionRendererMode int extensionRendererMode =
SimpleExoPlayer.EXTENSION_RENDERER_MODE_OFF;
final TrackSelection.Factory videoTrackSelectionFactory =
new AdaptiveTrackSelection.Factory(BANDWIDTH_METER);
this.exoPlayer = ExoPlayerFactory.newSimpleInstance(
context,
new DefaultTrackSelector(videoTrackSelectionFactory),
new DefaultLoadControl(),
null,
extensionRendererMode
);
this.exoPlayer.addListener(this);
}
#Override
public boolean canPause() {
return true;
}
#Override
public boolean canSeekBackward() {
return true;
}
#Override
public boolean canSeekForward() {
return true;
}
#Override
public int getAudioSessionId() {
throw new UnsupportedOperationException();
}
#Override
public int getBufferPercentage() {
return exoPlayer.getBufferedPercentage();
}
#Override
public int getCurrentPosition() {
return exoPlayer.getDuration() == com.google.android.exoplayer2.C.TIME_UNSET ? 0
: (int) exoPlayer.getCurrentPosition();
}
#Override
public int getDuration() {
return exoPlayer.getDuration() == com.google.android.exoplayer2.C.TIME_UNSET ? 0
: (int) exoPlayer.getDuration();
}
#Override
public boolean isPlaying() {
return exoPlayer.getPlayWhenReady();
}
#Override
public void start() {
exoPlayer.setPlayWhenReady(true);
}
#Override
public void pause() {
exoPlayer.setPlayWhenReady(false);
}
public void stop() {
exoPlayer.seekTo(0);
pause();
}
public void setOnErrorListener(final OnErrorListener onErrorListener) {
this.onErrorListener = onErrorListener;
}
public void setOnPreparedListener(final OnPreparedListener onPreparedListener) {
this.onPreparedListener = onPreparedListener;
}
public void setOnCompletionListener(final OnCompletionListener onCompletionListener) {
this.onCompletionListener = onCompletionListener;
}
public void setVolume(final float volume) {
exoPlayer.setVolume(volume);
}
public void release() {
exoPlayer.release();
}
public void updateUrl(final String url) {
this.url = url;
exoPlayer.prepare(buildMediaSource(Uri.parse(url)));
}
public SimpleExoPlayer exoPlayer() {
return exoPlayer;
}
#Override
public void seekTo(final int timeMillis) {
exoPlayer.seekTo(timeMillis);
}
#Override
public void onTimelineChanged(final Timeline timeline, final Object manifest) {
}
#Override
public void onTracksChanged(final TrackGroupArray trackGroups, final TrackSelectionArray trackSelections) {
}
#Override
public void onLoadingChanged(final boolean isLoading) {
}
#Override
public void onPlayerStateChanged(final boolean playWhenReady, final int playbackState) {
if (playbackState == ExoPlayer.STATE_READY) {
onPreparedListener.onPrepared();
}
if (playbackState == ExoPlayer.STATE_ENDED) {
onCompletionListener.onComplete();
}
}
#Override
public void onPlayerError(final ExoPlaybackException error) {
onErrorListener.onError(error);
}
#Override
public void onPositionDiscontinuity() {
}
public String url() {
return url;
}
private MediaSource buildMediaSource(final Uri uri) {
return new ExtractorMediaSource(uri, buildDataSourceFactory(true), new DefaultExtractorsFactory(),
null, null);
}
private DataSource.Factory buildDataSourceFactory(final DefaultBandwidthMeter bandwidthMeter) {
return new DefaultDataSourceFactory(context, bandwidthMeter,
buildHttpDataSourceFactory(bandwidthMeter));
}
private HttpDataSource.Factory buildHttpDataSourceFactory(final DefaultBandwidthMeter bandwidthMeter) {
return new DefaultHttpDataSourceFactory(Util.getUserAgent(context, Application.TAG), bandwidthMeter);
}
private DataSource.Factory buildDataSourceFactory(final boolean useBandwidthMeter) {
return buildDataSourceFactory(useBandwidthMeter ? BANDWIDTH_METER : null);
}
}

Android back to main activity from MusicService notification

I'm working on a music player for android and i'm stuck at this problem.
By now i can play a song with musicservice and send it to background, i also display a notification with current playing song.
What i need is to re-open the main activity from the song notification and continue playing the song, it actually starts the desired activity but the music service is re-created and it stops the current playing song.
Here is my code.
MusicService.java
public class MusicService extends Service implements
MediaPlayer.OnPreparedListener,
MediaPlayer.OnErrorListener,
MediaPlayer.OnCompletionListener {
private final IBinder musicBind = new MusicBinder();
//media player
private MediaPlayer player;
//song list
private ArrayList<SongModel> songs;
//current position
private int songPosition;
public MusicService() {
}
public void onCreate() {
//create the service
super.onCreate();
//initialize position
songPosition = 0;
//create player
player = new MediaPlayer();
initMusicPlayer();
}
public void initMusicPlayer() {
//set player properties
player.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setOnPreparedListener(this);
player.setOnCompletionListener(this);
player.setOnErrorListener(this);
}
public void setList(ArrayList<SongModel> theSongs) {
songs = theSongs;
}
public class MusicBinder extends Binder {
public MusicService getService() {
return MusicService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return musicBind;
}
#Override
public boolean onUnbind(Intent intent) {
player.stop();
player.release();
return false;
}
public int getPosition() {
return player.getCurrentPosition();
}
public int getCurrenListPosition() {
return songPosition;
}
public int getDuration() {
return player.getDuration();
}
public boolean isPlaying() {
return player.isPlaying();
}
public void pausePlayer() {
player.pause();
}
public void stopPlayer() {
player.stop();
}
public void seekToPosition(int posn) {
player.seekTo(posn);
}
public void start() {
player.start();
}
public void playSong() {
try {
//play a song
player.reset();
SongModel playSong = songs.get(songPosition);
String trackUrl = playSong.getFileUrl();
player.setDataSource(trackUrl);
player.prepareAsync();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onCompletion(MediaPlayer mp) {
if (mp.getCurrentPosition() == 0) {
mp.reset();
}
}
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mp.reset();
return false;
}
#Override
public void onPrepared(MediaPlayer mp) {
//start playback
mp.start();
SongModel playingSong = songs.get(songPosition);
Intent intent = new Intent(this, NavDrawerMainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Builder builder = new Notification.Builder(this);
builder.setContentIntent(pendingIntent)
.setSmallIcon(R.drawable.ic_action_playing)
.setTicker(playingSong.getTitle())
.setOngoing(true)
.setContentTitle(playingSong.getTitle())
.setContentText(playingSong.getArtistName());
Notification notification = builder.build();
startForeground((int) playingSong.getSongId(), notification);
}
#Override
public void onDestroy() {
stopForeground(true);
}
public void setSong(int songIndex) {
songPosition = songIndex;
}
}
DiscoverSongsFragment.java
public class DiscoverSongsFragment extends Fragment
implements MediaController.MediaPlayerControl {
JazzyGridView songsContainer;
SongsHelper songsHelper;
SongsAdapter songsAdapter;
ArrayList<SongModel> songsArrayList;
ConnectionState connectionState;
Context mContext;
private static View rootView;
SongModel currentSong;
SeekBar nowPlayingSeekBar;
final Handler handler = new Handler();
// this value contains the song duration in milliseconds.
// Look at getDuration() method in MediaPlayer class
int mediaFileLengthInMilliseconds;
View nowPlayingLayout;
boolean nowPlayingLayoutVisible;
TextView nowPlayingTitle;
TextView nowPlayingArtist;
ImageButton nowPlayingCover;
ImageButton nowPlayingStop;
private MusicService musicService;
private Intent playIntent;
private boolean musicBound = false;
private boolean playbackPaused = false;
private int mCurrentTransitionEffect = JazzyHelper.SLIDE_IN;
public static DiscoverSongsFragment newInstance() {
return new DiscoverSongsFragment();
}
public DiscoverSongsFragment() {
// Required empty public constructor
}
#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_discover_songs, container, false);
mContext = rootView.getContext();
setupViews(rootView);
return rootView;
}
#Override
public void onStart() {
super.onStart();
if (playIntent == null) {
playIntent = new Intent(mContext, MusicService.class);
mContext.bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
mContext.startService(playIntent);
}
}
#Override
public void onResume() {
super.onResume();
if (isPlaying()) {
showNowPlayingLayout();
primarySeekBarProgressUpdater();
}
}
#Override
public void onDestroy() {
mContext.stopService(playIntent);
musicService = null;
super.onDestroy();
}
private void hideNowPlayingLayout() {
nowPlayingLayoutVisible = false;
nowPlayingLayout.setVisibility(View.GONE);
Animation animationFadeIn = AnimationUtils.loadAnimation(mContext, R.anim.fade_out);
nowPlayingLayout.startAnimation(animationFadeIn);
}
private void showNowPlayingLayout() {
nowPlayingLayoutVisible = true;
nowPlayingLayout.setVisibility(View.VISIBLE);
Animation animationFadeIn = AnimationUtils.loadAnimation(mContext, R.anim.fade_in);
nowPlayingLayout.startAnimation(animationFadeIn);
}
private void setupViews(View rootView) {
songsHelper = new SongsHelper();
songsArrayList = new ArrayList<SongModel>();
connectionState = new ConnectionState(mContext);
songsAdapter = new SongsAdapter(mContext, songsArrayList);
nowPlayingLayout = rootView.findViewById(R.id.nowPlayingLayout);
nowPlayingLayout.setVisibility(View.GONE);
nowPlayingLayoutVisible = false;
songsContainer = (JazzyGridView) rootView.findViewById(R.id.songsContainerView);
songsContainer.setTransitionEffect(mCurrentTransitionEffect);
songsContainer.setAdapter(songsAdapter);
songsContainer.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
musicService.setSong(position);
musicService.playSong();
if (playbackPaused) {
playbackPaused = false;
}
currentSong = songsArrayList.get(position);
// gets the song length in milliseconds from URL
mediaFileLengthInMilliseconds = getDuration();
if (currentSong != null) {
nowPlayingTitle.setText(currentSong.getTitle());
nowPlayingArtist.setText(currentSong.getArtistName());
nowPlayingCover.setImageBitmap(currentSong.getCoverArt());
}
primarySeekBarProgressUpdater();
if (!nowPlayingLayoutVisible) {
showNowPlayingLayout();
}
}
});
nowPlayingSeekBar = (SeekBar) rootView.findViewById(R.id.nowPlayingSeekbar);
nowPlayingSeekBar.setMax(99);
nowPlayingTitle = (TextView) rootView.findViewById(R.id.nowPlayingTitle);
nowPlayingArtist = (TextView) rootView.findViewById(R.id.nowPlayingArtist);
nowPlayingStop = (ImageButton) rootView.findViewById(R.id.nowPlayingStop);
nowPlayingStop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (isPlaying()) {
currentSong = null;
playbackPaused = false;
musicService.stopPlayer();
mediaFileLengthInMilliseconds = 0;
nowPlayingSeekBar.setProgress(0);
hideNowPlayingLayout();
}
}
});
nowPlayingCover = (ImageButton) rootView.findViewById(R.id.nowPlayingCover);
nowPlayingCover.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
Intent intent = new Intent(mContext, SongDetailsActivity.class);
intent.putExtra("Title", currentSong.getTitle());
intent.putExtra("Artist", currentSong.getArtistName());
intent.putExtra("Album", currentSong.getAlbumName());
intent.putExtra("Genre", currentSong.getGenre());
intent.putExtra("CoverUrl", currentSong.getCoverArtUrl());
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
});
getSongs();
hideNowPlayingLayout();
}
private void getSongs() {
if (!connectionState.isConnectedToInternet()) {
}
songsAdapter.clear();
String songsUrl = Constants.getAPI_SONGS_URL();
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(songsUrl, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray jsonArray) {
if (jsonArray != null) {
for (int i = 0; i < jsonArray.length(); i++) {
try {
JSONObject jsonObject = jsonArray.getJSONObject(i);
SongModel song = songsHelper.getSongFromJson(jsonObject);
songsAdapter.add(song);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
}
});
AppController.getInstance().addToRequestQueue(jsonArrayRequest);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
#Override
public void onDetach() {
super.onDetach();
}
/**
* Method which updates the SeekBar primary progress by current song playing position
*/
private void primarySeekBarProgressUpdater() {
nowPlayingSeekBar.setProgress((int) (((float) getCurrentPosition() / getDuration()) * 100));
//if (isPlaying()) {
Runnable runnable = new Runnable() {
public void run() {
primarySeekBarProgressUpdater();
}
};
handler.postDelayed(runnable, 1000);
//}
}
#Override
public void start() {
musicService.start();
}
#Override
public void pause() {
playbackPaused = true;
musicService.pausePlayer();
}
#Override
public int getDuration() {
if (musicService != null && musicBound && musicService.isPlaying()) {
return musicService.getDuration();
}
return 0;
}
#Override
public int getCurrentPosition() {
if (musicService != null && musicBound && musicService.isPlaying()) {
return musicService.getPosition();
}
return 0;
}
public int getCurrentListPosition() {
if (musicService != null && musicBound && musicService.isPlaying()) {
return musicService.getCurrenListPosition();
}
return 0;
}
#Override
public void seekTo(int pos) {
musicService.seekToPosition(pos);
}
#Override
public boolean isPlaying() {
if (musicService != null && musicBound && musicService.isPlaying()) {
return musicService.isPlaying();
}
return false;
}
#Override
public int getBufferPercentage() {
return 0;
}
#Override
public boolean canPause() {
return true;
}
#Override
public boolean canSeekBackward() {
return true;
}
#Override
public boolean canSeekForward() {
return true;
}
#Override
public int getAudioSessionId() {
return 0;
}
//connect to the service
private ServiceConnection musicConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicService.MusicBinder binder = (MusicService.MusicBinder) service;
//get service
musicService = binder.getService();
//pass list
musicService.setList(songsArrayList);
musicBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
musicBound = false;
}
};
}
(The fragment also re-creates itself when navigating through drawer menu items)
I hope somebody can help me achieve this. I dont know how to maintane the state when re-starting the MainActivity (by the way, im using navdrawer to hold fragments)
Include the currently playing song in your notification intent. Update the intent as the song changes. Include the flag to clear top and the flag to update current in the notification intent. :( sorry IDK if I have the flags right for your situation but you'll have a place to do more research.
In your service where you create the notification intent.
// link the notifications to the recorder activity
Intent resultIntent = new Intent(context, KmlReader.class);
resultIntent
.setAction(ServiceLocationRecorder.INTENT_COM_GOSYLVESTER_BESTRIDES_LOCATION_RECORDER);
resultIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent resultPendingIntent = PendingIntent
.getActivity(context, 0, resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
return mBuilder.build();
}
Then in main onCreate check the bundle for the name of the currently playing song and display it. Notice how I check for the existence of a bundle key before using it.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
String intentaction = intent.getAction();
// First Run checks
if (savedInstanceState == null) {
// first run init
...
} else {
// get the saved_Instance state
// always get the default when key doesn't exist
// default is null for this example
currentCameraPosition = savedInstanceState
.containsKey(SAVED_INSTANCE_CAMERA_POSITION) ? (CameraPosition) savedInstanceState
.getParcelable(SAVED_INSTANCE_CAMERA_POSITION) : null;
...

Categories

Resources