Playing/Controlling songs from Android AppWidget - android

I created service class to play/pause songs from Activity. But am unable to run that service from AppWidget & also unable to handle click event like how I handled in Activity. Valuable comments/answers are highly appreciated. Thank you.
Service Class
public class MusicService extends Service implements MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener,
MediaPlayer.OnCompletionListener {
//media player
private MediaPlayer player;
//song list
private ArrayList<Song> songs;
//current position
private int songPosn;
//binder
private final IBinder musicBind = new MusicBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
Log.e("***", "MusicService - onBind");
return musicBind;
}
#Override
public boolean onUnbind(Intent intent) {
Log.e("***", "MusicService - onUnbind");
player.stop();
player.release();
return false;
}
#Override
public void onDestroy() {
Log.e("***", "MusicService - onDestroy");
super.onDestroy();
}
#Override
public void onCreate() {
super.onCreate();
Log.e("***", "MusicService - onCreate");
//initialize position
songPosn = 0;
//create player
player = new MediaPlayer();
//initialize
initMusicPlayer();
}
public void initMusicPlayer() {
//set player properties
player.setWakeMode(getApplicationContext(),
PowerManager.PARTIAL_WAKE_LOCK);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
//set listeners
player.setOnPreparedListener(this);
player.setOnCompletionListener(this);
player.setOnErrorListener(this);
}
#Override
public void onCompletion(MediaPlayer mp) {
}
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
return false;
}
#Override
public void onPrepared(MediaPlayer mp) {
//start playback
mp.start();
}
public void setList(ArrayList<Song> theSongs) {
songs = theSongs;
}
public class MusicBinder extends Binder {
public MusicService getService() {
return MusicService.this;
}
}
public void playSong() {
//play a song
player.reset();
//get song
Song playSong = songs.get(songPosn);
//get id
long currSong = playSong.getID();
//set uri
Uri trackUri = ContentUris.withAppendedId(
android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
currSong);
//set the data source
try {
player.setDataSource(getApplicationContext(), trackUri);
} catch (Exception e) {
Log.e("MUSIC SERVICE", "Error setting data source", e);
}
player.prepareAsync();
}
public void stopSong() {
player.stop();
player.reset();
}
public void pauseSong() {
player.pause();
}
public void resumeSong() {
player.start();
}
public void setSong(int songIndex) {
songPosn = songIndex;
}
}
AppWidget class
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
// Construct the RemoteViews object
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
// //views.setTextViewText(R.id.appwidget_text, String.valueOf(appWidgetId));
// Create an Intent to launch ExampleActivity
// Intent intent = new Intent(context, MainActivity.class);
// PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
Intent intent = new Intent(context, MusicService.class);
PendingIntent pendingIntent = PendingIntent.getForegroundService(context, 0, intent, 0);
// Get the layout for the App Widget and attach an on-click listener
// to the button
views.setOnClickPendingIntent(R.id.appwidget_text, pendingIntent);
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}

Your service is bound, so problem is that you can't bind to service from AppWidgetProvider (since it's a BroadcastReceiver under the hood). You already make a pending intents on button clicks, just make this intents unique and determine which action is right now in onStartCommand() call in service.
While preparing your remoteview:
Intent intent = new Intent(context, MusicService.class);
intent.setAction("TEXT_CLICK");
PendingIntent pendingIntent = PendingIntent.getForegroundService(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.appwidget_text, pendingIntent);
So now in onStartCommand check for this action like this:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent == null || intent.getAction() == null) {
return super.onStartCommand(null, flags, startId);
}
if (intent.getAction().equals("TEXT_CLICK")) {
//make whatever you want (play/stop song, next/previous etc)
}
return super.onStartCommand(intent, flags, startId);
}

Related

Music Controls in Notification

Following [this tutorial] (http://www.tutorialsface.com/2015/08/android-custom-notification-tutorial) I ended up with the controls showing in the notification, but all are unresponsive (other than showing the Toasts the author included).
The controls don't seem to be bound to the music service in any way. I've tried creating a broadcast, calling the service directly from within the notifications, creating a new instance of the service. I've tried so many things I can't even remember all of them. I've seen people ask similar questions but nothing I've tried works. Now I've tried so many things that I've gotten myself confused about when/where I thought I was on a 'right path'. Any ideas as to how to get these controls functioning properly?
Notification Service:
public class NotificationService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction().equals(Constant.ACTION.STARTFOREGROUND_ACTION)) {
showNotification();
Toast.makeText(this, "Service Started", Toast.LENGTH_SHORT).show();
} else if (intent.getAction().equals(Constant.ACTION.PREV_ACTION)) {
Toast.makeText(this, "Clicked Previous", Toast.LENGTH_SHORT).show();
Log.i("NS", "Clicked Previous");
} else if (intent.getAction().equals(Constant.ACTION.PLAY_ACTION)) {
Log.i("NS", "Clicked Play");
} else if (intent.getAction().equals(Constant.ACTION.NEXT_ACTION)) {
Toast.makeText(this, "Clicked Next", Toast.LENGTH_SHORT).show();
Log.i("NS", "Clicked Next");
} else if (intent.getAction().equals(
Constant.ACTION.STOPFOREGROUND_ACTION)) {
Log.i("NS", "Received Stop Foreground Intent");
Toast.makeText(this, "Service Stoped", Toast.LENGTH_SHORT).show();
stopForeground(true);
stopSelf();
}
return START_STICKY;
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public void showNotification() {
Notification status;
// Using RemoteViews to bind custom layouts into Notification
RemoteViews views = new RemoteViews(getPackageName(),
R.layout.status_bar);
RemoteViews bigViews = new RemoteViews(getPackageName(),
R.layout.status_bar_expanded);
// showing default album image
views.setViewVisibility(R.id.status_bar_icon, View.VISIBLE);
views.setViewVisibility(R.id.status_bar_album_art, View.GONE);
bigViews.setImageViewBitmap(R.id.status_bar_album_art,
Constant.getDefaultAlbumArt(this));
Intent notificationIntent = new Intent(this, NotificationService.class);
notificationIntent.setAction(Constant.ACTION.MAIN_ACTION);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
Intent previousIntent = new Intent(this, NotificationService.class);
previousIntent.setAction(Constant.ACTION.PREV_ACTION);
PendingIntent ppreviousIntent = PendingIntent.getService(this, 0,
previousIntent, 0);
Intent playIntent = new Intent(this, NotificationService.class);
playIntent.setAction(Constant.ACTION.PLAY_ACTION);
PendingIntent pplayIntent = PendingIntent.getService(this, 0,
playIntent, 0);
Intent nextIntent = new Intent(this, NotificationService.class);
nextIntent.setAction(Constant.ACTION.NEXT_ACTION);
PendingIntent pnextIntent = PendingIntent.getService(this, 0,
nextIntent, 0);
Intent closeIntent = new Intent(this, NotificationService.class);
closeIntent.setAction(Constant.ACTION.STOPFOREGROUND_ACTION);
PendingIntent pcloseIntent = PendingIntent.getService(this, 0,
closeIntent, 0);
views.setOnClickPendingIntent(R.id.status_bar_play, pplayIntent);
bigViews.setOnClickPendingIntent(R.id.status_bar_play, pplayIntent);
views.setOnClickPendingIntent(R.id.status_bar_next, pnextIntent);
bigViews.setOnClickPendingIntent(R.id.status_bar_next, pnextIntent);
views.setOnClickPendingIntent(R.id.status_bar_prev, ppreviousIntent);
bigViews.setOnClickPendingIntent(R.id.status_bar_prev, ppreviousIntent);
views.setOnClickPendingIntent(R.id.status_bar_collapse, pcloseIntent);
bigViews.setOnClickPendingIntent(R.id.status_bar_collapse, pcloseIntent);
views.setImageViewResource(R.id.status_bar_play,
R.drawable.apollo_holo_dark_pause);
bigViews.setImageViewResource(R.id.status_bar_play,
R.drawable.apollo_holo_dark_pause);
views.setTextViewText(R.id.status_bar_track_name, "Song Title");
bigViews.setTextViewText(R.id.status_bar_track_name, "Song Title");
views.setTextViewText(R.id.status_bar_artist_name, "Artist Name");
bigViews.setTextViewText(R.id.status_bar_artist_name, "Artist Name");
bigViews.setTextViewText(R.id.status_bar_album_name, "Album Name");
status = new Notification.Builder(this).build();
status.contentView = views;
status.bigContentView = bigViews;
status.flags = Notification.FLAG_ONGOING_EVENT;
status.icon = R.drawable.ic_launcher;
status.contentIntent = pendingIntent;
startForeground(Constant.NOTIFICATION_ID.FOREGROUND_SERVICE, status);
}
}
MusicService:
public class MusicService extends Service implements
MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener,
MediaPlayer.OnCompletionListener {
//media player
private MediaPlayer player;
//song list
private ArrayList<Song> songs;
//current position
private int songPosn;
private final IBinder musicBind = new MusicBinder();
private String songTitle="";
private static final int NOTIFY_ID=1;
private boolean shuffle=false;
private Random rand;
public void onCreate(){
//create the service
super.onCreate();
songPosn=0;
player = new MediaPlayer();
initMusicPlayer();
rand=new Random();
}
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<Song> theSongs){
songs=theSongs;
}
public class MusicBinder extends Binder {
MusicService getService() {
return MusicService.this;
}
}
public void setShuffle(){
if(shuffle) shuffle=false;
else shuffle=true;
}
public void playSong(){
player.reset();
//get song
Song playSong = songs.get(songPosn);
//get id
long currSong = playSong.getID();
//set uri
Uri trackUri = ContentUris.withAppendedId(
android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
currSong);
try{
player.setDataSource(getApplicationContext(), trackUri);
}
catch(Exception e){
Log.e("MUSIC SERVICE", "Error setting data source", e);
}
player.prepareAsync();
songTitle=playSong.getTitle();
}
public void setSong(int songIndex){
songPosn=songIndex;
}
public int getPosn(){
return player.getCurrentPosition();
}
public int getDur(){
return player.getDuration();
}
public boolean isPng(){
return player.isPlaying();
}
public void pausePlayer(){
player.pause();
}
public void seek(int posn){
player.seekTo(posn);
}
public void go(){
player.start();
}
public void playPrev(){
songPosn--;
if(songPosn<0) songPosn=songs.size()-1;
playSong();
}
//skip to next
public void playNext(){
if(shuffle){
int newSong = songPosn;
while(newSong==songPosn){
newSong=rand.nextInt(songs.size());
}
songPosn=newSong;
}
else{
songPosn++;
if(songPosn>=songs.size()) songPosn=0;
}
playSong();
}
#Override
public void onDestroy() {
stopForeground(true);
}
#Override
public IBinder onBind(Intent intent) {
return musicBind;
}
#Override
public boolean onUnbind(Intent intent){
player.stop();
player.release();
return false;
}
#Override
public void onCompletion(MediaPlayer mp) {
if(player.getCurrentPosition()>0){
mp.reset();
playNext();
}
}
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mp.reset();
return false;
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
#Override
public void onPrepared(MediaPlayer mp) {
//start playback
mp.start();
Intent onPreparedIntent = new Intent("MEDIA_PLAYER_PREPARED");
LocalBroadcastManager.getInstance(this).sendBroadcast(onPreparedIntent);
Intent notIntent = new Intent(this, MusicPlayer.class);
notIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendInt = PendingIntent.getActivity(this, 0,
notIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Builder builder = new Notification.Builder(this);
builder.setContentIntent(pendInt)
.setSmallIcon(R.drawable.player_play)
.setTicker(songTitle)
.setOngoing(true)
.setContentTitle("Playing")
.setContentText(songTitle);
Notification not = builder.build();
Intent serviceIntent = new Intent(MusicService.this, NotificationService.class);
serviceIntent.setAction(Constant.ACTION.STARTFOREGROUND_ACTION);
startService(serviceIntent);
}
}
Music Player:
public class MusicPlayer extends AppCompatActivity implements MediaPlayerControl {
private ArrayList<Song> songList;
private ListView songView;
public MusicService musicSrv;
private Intent playIntent;
private boolean musicBound=false;
private MusicController controller;
private boolean paused=false, playbackPaused=false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_music_player);
songView = (ListView)findViewById(R.id.song_list);
songList = new ArrayList<Song>();
getSongList();
Collections.sort(songList, new Comparator<Song>(){
public int compare(Song a, Song b){
return a.getArtist().compareTo(b.getArtist());
}
});
songAdapter songAdt = new songAdapter(this, songList);
songView.setAdapter(songAdt);
setController();
FloatingActionButton fabRandom = (FloatingActionButton)findViewById(R.id.fabRandom);
fabRandom.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
}
//play next
private void playNext(){
musicSrv.playNext();
if(playbackPaused){
setController();
playbackPaused=false;
}
controller.show(0);
}
private void playPrev(){
musicSrv.playPrev();
if(playbackPaused){
setController();
playbackPaused=false;
}
controller.show(0);
}
public void songPicked(View view){
musicSrv.setSong(Integer.parseInt(view.getTag().toString()));
musicSrv.playSong();
if(playbackPaused){
setController();
playbackPaused=false;
}
setController();
controller.show(0);
}
#Override
protected void onPause(){
super.onPause();
paused=true;
}
#Override
protected void onResume(){
super.onResume();
// Set up receiver for media player onPrepared broadcast
LocalBroadcastManager.getInstance(this).registerReceiver(onPrepareReceiver,
new IntentFilter("MEDIA_PLAYER_PREPARED"));
if(paused){
setController();
paused=false;
}
}
#Override
protected void onStop() {
super.onStop();
}
private void setController(){
//set the controller up
if (controller == null) controller = new MusicController(this);
controller.invalidate();
controller.setPrevNextListeners(new View.OnClickListener() {
#Override
public void onClick(View v) {
playNext();
}
}, new View.OnClickListener() {
#Override
public void onClick(View v) {
playPrev();
}
});
controller.setMediaPlayer(this);
controller.setAnchorView(findViewById(R.id.song_list));
}
#Override
public void onBackPressed() {
moveTaskToBack(true);
Intent intent = new Intent (getApplicationContext(), FitnessActivity.class);
startActivity(intent);
}
// Broadcast receiver to determine when music player has been prepared
private BroadcastReceiver onPrepareReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context c, Intent i) {
// When music player has been prepared, show controller
controller.show(0);
}
};
private BroadcastReceiver onNextClickedReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
musicSrv.playNext();
}
};
//connect to the service
public ServiceConnection musicConnection = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicService.MusicBinder binder = (MusicService.MusicBinder)service;
//get service
musicSrv = binder.getService();
//pass list
musicSrv.setList(songList);
musicBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
musicBound = false;
}
};
#Override
protected void onStart() {
super.onStart();
if(playIntent==null){
playIntent = new Intent(this, MusicService.class);
bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
startService(playIntent);
setController();
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_shuffle:
musicSrv.setShuffle();
break;
case R.id.action_end:
stopService(playIntent);
musicSrv=null;
System.exit(0);
break;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onDestroy() {
stopService(playIntent);
musicSrv=null;
super.onDestroy();
}
public void getSongList() {
//retrieve song info
ContentResolver musicResolver = getContentResolver();
Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor musicCursor = musicResolver.query(musicUri, null, null, null, null);
if(musicCursor!=null && musicCursor.moveToFirst()){
//get columns
int titleColumn = musicCursor.getColumnIndex
(android.provider.MediaStore.Audio.Media.TITLE);
int idColumn = musicCursor.getColumnIndex
(android.provider.MediaStore.Audio.Media._ID);
int artistColumn = musicCursor.getColumnIndex
(android.provider.MediaStore.Audio.Media.ARTIST);
int durationColumn = musicCursor.getColumnIndex
(MediaStore.Audio.Media.DURATION);
//add songs to list
do {
long thisId = musicCursor.getLong(idColumn);
String thisTitle = musicCursor.getString(titleColumn);
String thisArtist = musicCursor.getString(artistColumn);
long thisDuration = musicCursor.getLong(durationColumn);
if (thisDuration>10000){
songList.add(new Song(thisId, thisTitle, thisArtist, thisDuration));}
}
while (musicCursor.moveToNext());
}
}
#Override
public void start() {
musicSrv.go();
}
#Override
public void pause() {
playbackPaused=true;
musicSrv.pausePlayer();
}
#Override
public int getDuration() {
if(musicSrv!=null && musicBound && musicSrv.isPng())
return musicSrv.getDur();
else return 0;
}
#Override
public int getCurrentPosition() {
if(musicSrv!=null && musicBound && musicSrv.isPng())
return musicSrv.getPosn();
else return 0;
}
#Override
public void seekTo(int pos) {
musicSrv.seek(pos);
}
#Override
public boolean isPlaying() {
if(musicSrv!=null && musicBound)
return musicSrv.isPng();
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;
}
public void onNextNotification(){
}
}
Manifest:
<activity
android:name=".MusicPlayer"
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MusicService"
/>
<service android:name=".NotificationService" />
Your notification actions gets received by Notifications service, not the Music service. Edit notification intents to target Music Service
Intent playIntent = new Intent(this, MusicService.class);
//... edit all of them
Move onStartCommand() method to Music Service and assign actions
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction().equals(Constant.ACTION.PLAY_ACTION)) {
//call play method
}
//...etc
except STARTFOREGROUND_ACTION and STOPFOREGROUND_ACTION, leave it in Notification Service's onStartCommand(). Also insert null check on Intent in both services.

Set Action buttons of notification bar

I know it's kinda repeated question but i totally failed to know what's wrong.
Actually , i am trying to create a media player that should be controlled from notification bar (play , pause , resume). The player is playing fine and the notification bar is displayed but when i click on the pause button for example it throws a null pointer exception. i guess the error is in the action of button itself as it can't start the service to perform the functions.
Also , the notification bar is not updated well and the service keeps creating itself even after being killed.
Here is my code :
MusicService.java
// play the music in the Service class, but control it from the Activity class,
public class MusicService extends Service implements
MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener,
MediaPlayer.OnCompletionListener {
private String songTitle="";
//media player
private MediaPlayer player;
//song list
private ArrayList<Music> songs;
//current position
private int songPosn;
private int length=0;
private static final String LOG_TAG = "ForegroundService";
#Override
public void onCreate() {
super.onCreate();
player =new MediaPlayer();
songPosn=0;
Toast.makeText(this, "Service was Created", Toast.LENGTH_LONG).show();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
songs = (ArrayList<Music>)intent.getSerializableExtra("array");
songPosn=intent.getIntExtra("id",0);
playSong();
Notify();
if(intent.getAction().equals(Constants.ACTION.STARTFOREGROUND_ACTION)) {
Log.i(LOG_TAG, "Received Start Foreground Intent ");}
else if (intent.getAction().equals(Constants.ACTION.RESUME_ACTION)) {
Log.i(LOG_TAG, "Clicked Resume");
} else if (intent.getAction().equals(Constants.ACTION.PLAY_ACTION)) {
Log.i(LOG_TAG, "Clicked Play");
} else if (intent.getAction().equals(Constants.ACTION.PAUSE_ACTION)) {
Log.i(LOG_TAG, "Clicked pause");
} else if (intent.getAction().equals(
Constants.ACTION.STOPFOREGROUND_ACTION)) {
Log.i(LOG_TAG, "Received Stop Foreground Intent");
stopForeground(true);
stopSelf();
}
return START_REDELIVER_INTENT;
}
#Override
public void onDestroy() {
super.onDestroy();
if (player.isPlaying()) {
player.stop();
}
player.release();
Log.i(LOG_TAG, "In onDestroy");
stopForeground(true);
}
public void pauseMusic()
{
if(player.isPlaying())
{
player.pause();
length=player.getCurrentPosition();
}
}
public void resumeMusic()
{
if(player.isPlaying()==false)
{
player.seekTo(length);
player.start();
}
}
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
songPosn=songPosn+1;
playSong();
mediaPlayer.start();
}
#Override
public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
return false;
}
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
player.start();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
public void playSong() {
player.reset();
//get song
Music playSong = songs.get(songPosn);
songTitle=playSong.getMusicTitle();
//get id
long currSong = playSong.getMusicId();
// set uri
Uri trackUri = ContentUris.withAppendedId(
android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
currSong);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setOnPreparedListener(this); // listner when the MediaPlayer instance is prepared
player.setOnErrorListener(this); // an error is thrown
player.setOnCompletionListener(this);
try{
player.setDataSource(getApplicationContext(), trackUri);
}
catch(Exception e){
Log.e("MUSIC SERVICE", "Error setting data source", e);
}
player.prepareAsync();
Toast.makeText(this, "play music",
Toast.LENGTH_LONG).show();
}
public void Notify()
{
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setAction(Constants.ACTION.MAIN_ACTION);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
Intent resumeIntent = new Intent(this, MusicService.class);
resumeIntent.setAction(Constants.ACTION.RESUME_ACTION);
PendingIntent rresumeIntent = PendingIntent.getService(this, 0,
resumeIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Intent playIntent = new Intent(this, MusicService.class);
playIntent.setAction(Constants.ACTION.PLAY_ACTION);
PendingIntent pplayIntent = PendingIntent.getService(this, 0,
playIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Intent pauseIntent = new Intent(this, MusicService.class);
pauseIntent.setAction(Constants.ACTION.PAUSE_ACTION);
PendingIntent ppauseIntent = PendingIntent.getService(this, 0,
pauseIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Bitmap icon = BitmapFactory.decodeResource(getResources(),
R.drawable.pic);
NotificationCompat.Builder notification = new NotificationCompat.Builder(this)
.setContentTitle(songTitle)
.setTicker(songTitle)
.setContentText("My Music")
.setSmallIcon(R.drawable.pic)
.setLargeIcon(
Bitmap.createScaledBitmap(icon, 128, 128, false))
.setContentIntent(pendingIntent)
.setPriority(Notification.PRIORITY_MAX)
.addAction(android.R.drawable.ic_media_ff,
"Resume", rresumeIntent)
.addAction(android.R.drawable.ic_media_play, "Play",
pplayIntent)
.addAction(android.R.drawable.ic_media_pause, "Pause",
ppauseIntent);
NotificationManager mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNotifyMgr.notify(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE,
notification.build());
notification.setContentTitle(songTitle);
mNotifyMgr.notify(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE,notification.build());
}
}
MusicFragment.java
public class MusicFragment extends android.support.v4.app.Fragment {
private final String LOG_TAG = MusicFragment.class.getSimpleName();
private ArrayList<Music> songList;
private ListView songView;
private MusicService musicSrv = new MusicService() ;
private Intent playIntent;
private boolean musicBound=false;
private LinearLayout songsLayout;
private MusicController controller;
SongAdapter songAdt;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View myView = inflater.inflate(R.layout.activity_music_fragment, container, false);
songView = (ListView)myView.findViewById(R.id.song_list);
songsLayout =(LinearLayout)myView.findViewById(R.id.song_layout);
setHasOptionsMenu(true);
songList = new ArrayList<Music>();
getSongList();
// sort songs alphabitcally
Collections.sort(songList, new Comparator<Music>(){
public int compare(Music a, Music b){
return a.getMusicTitle().compareTo(b.getMusicTitle());
}
});
songAdt = new SongAdapter(getActivity(), songList);
songView.setAdapter(songAdt);
songView.setOnItemClickListener(new ListClickHandler());
return myView;
}
#Override
public void onCreateOptionsMenu (Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.service_menu, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_end:
getActivity().stopService(playIntent);
musicSrv=null;
System.exit(0);
break;
}
return super.onOptionsItemSelected(item);
}
public void getSongList() {
ContentResolver musicResolver = getContext().getContentResolver();
Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor musicCursor = musicResolver.query(musicUri, null, null, null, null);
if(musicCursor!=null && musicCursor.moveToFirst()){
//get columns
int titleColumn = musicCursor.getColumnIndex
(android.provider.MediaStore.Audio.Media.TITLE);
int idColumn = musicCursor.getColumnIndex
(android.provider.MediaStore.Audio.Media._ID);
int artistColumn = musicCursor.getColumnIndex
(android.provider.MediaStore.Audio.Media.ARTIST);
//add songs to list
do {
long thisId = musicCursor.getLong(idColumn);
String thisTitle = musicCursor.getString(titleColumn);
String thisArtist = musicCursor.getString(artistColumn);
songList.add(new Music(thisId, thisTitle, thisArtist));
}
while (musicCursor.moveToNext());
}
}
public class ListClickHandler implements AdapterView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> adapter, View view, int position, long arg3) {
// TODO Auto-generated method stub
Intent startIntent = new Intent(getActivity(), MusicService.class);
startIntent.setAction(Constants.ACTION.STARTFOREGROUND_ACTION);
startIntent.putExtra("array",songList);
startIntent.putExtra("id",Integer.parseInt(view.getTag().toString()));
getActivity().startService(startIntent);
}}
#Override
public void onDestroy() {
super.onDestroy();
musicSrv.stopForeground(true);
}
}
Logcat :
E/AndroidRuntime: FATAL EXCEPTION: main java.lang.RuntimeException: Unable to start service .MusicService#42bb1fa0 with Intent { act=.MusicService.action.pause flg=0x10000000 cmp=/.MusicService bnds=[518,1047][720,1143] }: java.lang.NullPointerException
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2850)
at android.app.ActivityThread.access$2000(ActivityThread.java:159)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1419)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:5419)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
at dalvik.system.NativeStart.main(Native Method)

How know if mediaplayer controls on notification are playing music or not?

I'm doing a sound app that contains a main activity and 2 services, in the mainActivity I can control if the music is played or paused manually with a button on the main activity(so you can see it on the screen) that starts a service which active/stop mediaplayer. Moreover, I have a media player control on notification in other service for control the play/stop on the background. The problem is that I need to cordinate the notification in the background with the main controls of the main activity, for example when I put the lockscreen (with the music is playing) and I press stop on the notification, the music doens't stop because in the main activity the service of mediaplayer continues enabled. So, I need to know when the notification is playing music or not in the main activity for doing a boolean (if the notification stops the music, i want that de mediaplayer service stops the music).
Thank you all!
This is the code of my notification :
public class Notificaciones extends Service {
public static final String ACTION_PLAY = "action_play";
public static final String ACTION_PAUSE = "action_pause";
public static final String ACTION_REWIND = "action_rewind";
public static final String ACTION_FAST_FORWARD = "action_fast_forward";
public static final String ACTION_NEXT = "action_next";
public static final String ACTION_PREVIOUS = "action_previous";
public static final String ACTION_STOP = "action_stop";
public static final String ACTION_BAR = "action_bar";
private MediaSession mSession;
private MediaSessionManager mManager;
private MediaController mController;
private MediaPlayer mMediaPlayer;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (mManager == null) {
mMediaPlayer = new MediaPlayer();
mSession = new MediaSession(getApplicationContext(), "example");
mController = new MediaController(getApplicationContext(), mSession.getSessionToken());
mSession.setCallback(new MediaSession.Callback() {
#Override
public void onPlay() {
super.onPlay();
Log.e("MyServiceClass", "onPlay");
buildNotification(generateAction(android.R.drawable.ic_media_pause, "Pause", ACTION_PAUSE));
}
#Override
public void onPause() {
super.onPause();
Log.e("MyServiceClass", "onPause");
buildNotification(generateAction(android.R.drawable.ic_media_play, "Play", ACTION_PLAY));
}
#Override
public void onSkipToNext() {
super.onSkipToNext();
buildNotification(generateAction(android.R.drawable.ic_media_pause, "Pause", ACTION_PAUSE));
}
#Override
public void onFastForward() {
super.onFastForward();
}
#Override
public void onRewind() {
super.onRewind();
}
#Override
public void onStop() {
super.onStop();
Log.e("MyServiceClass", "onStop");
NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(1);
Intent intent = new Intent(getApplicationContext(), MyServiceClass.class);
stopService(intent);
}
});
}
handleIntent(intent);
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
Log.e("MyServiceClass", "onStop");
mController.getTransportControls().stop();
NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(1);
Intent intent = new Intent(getApplicationContext(), MyServiceClass.class);
stopService(intent);
mMediaPlayer.stop();
mMediaPlayer.release();
stopSelf();
super.onDestroy();
}
private void handleIntent (Intent intent){
if (intent == null || intent.getAction()==null){
return;
}
String action = intent.getAction();
if (action.equalsIgnoreCase(ACTION_PLAY)){
mController.getTransportControls().play();
}else if (action.equalsIgnoreCase(ACTION_PAUSE)){
mController.getTransportControls().pause();
}else if (action.equalsIgnoreCase(ACTION_FAST_FORWARD)){
mController.getTransportControls().fastForward();
}else if (action.equalsIgnoreCase(ACTION_REWIND)){
mController.getTransportControls().rewind();
}else if (action.equalsIgnoreCase(ACTION_PREVIOUS)){
mController.getTransportControls().skipToPrevious();
}else if (action.equalsIgnoreCase(ACTION_NEXT)){
mController.getTransportControls().skipToNext();
}else if (action.equalsIgnoreCase(ACTION_STOP)){
mController.getTransportControls().stop();
}if (action.equalsIgnoreCase(ACTION_BAR)){
mController.getTransportControls().stop();
}
}
private android.app.Notification.Action generateAction(int icon, String title, String intentAction){
Intent intent = new Intent(getApplicationContext(), MyServiceClass.class);
intent.setAction(intentAction);
PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 1, intent, 0);
return new android.app.Notification.Action.Builder(icon, title, pendingIntent).build();
}
private void buildNotification(android.app.Notification.Action action){
android.app.Notification.MediaStyle style = new android.app.Notification.MediaStyle();
Intent intent = new Intent(getApplicationContext(), MyServiceClass.class);
intent.setAction(ACTION_STOP);
PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 1, intent, 0);
android.app.Notification.Builder builder = new android.app.Notification.Builder(this).setSmallIcon(R.drawable.logo).setContentTitle("TEEN FM").setContentText("Adolescents.cat")
.setDeleteIntent(pendingIntent).setStyle(style);
builder.addAction(generateAction(android.R.drawable.ic_media_pause, "Previous", ACTION_PREVIOUS));
builder.addAction(generateAction(android.R.drawable.ic_media_rew, "Rewind", ACTION_REWIND));
builder.addAction(action);
builder.addAction(generateAction(android.R.drawable.ic_media_ff, "Fast Forward", ACTION_FAST_FORWARD));
builder.addAction(generateAction(android.R.drawable.ic_media_next, "Next", ACTION_NEXT));
style.setShowActionsInCompactView(0, 1, 2, 3, 4);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, builder.build());
}
#Override
public boolean onUnbind(Intent intent) {
mSession.release();
return super.onUnbind(intent);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
You should declarate your MediaPlayer like a static Object in your MainActivity and you will call it from the Notificaciones Service.
private static MediaPlayer mMediaPlayer;
MainActivity main;
When you want stop it, you should do the next thing:
main=new MainActivity();
main.mMediaPlayer.stop
//this is an example, i don't know how is your player working. Because If your are creating anohe instance of you MediaPlayer you will not stop it never from the Service. The MediaPlayer service is an instance and the Activity MediaPlayer is another one.
If you need more help me. Let me know. Have a nice day!

Service stops when activity is destroyed

I have searched a lot on stackoverflow regarding this issue but nothing seems to work.
I am developing a music player which plays music by binding to a service. I have two activities.The first activity(called as AllSongs) provides me with the list of songs.When I select a song it starts another activity(called as SongUI) which plays the song by binding to a service.
Now when I move back to my AllSongs activity the music stops.Now when I select a song again,my SongUI activity is started and when I go back to my AllSongs activity, the music does not stop and plays in the background.I am not able to understand what is causing this issue. I think I am doing something silly somewhere but am not able to figure it out. I want songs to be played in the background same as any music player does.Here is the code.
AllSongs activity:
public class AllSongs extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.allsongs_activity);
getSongList();
from = new String[]{MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.DURATION};
to = new int[]{R.id.title_entry,R.id.artist_entry,R.id.duration_entry};
listView = (ListView) findViewById(R.id.listView);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,R.layout.singlesong,myCursor,from,to,SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent songUIIntent = new Intent(getApplicationContext(),SongUI.class);
songUIIntent.putExtra("position",id);
startActivity(songUIIntent);
}
});
}
private void getSongList() {
ContentResolver myContentResolver = getContentResolver();
myCursor = myContentResolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,null,null,null,null);
if(myCursor!=null && myCursor.moveToFirst()) {
int titleColumn = myCursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
int idColumn = myCursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID);
int artistColumn = myCursor.getColumnIndex(android.provider.MediaStore.Audio.Media.ARTIST);
long albumID = myCursor.getLong(myCursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
do {
long ID = myCursor.getLong(idColumn);
String title = myCursor.getString(titleColumn);
String artist = myCursor.getString(artistColumn);
songList.add(new currentSong(ID,title,artist));
}while (myCursor.moveToNext());
}
}
#Override
protected void onDestroy() {
super.onDestroy();
}
}
SongUI activity:
public class SongUI extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.song_ui);
button = (Button) findViewById(R.id.play);
isBound = false;
Intent receivedIntent = getIntent();
position = receivedIntent.getLongExtra("position",0);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main,menu);
return super.onCreateOptionsMenu(menu);
}
public void playAudio(View view) {
Intent objIntent = new Intent(this,MyService.class);
if(!isBound)
{
objIntent.putExtra("position", position);
startService(objIntent);
isBound=true;
button.setBackgroundResource(R.drawable.play);
bindService(objIntent, myConnection, Context.BIND_AUTO_CREATE);
}
else
{
myServiceObject.pauseAudio();
button.setBackgroundResource(R.drawable.play);
isBound=false;
unbindService(myConnection);
}
}
public void stopAudio(View view) {
Intent objIntent = new Intent(this,MyService.class);
if(isBound)
{
isBound=false;
unbindService(myConnection);
stopService(objIntent);
}
else {
stopService(objIntent);
}
button.setBackgroundResource(R.drawable.play);
}
private ServiceConnection myConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
myServiceObject = ((MusicBinder) service).getService();
isBound = true;
}
public void onServiceDisconnected(ComponentName arg0) {
isBound = false;
}
};
#Override
protected void onDestroy() {
super.onDestroy();
if (isBound) {
unbindService(myConnection);
isBound = false;
}
}
}
MyService class
public class MyService extends Service {
#Override
public void onCreate() {
super.onCreate();
player = new MediaPlayer();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "on startCommand is called");
long id = intent.getLongExtra("position",0);
Uri contentUri = ContentUris.withAppendedId(
android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id);
Log.d(TAG, "Service is Started");
player = MediaPlayer.create(this,contentUri);
player.start();
Intent notIntent = new Intent(this, SongUI.class);
notIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendInt = PendingIntent.getActivity(this, 0,
notIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Builder builder = new Notification.Builder(this);
builder.setContentIntent(pendInt)
.setSmallIcon(R.drawable.play)
.setTicker(songTitle)
.setOngoing(true)
.setContentTitle("Playing")
.setContentText(songTitle);
Notification notification = builder.build();
startForeground(NOTIFY_ID, notification);
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "on Bind is called");
return myBinder;
}
#Override
public boolean onUnbind(Intent intent){
Log.d(TAG,"onUnbind is called");
player.stop();
player.release();
return false;
}
public class MusicBinder extends Binder {
MyService getService() {
return MyService.this;
}
}
public void pauseAudio() {
if(player.isPlaying()) {
player.pause();
}
}
#Override
public void onDestroy() {
Log.d(TAG,"on destroy is called");
stopForeground(true);
}
I have figured out where I was going wrong. I was calling unbindService(myConnection) in onDestroy of my SongsUI activity which was stopping the playback.
And the reason why this was not the case the second time round was that I was returning false in onUnbind method. So the system was not calling onBind method the second time and subsequently onUnbind was also not getting called. Hence the playback was also not stopping.

Pass an arraylist of strings from activity to service in Android

I've made a functional android application that implements MediaPlayer and I know it's late now but better now than never, I want to implement a service to be able to play media while multitasking on other applications.
Is there a way how can I pass for example an ArrayList of String from activity to the service ? What I have found were information about Custom Objects that are passed through parcelable which I think is not needed.
For example, how I've started my transition:
public class PlayerService extends Service implements MediaPlayer.OnPreparedListener{
private static final String ACTION_PLAY = "action.PLAY";
private static final String ACTION_PAUSE = "action.PAUSE";
private MediaPlayer mediaPlayer = null;
#Override
public void onCreate() {
mediaPlayer = new MediaPlayer();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction().equals(ACTION_PLAY)) {
try {
if(mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.reset();
mediaPlayer.setDataSource(musicUrl.get(position));
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.prepareAsync();
} catch (IOException e) {
e.printStackTrace();
}
// setCurrentSong(myDataList.get(position));
// morphButton.setState(MorphButton.MorphState.START);
//
// setHighlight(myDataList.get(currentPosition));
}
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onPrepared(MediaPlayer mp) {
}
}
As you can see, I need to get from an ArrayList the music URL to prepare de MediaPlayer
In your activity, where you bind to the service you can add an ArrayList<String> via the intent:
ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
ArrayList<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("b");
Intent i = new Intent(this, BLEDiscoveryService.class);
i.putStringArrayListExtra("list", stringList);
bindService(new Intent(this, MyService.class), serviceConnection, BIND_AUTO_CREATE);
And in your service's onBind() you can retrieve it from the passed intent.
public class LocalBinder extends Binder {
public MyService getService() {
return MyService.this;
}
}
#Override
public void onCreate() {
super.onCreate();
binder = new LocalBinder();
}
#Override
public IBinder onBind(Intent intent) {
ArrayList<String> stringList = intent.getStringArrayListExtra("list");
return binder;
}

Categories

Resources