Problem:
I have recyclerview and mediaplayer
I have many seekbars (managed by RecyclerView.Adapter),By changing the seekbar of one row item , it automatically change the seekbar of previous or next row.
Main problem is second last item of recyclerview is playing the song and i change the last item's seekbar ,it also change the second last item's seekbar.
I'm guessing two views are using the same reference .
#ViewholderClass
public class AudioViewHolder extends BaseHolder<ChatViewModelList> {
private Context context;
TextView tvTimestamp;
ImageView ivUser;
private final TextView startTime;
static PlayAudioFragment playAudioFragment;
private View loadingAudio;
private ImageView playAudio;
private TextView durationAudio;
private SeekBar progressAudio;
public AudioViewHolder(View itemView, Context context, PlayAudioFragment playAudioFragment) {
super(itemView);
this.context = context;
tvTimestamp = (TextView) itemView.findViewById(R.id.ImgTime);
ivUser = (ImageView) itemView.findViewById(R.id.ContactListIcon);
this.playAudioFragment = playAudioFragment;
loadingAudio = itemView.findViewById(R.id.chatMessageLoadingAudio);
playAudio = (ImageView) itemView.findViewById(R.id.chatMessagePlayAudio);
progressAudio = (SeekBar) itemView.findViewById(R.id.chatMessageProgressAudio);
durationAudio = (TextView) itemView.findViewById(R.id.chatMessageDurationAudio);
startTime = (TextView) itemView.findViewById(R.id.startTime);
}
#Override
public void BindData(final ChatViewModelList model) {
setIvUser(model.getMessage().getUserModel().getPhoto_profile());
setTvTimestamp(model.getMessage().getTimeStamp());
if (model.getMessage().getFileModel().getType().equals(Media.Type.Audio)) {
startTime.setText(TimeFormatter.getDurationString(0));
progressAudio.setProgress(0);
progressAudio.setMax(100);
playAudio.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FileModel fileModel = model.getMessage().getFileModel();
if (playAudioFragment.isStopped() || !playAudioFragment.getCurrentMedia().equals(fileModel)) {
playAudioFragment.resetPlayback();
playAudioFragment.setCustomPlayback(playAudio, durationAudio, loadingAudio, progressAudio);
playAudioFragment.loadNewMedia(fileModel);
} else {
playAudioFragment.togglePlayback();
}
}
});
if (!model.getMessage().getFileModel().equals(playAudioFragment.getCurrentMedia())) {
loadingAudio.setVisibility(View.GONE);
progressAudio.setProgress(0);
playAudio.setImageResource(R.drawable.ic_play_arrow_blue_36dp);
int duration = (int) model.getMessage().getFileModel().getDuration();
long minutes = TimeUnit.MILLISECONDS.toMinutes(duration);
long seconds = TimeUnit.MILLISECONDS.toSeconds(duration)
- TimeUnit.MINUTES.toSeconds(minutes);
durationAudio.setText(String.format("%02d:%02d", minutes, seconds));
if (playAudioFragment.isPlayView(playAudio)) {
playAudioFragment.resetPlayback();
}
} else {
playAudioFragment.setCustomPlayback(playAudio, durationAudio, loadingAudio, progressAudio);
}
}
}
public void setIvUser(String urlPhotoUser) {
if (ivUser == null) return;
Glide.with(ivUser.getContext()).load(urlPhotoUser).centerCrop().placeholder(R.drawable.ic_menu_camera).transform(new CircleTransform(ivUser.getContext())).override(40, 40).into(ivUser);
}
public void setTvTimestamp(String timestamp) {
if (tvTimestamp == null) return;
tvTimestamp.setText(DateUtils.convertMillisecondsToTime(Long.valueOf(timestamp)));
}
}
And code of Fragment for playing audio.
public class PlayAudioFragment extends DialogFragment {
public static final String TAG = "RecordAudioFragment";
public static final int MAX_DURATION_MS = 50 * 1000;
public static final int IDLE_STATUS = 0;
public static final int READY_STATUS = 2;
public static final int PLAYER_STATUS = 3;
public static final int PLAYING_STATUS = 0;
public static final int PAUSED_STATUS = 1;
public static final int STOPPED_STATUS = 2;
public static final String EXTRA_MEDIA = "media";
public TextView startTime;
public TextView endTime;
public ImageView play;
public SeekBar progress;
public TextView mainAction;
public TextView cancel;
public View loadingContainer;
public Handler handler;
public static File recordedAudio;
public MediaRecorder mediaRecorder;
public MediaPlayer mediaPlayer;
public int recordingStatus = IDLE_STATUS;
public int playbackStatus = STOPPED_STATUS;
public int duration = 0;
public CountDownTimer timer;
private RelativeLayout root;
private FileModel media;
public static PlayAudioFragment newInstance(Media media) {
Bundle args = new Bundle();
args.putParcelable(EXTRA_MEDIA, media);
PlayAudioFragment fragment = new PlayAudioFragment();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_record_audio, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setupObjects();
setupView(view);
setupDataIfExists();
}
public void setupDataIfExists() {
Bundle args = getArguments();
if (args != null && args.containsKey(EXTRA_MEDIA)) {
media = args.getParcelable(EXTRA_MEDIA);
switchRecordingStatus(PLAYER_STATUS);
root.setVisibility(View.VISIBLE);
}
}
public void setupView(View view) {
loadingContainer = view.findViewById(R.id.loadingContainer);
endTime = (TextView) view.findViewById(R.id.endTime);
endTime.setText(TimeFormatter.getDurationStringFromMillis(MAX_DURATION_MS));
startTime = (TextView) view.findViewById(R.id.startTime);
progress = (SeekBar) view.findViewById(R.id.progress);
root = (RelativeLayout) view.findViewById(R.id.root);
play = (ImageView) view.findViewById(R.id.play);
play.setOnClickListener(onPlayClickListener);
setCustomPlayback(play, startTime, loadingContainer, progress);
mainAction = (TextView) view.findViewById(R.id.mainAction);
cancel = (TextView) view.findViewById(R.id.cancel);
cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dismiss();
}
});
}
public void setCustomPlayback(ImageView play, TextView duration, View loadingContainer, SeekBar progress) {
this.loadingContainer = loadingContainer;
this.startTime = duration;
this.startTime.setText(TimeFormatter.getDurationString(0));
this.play = play;
this.progress = progress;
this.progress.setOnSeekBarChangeListener(onSeekBarChangeListener);
setupObjects();
if (recordingStatus == PLAYER_STATUS) {
switchPlaybackStatus(PLAYING_STATUS);
handler.post(playRunnable);
}
}
public SeekBar.OnSeekBarChangeListener onSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (mediaPlayer != null && fromUser) {
mediaPlayer.seekTo(progress);
handler.removeCallbacks(playRunnable);
long minutes = TimeUnit.MILLISECONDS.toMinutes(mediaPlayer.getCurrentPosition());
long seconds = TimeUnit.MILLISECONDS.toSeconds(mediaPlayer.getCurrentPosition())
- TimeUnit.MINUTES.toSeconds(minutes);
startTime.setText(String.format("%02d:%02d", minutes, seconds));
updateSeekBar();
} else if (mediaPlayer == null && fromUser) {
prepareMediaPlayerFromPoint(progress);
updateSeekBar();
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
if (mediaPlayer != null) {
// remove message Handler from updating progress bar
handler.removeCallbacks(playRunnable);
}
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (mediaPlayer != null) {
handler.removeCallbacks(playRunnable);
mediaPlayer.seekTo(seekBar.getProgress());
long minutes = TimeUnit.MILLISECONDS.toMinutes(mediaPlayer.getCurrentPosition());
long seconds = TimeUnit.MILLISECONDS.toSeconds(mediaPlayer.getCurrentPosition())
- TimeUnit.MINUTES.toSeconds(minutes);
startTime.setText(String.format("%02d:%02d", minutes, seconds));
updateSeekBar();
}
}
};
private void prepareMediaPlayerFromPoint(int progresss) {
mediaPlayer = new MediaPlayer();
try {
Uri uri = Uri.fromFile(new File(media.getUrl_file()));
String path = FileHelper.getPath(getActivity(), uri);
mediaPlayer.setDataSource(path);
mediaPlayer.prepare();
progress.setMax(mediaPlayer.getDuration());
mediaPlayer.seekTo(progresss);
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
}
});
} catch (IOException e) {
}
}
public void loadNewMedia(FileModel media) {
this.media = media;
stopCompletely();
switchRecordingStatus(PLAYER_STATUS);
}
public boolean isStopped() {
return playbackStatus == STOPPED_STATUS;
}
public boolean isPlayView(View play) {
return this.play != null && this.play.equals(play);
}
public View.OnClickListener onPlayClickListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
togglePlayback();
}
};
public void setupObjects() {
handler = new Handler();
}
#Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
stopCompletely();
}
#Override
public void onDestroy() {
super.onDestroy();
handler.removeCallbacks(playRunnable);
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
}
public Runnable playRunnable = new Runnable() {
#Override
public void run() {
if (mediaPlayer != null) {
int mCurrentPosition = mediaPlayer.getCurrentPosition();
progress.setProgress(mCurrentPosition);
long minutes = TimeUnit.MILLISECONDS.toMinutes(mCurrentPosition);
long seconds = TimeUnit.MILLISECONDS.toSeconds(mCurrentPosition)
- TimeUnit.MINUTES.toSeconds(minutes);
startTime.setText(String.format("%02d:%02d", minutes, seconds));
updateSeekBar();
}
}
};
private void updateSeekBar() {
handler.postDelayed(playRunnable, 100);
}
public void stopCompletely() {
handler.removeCallbacks(playRunnable);
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
}
public void stopp() {
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
}
public void switchRecordingStatus(int status) {
if (cancel != null) cancel.setText("cancel");
recordingStatus = status;
switch (status) {
case READY_STATUS:
timer.cancel();
play.setVisibility(View.VISIBLE);
prepareToPlay();
if (mainAction != null) mainAction.setText("Play");
break;
case PLAYER_STATUS:
if (mainAction != null) mainAction.setVisibility(View.GONE);
switchPlaybackStatus(PLAYING_STATUS);
loadAudio();
}
}
public void prepareToPlay() {
switchPlaybackStatus(PAUSED_STATUS);
progress.setProgress(0);
progress.setMax(mediaPlayer.getDuration());
startTime.setText(TimeFormatter.getDurationString(0));
if (endTime != null) {
if (mediaPlayer != null)
endTime.setText(TimeFormatter.getDurationStringFromMillis(mediaPlayer.getDuration()));
else
endTime.setText(TimeFormatter.getDurationString(duration));
}
}
public void switchPlaybackStatus(int status) {
if (play == null) return;
playbackStatus = status;
play.setVisibility(View.VISIBLE);
switch (status) {
case PLAYING_STATUS:
play.setImageResource(R.drawable.ic_media_pause);
break;
case PAUSED_STATUS:
play.setImageResource(R.drawable.ic_play_arrow_blue_36dp);
break;
case STOPPED_STATUS:
play.setImageResource(R.drawable.ic_play_arrow_blue_36dp);
progress.setProgress(0);
}
}
public void togglePlayback() {
switch (playbackStatus) {
case PLAYING_STATUS:
mediaPlayer.pause();
switchPlaybackStatus(PAUSED_STATUS);
break;
case STOPPED_STATUS:
case PAUSED_STATUS:
loadAudio();
switchPlaybackStatus(PLAYING_STATUS);
}
}
public void loadAudio() {
if (mediaPlayer != null) {
play.setImageResource(R.drawable.ic_media_pause);
handler.removeCallbacks(playRunnable);
mediaPlayer.start();
updateSeekBar();
} else {
mediaPlayer = new MediaPlayer();
try {
if (recordingStatus == PLAYER_STATUS) {
Uri uri = Uri.fromFile(new File(media.getUrl_file()));
String path = FileHelper.getPath(getActivity(), uri);
mediaPlayer.setDataSource(path);
} else
mediaPlayer.setDataSource(recordedAudio.getAbsolutePath());
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.prepareAsync();
progress.setMax(mediaPlayer.getDuration());
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
startPlay();
}
});
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
if(mp.getCurrentPosition()!=0) {
resetPlayback();
switchPlaybackStatus(STOPPED_STATUS);
stopp();
}
}
});
} catch (IOException exception) {
Log.e(TAG, "prepare() failed");
}
}
}
public void startPlay() {
startTime.setText(TimeFormatter.getDurationString(0));
if (endTime != null) {
endTime.setText(TimeFormatter.getDurationStringFromMillis(mediaPlayer.getDuration()));
}
progress.setMax(mediaPlayer.getDuration());
loadingContainer.setVisibility(View.GONE);
handler.post(playRunnable);
mediaPlayer.start();
}
public void resetPlayback() {
if (handler != null) handler.removeCallbacks(playRunnable);
switchPlaybackStatus(STOPPED_STATUS);
play = null;
duration = 0;
progress = null;
if (mediaPlayer != null) {
startTime.setText(TimeFormatter.getDurationStringFromMillis(mediaPlayer.getDuration()));
}
}
public FileModel getCurrentMedia() {
return media;
}
}
Related
Everytime I click on the nextBTn and PrevBtn in "music player activity",the next/previous Items in the recyclerview of "songs activity" or it's adapter need to play the perticuclar song in "Player activity".
I tried to make position++ and position-- but the items need to save in player activity I guess.
How can I play next and previous song when my player activity and adapter are two different activities.
How can I give the recyclerview items of the song currently playing and apply previoussongBTn,nextsongBTn?
code of player.java
public class player extends AppCompatActivity {
private ImageView imagePlayPause, forwardBtn, backwardBtn;
MediaPlayer mediaPlayer;
ImageView songImageIV;
String song_path,image_path,song_name,album_name,sng_path,pre_song;
TextView song_nameTV,albumNameTV;
private SeekBar playerSeekBar;
private TextView textCurrentTime, textTotalDuration;
private Handler handler = new Handler();
AdapterSongs songAdapter;
private int seekForwardTime = 10 * 1000;
private int seekBackwardTime = 10 * 1000; // default 10 second
private ChipNavigationBar chipNavigationBar;//for navigation
TextView scrollingText;//song name which scrolls horizontally
#SuppressLint("ClickableViewAccessibility")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.player_activity);
songImageIV = findViewById(R.id.song_image);
song_nameTV = findViewById(R.id.tv_songName);
albumNameTV = findViewById(R.id.topBarAlbumName);
textCurrentTime = findViewById(R.id.current_time);
textTotalDuration = findViewById(R.id.totalDuration);
playerSeekBar = findViewById(R.id.seekbar);
imagePlayPause = findViewById(R.id.playbtn);
forwardBtn = findViewById(R.id.forwardBtn);
backwardBtn = findViewById(R.id.backwardBtn);
mediaPlayer = playerInstance.getInstance();
playerSeekBar.setMax(100);
SharedPreferences sharedPreferences = getSharedPreferences("songDetails",MODE_PRIVATE);
song_path = sharedPreferences.getString("songPath","");
image_path = sharedPreferences.getString("album_img","");
song_name = sharedPreferences.getString("songName","");
album_name = sharedPreferences.getString("album_name","");
pre_song = sharedPreferences.getString("pre_song","");
// albumNameTV.append(album_name);
Picasso.get().load(image_path).into(songImageIV);
song_nameTV.setText(song_name);
albumNameTV.append(album_name);
scrollingText = (TextView)findViewById(R.id.tv_songName);
scrollingText.setSelected(true);
Log.i("tagconvertstr", "[song_path = " +song_path + "]");
Log.i("tagconvertstr", "[pre_path" + pre_song + "]");
if(!song_path.equals(pre_song))
{
prepareMediaPlayer();
textTotalDuration.setText(milisecToTimer(mediaPlayer.getDuration()));
if(!mediaPlayer.isPlaying()){
prepareMediaPlayer();
}
}
if(mediaPlayer.isPlaying())
{
imagePlayPause.setImageResource(R.drawable.pause_icon);
updater.run();
textTotalDuration.setText(milisecToTimer(mediaPlayer.getDuration()));
}
if(song_path.equalsIgnoreCase(pre_song))
{
updater.run();
textTotalDuration.setText(milisecToTimer(mediaPlayer.getDuration()));
}
navigation();//for navigation
imagePlayPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
playpause();
}
});
playerSeekBar.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
SeekBar seekBar = (SeekBar) view;
int playPosition = (mediaPlayer.getDuration()/100)*seekBar.getProgress();
mediaPlayer.seekTo(playPosition);
textCurrentTime.setText(milisecToTimer(mediaPlayer.getCurrentPosition()));
return false;
}
});
mediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
#Override
public void onBufferingUpdate(MediaPlayer mediaPlayer, int i) {
playerSeekBar.setSecondaryProgress(i);
}
});
if(mediaPlayer!=null) {
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
mediaPlayer.stop();
mediaPlayer.reset();
prepareMediaPlayer();
playerSeekBar.setProgress(0);
imagePlayPause.setImageResource(R.drawable.pause_icon);
textCurrentTime.setText(R.string.zero);
textTotalDuration.setText(R.string.zero);
}
});
}
forwardBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
forwardSong();
}
});
backwardBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
rewindSong();
}
});
}
public void forwardSong() {
if (mediaPlayer != null) {
int currentPosition = mediaPlayer.getCurrentPosition();
if (currentPosition + seekForwardTime <= mediaPlayer.getDuration()) {
mediaPlayer.seekTo(currentPosition + seekForwardTime);
} else {
mediaPlayer.seekTo(mediaPlayer.getDuration());
}
}
}
public void rewindSong() {
if (mediaPlayer != null) {
int currentPosition = mediaPlayer.getCurrentPosition();
if (currentPosition - seekBackwardTime >= 0) {
mediaPlayer.seekTo(currentPosition - seekBackwardTime);
} else {
mediaPlayer.seekTo(0);
}
}
}
private void prepareMediaPlayer(){
mediaPlayer.reset();
pre_song = song_path;
SharedPreferences sharedPreferences = getSharedPreferences("songDetails",Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("pre_song",pre_song);
editor.apply();
imagePlayPause.setImageResource(R.drawable.pause_icon);
try{
mediaPlayer.setDataSource(song_path);
// mediaPlayer.setDataSource("https://testing-ariya.s3.ap-south-1.amazonaws.com/Faded_320(PaglaSongs).mp3");
mediaPlayer.prepare();
textTotalDuration.setText(milisecToTimer(mediaPlayer.getDuration()));
mediaPlayer.start();
updater.run();
}catch (Exception e){
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
public Runnable updater = new Runnable() {
#Override
public void run() {
updateseekbar();
long currentDuration = mediaPlayer.getCurrentPosition();
textCurrentTime.setText(milisecToTimer(currentDuration));
}
};
public void updateseekbar(){
if(mediaPlayer.isPlaying()){
playerSeekBar.setProgress((int) (((float) mediaPlayer.getCurrentPosition()/mediaPlayer.getDuration()) *100));
handler.postDelayed(updater,1000);
}
}
private String milisecToTimer(long milliseconds){
String timerString= "";
String secondsString;
int hours = (int) (milliseconds/(1000*60*60));
int minutes = (int) (milliseconds % (1000*60*60))/ (1000*60);
int seconds = (int) ((milliseconds%(1000*60*60))%(1000*60)/1000);
if (hours > 0) {
timerString = hours + ":";
}
if (seconds<10){
secondsString = "0" +seconds;
}else{
secondsString = ""+seconds;
}
timerString = timerString+minutes+":"+secondsString;
return timerString;
}
public void navigation() {
chipNavigationBar = findViewById(R.id.chipNavigation);
chipNavigationBar.setItemSelected(R.id.player, true);
//getSupportFragmentManager().beginTransaction().replace(R.id.container, new HomeFragment()).commit();
chipNavigationBar.setOnItemSelectedListener(new ChipNavigationBar.OnItemSelectedListener() {
#Override
public void onItemSelected(int i) {
switch (i) {
case R.id.home:
startActivity(new Intent(getApplicationContext(), MainActivity.class));
overridePendingTransition(0, 0);
finish();
return ;
case R.id.player:
return ;
}
}
});
}
public void playpause()
{
if(mediaPlayer.isPlaying()){
handler.removeCallbacks(updater);
mediaPlayer.pause();
imagePlayPause.setImageResource(R.drawable.play_icon);
}else{
imagePlayPause.setImageResource(R.drawable.pause_icon);
mediaPlayer.start();
updateseekbar();
}
}
}
code of Adaptersongs.java
public class AdapterSongs extends RecyclerView.Adapter<AdapterSongs.ViewHolder2>{
public List<SongsModelClass> songsModelClassList;
Context context;
Dialog customDialog;
public int selectedPosition;//for next and prev song playing
public AdapterSongs(List<SongsModelClass> songsModelClassList, Context context) {
super();
this.songsModelClassList = songsModelClassList;
this.context = context;
}
#NonNull
#Override
public ViewHolder2 onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_song_row,parent,false);
ViewHolder2 viewHolder2 = new ViewHolder2(view);
return viewHolder2;
}
#Override
public void onBindViewHolder(#NonNull AdapterSongs.ViewHolder2 holder2, int position) {
SongsModelClass songData = songsModelClassList.get(position);
holder2.title.setText(songData.getTitle());
//Picasso.get().load(albumdata.getArtworkPath()).into(holder2.thumbnail);
holder2.title.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
SharedPreferences sharedPreferences1 = context.getSharedPreferences("login",Context.MODE_PRIVATE);
String userType = sharedPreferences1.getString("subscription","");
Log.i("tagconvertstr", "[userType" + userType + "]");
if(songData.getSongType().equalsIgnoreCase("YES")&&userType.equalsIgnoreCase("NO"))
{
customDialog = new Dialog(context);
customDialog.setContentView(R.layout.premium_alert_box);
customDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
customDialog.setCancelable(false);
customDialog.show();
TextView cancel = customDialog.findViewById(R.id.changeEmail);
TextView subscribe = customDialog.findViewById(R.id.confirmEmail);
cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
customDialog.dismiss();
}
});
subscribe.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(context,PremiumScreen.class);
context.startActivity(i);
customDialog.dismiss();
}
});
return;
}
Log.i("tagconvertstr", "[" + songData.getPath() + "]");
Intent intent = new Intent(context,player.class);
intent.putExtra("song_name",songData.getTitle());
intent.putExtra("song_path",songData.getPath());
intent.putExtra("album_img",songData.getArtworkPath());
intent.putExtra("album_name",songData.getSongAlbum());
SharedPreferences sharedPreferences = context.getSharedPreferences("songDetails",Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("songPath",songData.getPath());
editor.putString("songName",songData.getTitle());
editor.putString("album_img",songData.getArtworkPath());
editor.putString("album_name",songData.getSongAlbum());
editor.apply();
context.startActivity(intent);
}
});
}
#Override
public int getItemCount() {
return songsModelClassList.size();
}
class ViewHolder2 extends RecyclerView.ViewHolder{
// ImageView thumbnail;
TextView title;
TextView id;
public ViewHolder2(#NonNull View itemView) {
super(itemView);
title = itemView.findViewById(R.id.song_title);
}
}
}
FCM with agora Implementation
I have down agora part but have to implement firebase console.
I have configured cm. Previously I was using sinch to have called between two apps but now want to change to calling with agoro but with the same concept. In that, we were sending a token to the server and according to that sinch use to handle the call.
public class MainActivity extends AppCompatActivity {
private static final int PERMISSION_REQ_ID = 22;
private static final String[] REQUESTED_PERMISSIONS = {
Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
private static final String TAG="Agora ";
private RtcEngine mRtcEmgine;
private FrameLayout mLocalContainer;
private RelativeLayout mRemoteContainer;
private SurfaceView mLocalView;
private SurfaceView mremoteView;
private ImageView mCallBtn;
private ImageView mMuteBtn;
private ImageView mSwitchCameraBtn;
private boolean mCallEnd;
private boolean mMuted;
private final IRtcEngineEventHandler mRtcHandler= new IRtcEngineEventHandler() {
#Override
public void onJoinChannelSuccess(String channel,final int uid, int elapsed) {
super.onJoinChannelSuccess(channel, uid, elapsed);
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.e("agora","Join channel success, uid "+(uid &0xFFFFFFFFL));
}
});
}
#Override
public void onUserOffline(final int uid, int reason) {
super.onUserOffline(uid, reason);
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.e("agora","User Offline, uid "+(uid &0xFFFFFFFFL));
removeRemoteVideo();
}
});
}
#Override
public void onRemoteVideoStateChanged(final int uid, int state, int reason, int elapsed) {
super.onRemoteVideoStateChanged(uid, state, reason, elapsed);
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.e("agora","First reomte video decoded, uid "+(uid &0xFFFFFFFFL));
setupRemoteVideo(uid);
}
});
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//initUI();
mLocalContainer=findViewById(R.id.local_video_view_container);
mRemoteContainer=findViewById(R.id.remote_video_view_container);
mCallBtn=findViewById(R.id.btn_call);
mCallBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mCallEnd){
startCall();
mCallEnd=false;
mCallBtn.setImageResource(R.drawable.btn_endcall);
}
else {
endCall();
mCallEnd=true;
mCallBtn.setImageResource(R.drawable.btn_startcall);
}
showButton(!mCallEnd);
}
});
mMuteBtn=findViewById(R.id.btn_mute);
mMuteBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mMuted = !mMuted;
mRtcEmgine.muteLocalAudioStream(mMuted);
int res = mMuted ? R.drawable.btn_mute : R.drawable.btn_unmute;
mMuteBtn.setImageResource(res);
}
});
mSwitchCameraBtn=findViewById(R.id.btn_switch_camera);
mSwitchCameraBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mRtcEmgine.switchCamera();
}
});
if (checkSelfpermission(REQUESTED_PERMISSIONS[0]) &&
checkSelfpermission(REQUESTED_PERMISSIONS[1]) &&
checkSelfpermission(REQUESTED_PERMISSIONS[2]))
{
Log.e(TAG," true ");
initEngineAndJoinChannel();
}
else {
Log.e(TAG," false ");
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode == PERMISSION_REQ_ID) {
if (grantResults[0] != PackageManager.PERMISSION_GRANTED ||
grantResults[1] != PackageManager.PERMISSION_GRANTED ||
grantResults[2] != PackageManager.PERMISSION_GRANTED) {
Log.e(TAG,"Need permissions " + Manifest.permission.RECORD_AUDIO +
"/" + Manifest.permission.CAMERA + "/" + Manifest.permission.WRITE_EXTERNAL_STORAGE);
finish();
return;
}
initEngineAndJoinChannel();
}
}
#Override
protected void onDestroy(){
super.onDestroy();
if (!mCallEnd){
leaveChannel();
}
RtcEngine.destroy();
}
private void initUI() {
Log.e(TAG," UI ");
mLocalContainer=findViewById(R.id.local_video_view_container);
mRemoteContainer=findViewById(R.id.remote_video_view_container);
mCallBtn=findViewById(R.id.btn_call);
mMuteBtn=findViewById(R.id.btn_mute);
mSwitchCameraBtn=findViewById(R.id.btn_switch_camera);
}
private void initEngineAndJoinChannel() {
initializeEngine();
setupVideoConfig();
setupLocalVideo();
joinChannel();
}
private void setupVideoConfig() {
Log.e(TAG,"running 2");
mRtcEmgine.enableVideo();
mRtcEmgine.setVideoEncoderConfiguration(new VideoEncoderConfiguration(
VideoEncoderConfiguration.VD_640x360,
VideoEncoderConfiguration.FRAME_RATE.FRAME_RATE_FPS_15,
VideoEncoderConfiguration.STANDARD_BITRATE,
VideoEncoderConfiguration.ORIENTATION_MODE.ORIENTATION_MODE_FIXED_PORTRAIT
));
}
private void setupLocalVideo() {
Log.e(TAG,"running 3");
mRtcEmgine.enableVideo();
mLocalView=RtcEngine.CreateRendererView(getBaseContext());
mLocalView.setZOrderMediaOverlay(true);
mLocalContainer.addView(mLocalView);
VideoCanvas localVideoCanvas = new VideoCanvas(mLocalView, VideoCanvas.RENDER_MODE_HIDDEN,0);
mRtcEmgine.setupLocalVideo(localVideoCanvas);
}
private void setupRemoteVideo(int uid) {
int count = mRemoteContainer.getChildCount();
View view = null;
for(int i = 0; i < count; i++) {
View v= mRemoteContainer.getChildAt(i);
if (v.getTag() instanceof Integer && ((int)v.getTag()) == uid) {
view = v;
}
}
if (view != null) {
return;
}
mremoteView = RtcEngine.CreateRendererView(getBaseContext());
mRemoteContainer.addView(mremoteView);
mRtcEmgine.setupRemoteVideo(new VideoCanvas(mremoteView, VideoCanvas.RENDER_MODE_HIDDEN, uid));
mremoteView.setTag(uid);
}
private void initializeEngine() {
Log.e(TAG,"running 1");
try {
mRtcEmgine=RtcEngine.create(getBaseContext(),getString(R.string.agora_app_id),mRtcHandler);
}
catch (Exception e) {
Log.e(TAG,Log.getStackTraceString(e));
throw new RuntimeException("NEED TO check rtc sdk fatal error \n"+Log.getStackTraceString(e));
}
}
private void removeRemoteVideo() {
if (mremoteView != null) {
mRemoteContainer.removeView(mremoteView);
}
mremoteView = null;
}
private void joinChannel() {
Log.e(TAG,"running 4");
String token = getString(R.string.agora_access_token);
if (TextUtils.isEmpty(token)) {
token = null;
}
mRtcEmgine.joinChannel(token,"demochannel", "", 0);
}
private void leaveChannel() {
mRtcEmgine.leaveChannel();
}
/* public void onLocalAudioMuteClicked(View view) {
mMuted = !mMuted;
mRtcEmgine.muteLocalAudioStream(mMuted);
int res = mMuted ? R.drawable.btn_mute : R.drawable.btn_unmute;
mMuteBtn.setImageResource(res);
}*/
/* public void onSwitchClicked(View view) {
mRtcEmgine.switchCamera();
}*/
/* public void onCallClicked(View view) {
if (mCallEnd){
startCall();
mCallEnd = false;
mCallBtn.setImageResource(R.drawable.btn_endcall);
}
else {
endCall();
mCallEnd = true;
mCallBtn.setImageResource(R.drawable.btn_startcall);
}
showButton(!mCallEnd);
}*/
private void startCall() {
setupLocalVideo();
joinChannel();
}
private void endCall() {
removeLocalVideo();
removeRemoteVideo();
leaveChannel();
}
private void removeLocalVideo() {
if (mLocalView != null) {
mLocalContainer.removeView(mLocalView);
}
mLocalView = null;
}
private void showButton(boolean show) {
int visibilty = show ? View.VISIBLE : View.GONE;
mMuteBtn.setVisibility(visibilty);
mSwitchCameraBtn.setVisibility(visibilty);
}
private Boolean checkSelfpermission(String permission) {
if (ContextCompat.checkSelfPermission(this,permission) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, REQUESTED_PERMISSIONS, MainActivity.PERMISSION_REQ_ID);
return false;
}
return true;
}
}
When the audio player app is resumed while playing audio, the SeekBar resets to 0. During audio playback, the SeekBar updates progress. However, when the screen is resumed, the SeekBar starts from the beginning without indicating the player's current position. When you press the pause button and then press the play button, it plays at the current position again. In updateProgress() method, there is long currentPosition = mLastPlaybackState.getPosition(); I think this code doesn't indicate the current position when resumed.
I implemented SeekBar update progress based on the UAMP FullScreenActivity
This is my NowPlayingAcitivy.java:
private PlaybackStateCompat mLastPlaybackState;
private final Handler mHandler = new Handler();
private final Runnable mUpdateProgressTask = new Runnable() {
#Override
public void run() {
updateProgress();
}
};
private final ScheduledExecutorService mExecutorService =
Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> mScheduledFuture;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNowPlayingBinding = DataBindingUtil.setContentView(
this, R.layout.activity_now_playing);
createMediaBrowserCompat();
mNowPlayingBinding.playingInfo.seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
mNowPlayingBinding.playingInfo.tvStart.setText(DateUtils.formatElapsedTime(
progress/1000));
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// Cancel the future returned by scheduleAtFixedRate() to stop the SeekBar from progressing
stopSeekbarUpdate();
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
MediaControllerCompat.getMediaController(NowPlayingActivity.this)
.getTransportControls().seekTo(seekBar.getProgress());
// Create and execute a periodic action to update the SeekBar progress
scheduleSeekbarUpdate();
}
});
}
private void createMediaBrowserCompat() {
mMediaBrowser = new MediaBrowserCompat(this,
new ComponentName(this, PodcastService.class),
mConnectionCallbacks,
null);
}
#Override
protected void onStart() {
super.onStart();
mMediaBrowser.connect();
}
#Override
protected void onResume() {
super.onResume();
setVolumeControlStream(AudioManager.STREAM_MUSIC);
}
#Override
protected void onStop() {
super.onStop();
if (MediaControllerCompat.getMediaController(this) != null) {
MediaControllerCompat.getMediaController(this).unregisterCallback(controllerCallback);
}
mMediaBrowser.disconnect();
}
#Override
protected void onDestroy() {
super.onDestroy();
stopSeekbarUpdate();
mExecutorService.shutdown();
}
private final MediaBrowserCompat.ConnectionCallback mConnectionCallbacks =
new MediaBrowserCompat.ConnectionCallback() {
#Override
public void onConnected() {
MediaSessionCompat.Token token = mMediaBrowser.getSessionToken();
MediaControllerCompat mediaController = null;
try {
mediaController = new MediaControllerCompat(NowPlayingActivity.this, token);
} catch (RemoteException e) {
Timber.e("Error creating media controller");
}
MediaControllerCompat.setMediaController(NowPlayingActivity.this,
mediaController);
buildTransportControls();
}
#Override
public void onConnectionSuspended() {
super.onConnectionSuspended();
}
#Override
public void onConnectionFailed() {
super.onConnectionFailed();
}
};
void buildTransportControls() {
mNowPlayingBinding.playingInfo.ibPlayPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
PlaybackStateCompat pbState =
MediaControllerCompat.getMediaController(NowPlayingActivity.this).getPlaybackState();
if (pbState != null) {
MediaControllerCompat.TransportControls controls =
MediaControllerCompat.getMediaController(NowPlayingActivity.this).getTransportControls();
switch (pbState.getState()) {
case PlaybackStateCompat.STATE_PLAYING: // fall through
case PlaybackStateCompat.STATE_BUFFERING:
controls.pause();
stopSeekbarUpdate();
break;
case PlaybackStateCompat.STATE_PAUSED:
case PlaybackStateCompat.STATE_STOPPED:
controls.play();
scheduleSeekbarUpdate();
break;
default:
Timber.d("onClick with state " + pbState);
}
}
}
});
MediaControllerCompat mediaController =
MediaControllerCompat.getMediaController(NowPlayingActivity.this);
MediaMetadataCompat metadata = mediaController.getMetadata();
PlaybackStateCompat pbState = mediaController.getPlaybackState();
updatePlaybackState(pbState);
if (metadata != null) {
// Get the episode duration from the metadata and sets the end time to the textView
updateDuration(metadata);
}
// Set the current progress to the current position
updateProgress();
if (pbState != null && (pbState.getState() == PlaybackStateCompat.STATE_PLAYING ||
pbState.getState() == PlaybackStateCompat.STATE_BUFFERING)) {
scheduleSeekbarUpdate();
}
mediaController.registerCallback(controllerCallback);
}
MediaControllerCompat.Callback controllerCallback = new MediaControllerCompat.Callback() {
#Override
public void onMetadataChanged(MediaMetadataCompat metadata) {
super.onMetadataChanged(metadata);
if (metadata != null) {
updateDuration(metadata);
}
}
#Override
public void onPlaybackStateChanged(PlaybackStateCompat state) {
super.onPlaybackStateChanged(state);
// Update the playback state
updatePlaybackState(state);
}
};
/**
* Creates and executes a periodic action that becomes enabled first after the given initial delay,
* and subsequently with the given period;that is executions will commence after initialDelay
* then initialDelay + period, then initialDelay + 2 * period, and so on.
*/
private void scheduleSeekbarUpdate() {
stopSeekbarUpdate();
if (!mExecutorService.isShutdown()) {
mScheduleFuture = mExecutorService.scheduleAtFixedRate(
new Runnable() {
#Override
public void run() {
mHandler.post(mUpdateProgressTask);
}
}, 100,
1000, TimeUnit.MILLISECONDS);
}
}
/**
* Cancels the future returned by scheduleAtFixedRate() to stop the SeekBar from progressing.
*/
private void stopSeekbarUpdate() {
if (mScheduledFuture != null) {
mScheduledFuture.cancel(false);
}
}
/**
* Gets the episode duration from the metadata and sets the end time to be displayed in the TextView.
*/
private void updateDuration(MediaMetadataCompat metadata) {
if (metadata == null) {
return;
}
int duration = (int) metadata.getLong(MediaMetadataCompat.METADATA_KEY_DURATION)
* 1000;
mNowPlayingBinding.playingInfo.seekBar.setMax(duration);
mNowPlayingBinding.playingInfo.tvEnd.setText(
DateUtils.formatElapsedTime(duration / 1000));
}
/**
* Calculates the current position (distance = timeDelta * velocity) and sets the current progress
* to the current position.
*/
private void updateProgress() {
if (mLastPlaybackState == null) {
return;
}
long currentPosition = mLastPlaybackState.getPosition();
if (mLastPlaybackState.getState() == PlaybackStateCompat.STATE_PLAYING) {
// Calculate the elapsed time between the last position update and now and unless
// paused, we can assume (delta * speed) + current position is approximately the
// latest position. This ensure that we do not repeatedly call the getPlaybackState()
// on MediaControllerCompat.
long timeDelta = SystemClock.elapsedRealtime() -
mLastPlaybackState.getLastPositionUpdateTime();
currentPosition += (int) timeDelta * mLastPlaybackState.getPlaybackSpeed();
}
mNowPlayingBinding.playingInfo.seekBar.setProgress((int) currentPosition);
}
private void updatePlaybackState(PlaybackStateCompat state) {
if (state == null) {
return;
}
mLastPlaybackState = state;
switch (state.getState()) {
case PlaybackStateCompat.STATE_PLAYING:
hideLoading();
mNowPlayingBinding.playingInfo.ibPlayPause.setImageResource(R.drawable.exo_controls_pause);
scheduleSeekbarUpdate();
break;
case PlaybackStateCompat.STATE_PAUSED:
hideLoading();
mNowPlayingBinding.playingInfo.ibPlayPause.setImageResource(R.drawable.exo_controls_play);
stopSeekbarUpdate();
break;
case PlaybackStateCompat.STATE_NONE:
case PlaybackStateCompat.STATE_STOPPED:
hideLoading();
mNowPlayingBinding.playingInfo.ibPlayPause.setImageResource(R.drawable.exo_controls_play);
stopSeekbarUpdate();
break;
case PlaybackStateCompat.STATE_BUFFERING:
showLoading();
mNowPlayingBinding.playingInfo.ibPlayPause.setImageResource(R.drawable.exo_controls_play);
stopSeekbarUpdate();
break;
default:
Timber.d("Unhandled state " + state.getState());
}
}
This is my PodcastService.java:
public class PodcastService extends MediaBrowserServiceCompat implements Player.EventListener {
#Override
public void onCreate() {
super.onCreate();
initializeMediaSession();
}
private void initializeMediaSession() {
mMediaSession = new MediaSessionCompat(PodcastService.this, TAG);
mMediaSession.setFlags(
MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
mStateBuilder = new PlaybackStateCompat.Builder()
.setActions(
PlaybackStateCompat.ACTION_PLAY |
PlaybackStateCompat.ACTION_PAUSE |
PlaybackStateCompat.ACTION_REWIND |
PlaybackStateCompat.ACTION_FAST_FORWARD |
PlaybackStateCompat.ACTION_PLAY_PAUSE);
mMediaSession.setPlaybackState(mStateBuilder.build());
mMediaSession.setCallback(new MySessionCallback());
setSessionToken(mMediaSession.getSessionToken());
mMediaSession.setSessionActivity(PendingIntent.getActivity(this,
11,
new Intent(this, NowPlayingActivity.class),
PendingIntent.FLAG_UPDATE_CURRENT));
}
private void initializePlayer() {
if (mExoPlayer == null) {
DefaultRenderersFactory defaultRenderersFactory = new DefaultRenderersFactory(this);
TrackSelector trackSelector = new DefaultTrackSelector();
LoadControl loadControl = new DefaultLoadControl();
mExoPlayer = ExoPlayerFactory.newSimpleInstance(this, defaultRenderersFactory,
trackSelector, loadControl);
mExoPlayer.addListener(this);
// Prepare the MediaSource
Uri mediaUri = Uri.parse(mUrl);
MediaSource mediaSource = buildMediaSource(mediaUri);
mExoPlayer.prepare(mediaSource);
mExoPlayer.setPlayWhenReady(true);
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent == null || intent.getAction() == null) {
Timber.e("intent in onStartCommand is null");
return START_STICKY;
}
// Check if the old player should be released
if (intent.getAction() != null && intent.getAction().equals(ACTION_RELEASE_OLD_PLAYER)) {
if (mExoPlayer != null) {
mExoPlayer.stop();
releasePlayer();
}
}
Bundle b = intent.getBundleExtra(EXTRA_ITEM);
if (b != null) {
mItem = b.getParcelable(EXTRA_ITEM);
mUrl = mItem.getEnclosures().get(0).getUrl();
}
initializePlayer();
// Convert hh:mm:ss string to seconds to put it into the metadata
long duration = PodUtils.getDurationInMilliSeconds(mItem);
MediaMetadataCompat metadata = new MediaMetadataCompat.Builder()
.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration).build();
mMediaSession.setMetadata(metadata);
return START_STICKY;
}
private void releasePlayer() {
mExoPlayer.release();
mExoPlayer = null;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
if (mExoPlayer != null) {
mExoPlayer.stop(true);
}
stopSelf();
}
#Override
public void onDestroy() {
mMediaSession.release();
releasePlayer();
super.onDestroy();
}
private MediaSource buildMediaSource(Uri mediaUri) {
String userAgent = Util.getUserAgent(this, getString(R.string.app_name));
DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(
this, userAgent);
CacheDataSourceFactory cacheDataSourceFactory =
new CacheDataSourceFactory(
DownloadUtil.getCache(this),
dataSourceFactory,
CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR);
return new ExtractorMediaSource.Factory(cacheDataSourceFactory).createMediaSource(mediaUri);
}
#Nullable
#Override
public BrowserRoot onGetRoot(#NonNull String clientPackageName, int clientUid,
#Nullable Bundle rootHints) {
return new BrowserRoot("pod_root_id", null);
}
#Override
public void onLoadChildren(#NonNull String parentMediaId,
#NonNull Result<List<MediaBrowserCompat.MediaItem>> result) {
// Browsing not allowed
if (TextUtils.equals("empty_root_id", parentMediaId)) {
result.sendResult(null);
return;
}
List<MediaBrowserCompat.MediaItem> mediaItems = new ArrayList<>();
// Check if this is the root menu:
if ("pod_root_id".equals(parentMediaId)) {
// Build the MediaItem objects for the top level,
// and put them in the mediaItems list...
} else {
// Examine the passed parentMediaId to see which submenu we're at,
// and put the children of that menu in the mediaItems list...
}
result.sendResult(mediaItems);
}
private class MySessionCallback extends MediaSessionCompat.Callback {
#Override
public void onPlay() {
startService(new Intent(getApplicationContext(), PodcastService.class));
mMediaSession.setActive(true);
// Start the player
if (mExoPlayer != null) {
mExoPlayer.setPlayWhenReady(true);
}
}
#Override
public void onPause() {
mExoPlayer.setPlayWhenReady(false);
stopForeground(false);
}
#Override
public void onRewind() {
mExoPlayer.seekTo(Math.max(mExoPlayer.getCurrentPosition() - 10000, 0));
}
#Override
public void onFastForward() {
long duration = mExoPlayer.getDuration();
mExoPlayer.seekTo(Math.min(mExoPlayer.getCurrentPosition() + 30000, duration));
}
#Override
public void onStop() {
stopSelf();
mMediaSession.setActive(false);
mExoPlayer.stop();
stopForeground(true);
}
#Override
public void onSeekTo(long pos) {
super.onSeekTo(pos);
if (mExoPlayer != null) {
mExoPlayer.seekTo((int) pos);
}
}
}
// Player Event Listeners
#Override
public void onTimelineChanged(Timeline timeline, #Nullable Object manifest, int reason) {
}
#Override
public void onPlayerError(ExoPlaybackException error) {
}
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
if (playbackState == Player.STATE_IDLE) {
mStateBuilder.setState(PlaybackStateCompat.STATE_PAUSED,
mExoPlayer.getCurrentPosition(), 1f);
} else if (playbackState == Player.STATE_BUFFERING) {
mStateBuilder.setState(PlaybackStateCompat.STATE_BUFFERING,
mExoPlayer.getCurrentPosition(), 1f);
} else if (playbackState == Player.STATE_READY && playWhenReady) {
mStateBuilder.setState(PlaybackStateCompat.STATE_PLAYING,
mExoPlayer.getCurrentPosition(), 1f);
Timber.d("onPlayerStateChanged: we are playing");
} else if (playbackState == Player.STATE_READY) {
mStateBuilder.setState(PlaybackStateCompat.STATE_PAUSED,
mExoPlayer.getCurrentPosition(), 1f);
Timber.d("onPlayerStateChanged: we are paused");
} else if (playbackState == Player.STATE_ENDED) {
mStateBuilder.setState(PlaybackStateCompat.STATE_PAUSED,
mExoPlayer.getCurrentPosition(), 1f);
} else {
mStateBuilder.setState(PlaybackStateCompat.STATE_NONE,
mExoPlayer.getCurrentPosition(), 1f);
}
mMediaSession.setPlaybackState(mStateBuilder.build());
}
}
Edit: The full source code is available here.
To set the state progress based on value should use setProgress(value) method.
when paused the music save value from seekBar as an Integer, then when resume it get that value and put it as a parameter in setProgress() method.
when you pause music to save the value:
#Override
protected void onPause() {
super.onPause();
mSeekBarRate.setOnSeekBarChangeListener(
new SeekBar.OnSeekBarChangeListener() {
int progress = 0;
#Override
public void onProgressChanged(SeekBar mSeekBarRate, int progressValue, boolean fromUser) {
progress = progressValue;
}
#Override
public void onStartTrackingTouch(SeekBar mSeekBarRate) {
}
#Override
public void onStopTrackingTouch(SeekBar mSeekBarRate) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
SharedPreferences.Editor editor = prefs.edit();
editor.putInt("value", progress);
}
});
}
when you resume music retrieve that value:
#Override
protected void onStart() {
super.onStart();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
int value = prefs.getInt("value", 0);
mSeekBarRate.setProgress(value);
}
Hope it Helps you.
How do I save the Exoplayer video current position and text on screen rotation and the video should not paused on Screen rotation? I tried using outState.putInt("position",(int) player.getCurrentPosition); on onSaveInstanceState() but it didn't work. The present code below shows the recipeName == null on onSaveInstanceState while debugging.
public class RecipeStepDetailFragment extends Fragment {
private SimpleExoPlayerView simpleExoPlayerView;
private SimpleExoPlayer player;
private BandwidthMeter bandwidthMeter;
private ArrayList<Step> steps = new ArrayList<>();
private int selectedIndex;
private Handler mainHandler;
private String recipeName;
private int contentPosition;
public RecipeStepDetailFragment() {
}
private ListItemClickListener itemClickListener;
public interface ListItemClickListener {
void onListItemClick(List<Step> allSteps,int Index,String recipeName);
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
TextView textView;
mainHandler = new Handler();
bandwidthMeter = new DefaultBandwidthMeter();
itemClickListener =(RecipeDetailActivity)getActivity();
ArrayList<Recipe> recipe = new ArrayList<>();
if(savedInstanceState != null) {
steps = savedInstanceState.getParcelableArrayList(SELECTED_STEPS);
selectedIndex = savedInstanceState.getInt(SELECTED_INDEX);
recipeName = savedInstanceState.getString("Title");
}
else {
assert getArguments() != null;
steps =getArguments().getParcelableArrayList(SELECTED_STEPS);
if (steps!=null) {
steps =getArguments().getParcelableArrayList(SELECTED_STEPS);
selectedIndex=getArguments().getInt(SELECTED_INDEX);
recipeName=getArguments().getString("Title");
}
else {
recipe =getArguments().getParcelableArrayList(SELECTED_RECIPES);
//casting List to ArrayList
assert recipe != null;
steps=(ArrayList<Step>) recipe.get(0).getSteps();
selectedIndex=0;
}
}
View rootView = inflater.inflate(R.layout.recipe_step_detail_fragment_body_part, container, false);
textView = rootView.findViewById(R.id.recipe_step_detail_text);
textView.setText(steps.get(selectedIndex).getDescription());
textView.setVisibility(View.VISIBLE);
simpleExoPlayerView = rootView.findViewById(R.id.playerView);
simpleExoPlayerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FIT);
String videoURL = steps.get(selectedIndex).getVideoURL();
if (rootView.findViewWithTag("sw600dp-port-recipe_step_detail")!=null) {
recipeName=((RecipeDetailActivity) Objects.requireNonNull(getActivity())).recipeName;
Objects.requireNonNull(((RecipeDetailActivity) getActivity()).getSupportActionBar()).setTitle(recipeName);
}
String imageUrl=steps.get(selectedIndex).getThumbnailURL();
if (!imageUrl.equals("")) {
Uri builtUri = Uri.parse(imageUrl).buildUpon().build();
ImageView thumbImage = rootView.findViewById(R.id.thumbImage);
Picasso.with(getContext()).load(builtUri).into(thumbImage);
}
if (!videoURL.isEmpty()) {
initializePlayer(Uri.parse(steps.get(selectedIndex).getVideoURL()));
if (rootView.findViewWithTag("sw600dp-land-recipe_step_detail")!=null) {
getActivity().findViewById(R.id.fragment_container2).setLayoutParams(new LinearLayout.LayoutParams(-1,-2));
simpleExoPlayerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH);
}
else if (isInLandscapeMode(Objects.requireNonNull(getContext()))){
textView.setVisibility(View.GONE);
}
}
else {
player=null;
simpleExoPlayerView.setForeground(ContextCompat.getDrawable(Objects.requireNonNull(getContext()), R.drawable.ic_visibility_off_white_36dp));
simpleExoPlayerView.setLayoutParams(new LinearLayout.LayoutParams(300, 300));
}
Button mPrevStep = rootView.findViewById(R.id.previousStep);
Button mNextstep = rootView.findViewById(R.id.nextStep);
mPrevStep.setOnClickListener(view -> {
if (steps.get(selectedIndex).getId() > 0) {
if (player!=null){
player.stop();
}
itemClickListener.onListItemClick(steps,steps.get(selectedIndex).getId() - 1,recipeName);
}
else {
Toast.makeText(getActivity(),"You already are in the First step of the recipe", Toast.LENGTH_SHORT).show();
}
});
mNextstep.setOnClickListener(view -> {
int lastIndex = steps.size()-1;
if (steps.get(selectedIndex).getId() < steps.get(lastIndex).getId()) {
if (player!=null){
player.stop();
}
itemClickListener.onListItemClick(steps,steps.get(selectedIndex).getId() + 1,recipeName);
}
else {
Toast.makeText(getContext(),"You already are in the Last step of the recipe", Toast.LENGTH_SHORT).show();
}
});
return rootView;
}
private void initializePlayer(Uri mediaUri) {
if (player == null) {
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveVideoTrackSelection.Factory(bandwidthMeter);
DefaultTrackSelector trackSelector = new DefaultTrackSelector(mainHandler, videoTrackSelectionFactory);
LoadControl loadControl = new DefaultLoadControl();
player = ExoPlayerFactory.newSimpleInstance(Objects.requireNonNull(getContext()), trackSelector, loadControl);
simpleExoPlayerView.setPlayer(player);
String userAgent = Util.getUserAgent(getContext(), "Baking App");
MediaSource mediaSource = new ExtractorMediaSource(mediaUri, new DefaultDataSourceFactory(getContext(), userAgent), new DefaultExtractorsFactory(), null, null);
player.prepare(mediaSource);
player.setPlayWhenReady(true);
}else{
player.getCurrentPosition();
}
}
#Override
public void onSaveInstanceState(#NonNull Bundle currentState) {
super.onSaveInstanceState(currentState);
currentState.putParcelableArrayList(SELECTED_STEPS,steps);
currentState.putInt(SELECTED_INDEX,selectedIndex);
currentState.putString("Title",recipeName);
//what code should I insert to save both the text and exoplayer on Screen rotation
// (int)
}
private boolean isInLandscapeMode(Context context) {
return (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
}
#Override
public void onDetach() {
super.onDetach();
if (player!=null) {
player.stop();
player.release();
}
}
#Override
public void onDestroyView() {
super.onDestroyView();
if (player!=null) {
player.stop();
player.release();
player=null;
}
}
#Override
public void onStop() {
super.onStop();
if (player!=null) {
player.stop();
player.release();
}
}
#Override
public void onPause() {
super.onPause();
if (player!=null) {
player.stop();
player.release();
}
}
}
I'm tying to play videos from a Firebase Listadapter. When the user clicks on the list they a video plays, and upon finishing the activity finishes, and they return to the original list.
When the click on the second video it starts the ExoPlayer activity, but won't play the video. If they press back and select the original video it will play fine.
public String mTastingWineID;
public String tastingWineId;
public String mWineVideoID;
public String tastingWineVideoId;
private DataSource.Factory mediaDataSourceFactory;
private boolean isPlaying = false;
public int mVideoResource;
public Uri videoUri;
private static final String TAG = "WineMediaActivity";
private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter();
private SimpleExoPlayer player;
private SimpleExoPlayerView mVideoView;
private ComponentListener componentListener;
private long playbackPostiion;
private int currentWindow;
private boolean playWhenReady = true;
private BandwidthMeter bandwidthMeter;
public Firebase wineMediaUrl;
public ValueEventListener wineMediaUrlListener;
private MediaControllerCompat mediaControllerCompat;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.analytics_media_wine_information);
Bundle bundle = getIntent().getExtras();
mTastingWineID = bundle.getString(Constants.WINE_ID);
tastingWineId = mTastingWineID.toString();
mWineVideoID = bundle.getString(Constants.WINE_VIDEO_ID);
tastingWineVideoId = mWineVideoID.toString();
if (player != null){
player.release();
}
getCurrentVideo();
}
public void getCurrentVideo(){
wineMediaUrl = new Firebase(Constants.FIREBASE_URL).child(FIREBASE_LOCATION_WINE_DETAILS).child(tastingWineId).child(WINE_MEDIA).child(tastingWineVideoId).child("wineVideoUrl");
wineMediaUrlListener = wineMediaUrl.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
componentListener = new ComponentListener();
mVideoView = findViewById(R.id.videoView1);
mVideoView.requestFocus();
Object tempVideoFiles = dataSnapshot.getValue();
String str = tempVideoFiles.toString();
videoUri = Uri.parse(str);
if (videoUri != null) {
initializePlayer();
} else {
Toast.makeText(WineMediaActivity.this, "No Video Found", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
mediaDataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "mediaPlayerSample"), (TransferListener<? super DataSource>) bandwidthMeter);
}
private class ComponentListener implements ExoPlayer.EventListener, VideoRendererEventListener, AudioRendererEventListener {
#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) {
String stateString;
switch (playbackState) {
case ExoPlayer.STATE_IDLE:
stateString = "ExoPlayer.STATE_IDLE";
break;
case ExoPlayer.STATE_BUFFERING:
stateString = "ExoPlayer.STATE_IDLE";
break;
case ExoPlayer.STATE_READY:
stateString = "ExoPlayer.STATE_IDLE";
break;
case ExoPlayer.STATE_ENDED:
stateString = "ExoPlayer.STATE_IDLE";
releasePlayer();
finish();
break;
default:
stateString = "UNKNOWN_STATE";
break;
}
Log.d(TAG, "changed state to: " + stateString + " play when ready: " + playWhenReady);
}
#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() {
}
#Override
public void onAudioEnabled(DecoderCounters counters) {
}
#Override
public void onAudioSessionId(int audioSessionId) {
}
#Override
public void onAudioDecoderInitialized(String decoderName, long initializedTimestampMs, long initializationDurationMs) {
}
#Override
public void onAudioInputFormatChanged(Format format) {
}
#Override
public void onAudioSinkUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) {
}
#Override
public void onAudioDisabled(DecoderCounters counters) {
}
#Override
public void onVideoEnabled(DecoderCounters counters) {
}
#Override
public void onVideoDecoderInitialized(String decoderName, long initializedTimestampMs, long initializationDurationMs) {
}
#Override
public void onVideoInputFormatChanged(Format format) {
}
#Override
public void onDroppedFrames(int count, long elapsedMs) {
}
#Override
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
}
#Override
public void onRenderedFirstFrame(Surface surface) {
}
#Override
public void onVideoDisabled(DecoderCounters counters) {
}
}
private void initializePlayer() {
if (player == null) {
TrackSelection.Factory adaptiveTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
player = ExoPlayerFactory.newSimpleInstance(new DefaultRenderersFactory(this), new DefaultTrackSelector(adaptiveTrackSelectionFactory), new DefaultLoadControl());
player.addListener(componentListener);
player.setVideoDebugListener(componentListener);
player.setAudioDebugListener(componentListener);
mVideoView.setPlayer(player);
player.setPlayWhenReady(playWhenReady);
player.seekTo(currentWindow, playbackPostiion);
}
MediaSource mediaSource = new ExtractorMediaSource(videoUri, mediaDataSourceFactory, extractorsFactory, null, null);
player.prepare(mediaSource, true, false);
}
#SuppressLint("InlinedApi")
private void hideSystemUi() {
mVideoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
}
private void releasePlayer() {
if (player != null) {
playbackPostiion = player.getCurrentPosition();
currentWindow = player.getCurrentWindowIndex();
playWhenReady = player.getPlayWhenReady();
player.removeListener(componentListener);
mVideoView.setPlayer(null);
player.setVideoListener(null);
player.setVideoDebugListener(null);
player.setAudioDebugListener(null);
player.release();
player = null;
if (wineMediaUrlListener != null) {
wineMediaUrl.removeEventListener(wineMediaUrlListener);
wineMediaUrlListener = null;
}
}
}
#Override
protected void onPause() {
super.onPause();
releasePlayer();
}
#Override
public void onStop() {
super.onStop();
releasePlayer();
}
#Override
public void onDestroy() {
super.onDestroy();
releasePlayer();
}
Apologies for the code, I'm newish to coding and hoping someone can help me.
Turns out the code is fine - the error was in the upload of videos, they were overwriting the previous video meaning the previous one wouldn't play.