the_dani the_dani - 5 months ago 17
Android Question

Notification isn't cancelable

I'm working on a Music-App, so my Notification uses MediaStyle and is shown linked with a foreground-service.

My Service:

public class MusicService extends Service
implements AudioManager.OnAudioFocusChangeListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener{

//region Variables

...

//endregion

//region Service

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

InitMediaPlayer();

mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
mPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());

iCurrentSongIndex = 0;
iSeekTo = -1;

bPlayingFromQueue = false;

bStarted = bPreparing = bRestartAfterLoss = bControlReceiverRegistered = false;

mPlayMode = PlayMode.PASS;

mSongQueue = new ArrayList<>();

nManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

int iRequestResult = mAudioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);

if (iRequestResult != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
Toast.makeText(getApplicationContext(), "Couldn't gain the Permission to play music!", Toast.LENGTH_LONG).show();

stopForeground(true);
stopSelf();

return;
}

mControlReceiver = new MediaControlReceiver();

IntentFilter infNotification = new IntentFilter();
infNotification.addAction(MediaControlReceiver.NOTIFY_PLAYPAUSE);
infNotification.addAction(MediaControlReceiver.NOTIFY_PREVIOUS);
infNotification.addAction(MediaControlReceiver.NOTIFY_NEXT);
infNotification.addAction(MediaControlReceiver.NOTIFY_CANCEL);
infNotification.addAction(Intent.ACTION_HEADSET_PLUG);

if (!bControlReceiverRegistered) {
registerReceiver(mControlReceiver, infNotification);

bControlReceiverRegistered = true;
}

mRemoteControlComponent = new ComponentName(this, RemoteControlReceiver.class);

mAudioManager.registerMediaButtonEventReceiver(mRemoteControlComponent);

getTheme().applyStyle(RuntimeInfo.getThemeID(), true);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
return new MusicBinder();
}

@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}

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

if (mMediaPlayer != null) {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
}

mMediaPlayer.reset();
mMediaPlayer.release();

mMediaPlayer = null;
}

if (bControlReceiverRegistered) {
unregisterReceiver(mControlReceiver);

mControlReceiver = null;
}

mAudioManager.unregisterMediaButtonEventReceiver(mRemoteControlComponent);

mAudioManager = null;

SharedPreferences.Editor mEditor = mPreferences.edit();

mEditor.putString(Constants.Preferences.PLAYMODE, mPlayMode.toString());

mEditor.apply();

if (SleepTimer.isTimerRunning()) {
SleepTimer.cancelTimer();
}
}

@Override
public void onAudioFocusChange(int focusChange) {
if (isActive()) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
if (bRestartAfterLoss) {
mMediaPlayer.setVolume(1.0f, 1.0f);

if (!isPlaying() && !isPreparing()) {
play();
}
}
break;
case AudioManager.AUDIOFOCUS_LOSS:
bRestartAfterLoss = false;

if (isPlaying()) {
pause();
}
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
bRestartAfterLoss = true;

if (isPlaying()) {
pause();
}
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
bRestartAfterLoss = true;

int duckFactor = mPreferences.getInt(getResources().getString(R.string.keyDuckVolume), 10);

float percent = (float) duckFactor / 100f;

mMediaPlayer.setVolume(percent, percent);
break;
}
}
}

//endregion

//region Control-Methods

public void play() {
if (!bStarted) {
playSong(iCurrentSongIndex);
}
else {
mMediaPlayer.start();

startForeground(NOTIFICATION_ID, Build_Notification());

if (mCallback != null) {
mCallback.onPlayPause(true);
}
}
}

public void pause() {
mMediaPlayer.pause();

nManager.notify(NOTIFICATION_ID, Build_Notification());

if (mCallback != null) {
mCallback.onPlayPause(false);
}
}

//endregion

//region MediaPlayer

@Override
public void onCompletion(MediaPlayer mp) {
if (mSongQueue.size() > 0) {
playSong(PLAY_QUEUE);
}
else {
switch (mPlayMode) {
default:
case PASS:
if (iCurrentSongIndex++ < sSongs.length) {
playSong(iCurrentSongIndex);
}
else {
mNotification = null;

if (mCallback != null) {
mCallback.onCompleted(getCurrentSong());
}
}
break;
case REPEAT_SINGLE:
playSong(iCurrentSongIndex);
break;
case REPEAT_ALL:
next();
break;
case SHUFFLE:
iCurrentSongIndex = new Random().nextInt(sSongs.length);

playSong(iCurrentSongIndex);
break;
}
}
}

@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mp.reset();

return false;
}

@Override
public void onPrepared(MediaPlayer mp) {
if (iSeekTo != -1) {
mp.seekTo(iSeekTo);

iSeekTo = -1;
}

mp.start();

SharedPreferences.Editor editor = mPreferences.edit();
editor.putLong(Constants.Preferences.LAST_SONG, getCurrentSong().getID());
editor.apply();

startForeground(NOTIFICATION_ID, Build_Notification());

bPreparing = false;

if (!bStarted) {
bStarted = true;
}
}

//endregion

//region Methods

private void InitMediaPlayer() {
mMediaPlayer = new MediaPlayer();

mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.setOnCompletionListener(this);
mMediaPlayer.setOnErrorListener(this);
}

private Notification Build_Notification() {
NotificationCompat.Builder nBuilder = new NotificationCompat.Builder(this);
nBuilder.setShowWhen(false);

TypedValue typedValue = new TypedValue();

getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);

int iPrimaryColor = typedValue.data;

nBuilder.setColor(iPrimaryColor);

Intent notIntent = new Intent(getApplicationContext(), MainActivity.class);

PendingIntent notOpenOnClick = PendingIntent.getActivity(getApplicationContext(), 0, notIntent, PendingIntent.FLAG_UPDATE_CURRENT);

MediaSessionCompat mMediaSession = new MediaSessionCompat(getApplicationContext(), getPackageName());

MediaMetadataCompat.Builder mMetaDataBuilder = new MediaMetadataCompat.Builder();

mMetaDataBuilder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, getCurrentSong().getTitle())
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, getCurrentSong().getAlbum())
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, getCurrentSong().getArtist());

if (isPreparing() || isPlaying()) {
mMediaSession.setActive(true);
}
else {
mMediaSession.setActive(false);
}

mMediaSession.setMetadata(mMetaDataBuilder.build());

mMediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);

nBuilder.setSmallIcon(R.drawable.not_icon)
.setContentTitle(getCurrentSong().getTitle())
.setContentText(getCurrentSong().getAlbum() + " - " + getCurrentSong().getArtist())
.setLargeIcon(new ArtworkProvider(this).getAlbumArtwork(getCurrentSong().getAlbumID(), 100, 100))
.setContentIntent(notOpenOnClick);

Intent previous = new Intent(MediaControlReceiver.NOTIFY_PREVIOUS);
Intent next = new Intent(MediaControlReceiver.NOTIFY_NEXT);
Intent playpause = new Intent(MediaControlReceiver.NOTIFY_PLAYPAUSE);
Intent cancel = new Intent(MediaControlReceiver.NOTIFY_CANCEL);

PendingIntent pPrevious = PendingIntent.getBroadcast(getApplicationContext(), 0, previous, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent pPlayPause = PendingIntent.getBroadcast(getApplicationContext(), 0, playpause, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent pNext = PendingIntent.getBroadcast(getApplicationContext(), 0, next, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent pCancel = PendingIntent.getBroadcast(getApplicationContext(), 0, cancel, PendingIntent.FLAG_UPDATE_CURRENT);

nBuilder.addAction(R.drawable.ic_previous_48dp, MediaControlReceiver.NOTIFY_PREVIOUS, pPrevious);

if (isPreparing() || isPlaying()) {
nBuilder.addAction(R.drawable.ic_pause_48dp, MediaControlReceiver.NOTIFY_PLAYPAUSE, pPlayPause);
}
else {
nBuilder.addAction(R.drawable.ic_play_48dp, MediaControlReceiver.NOTIFY_PLAYPAUSE, pPlayPause);
}

nBuilder.addAction(R.drawable.ic_next_48dp, MediaControlReceiver.NOTIFY_NEXT, pNext);

nBuilder.setStyle(new NotificationCompat.MediaStyle()
.setMediaSession(mMediaSession.getSessionToken())
.setShowActionsInCompactView(0, 1, 2)
.setShowCancelButton(true)
.setCancelButtonIntent(pCancel));

mNotification = nBuilder.build();

return mNotification;
}

//endregion

public enum PlayMode {
PASS, REPEAT_SINGLE, REPEAT_ALL, SHUFFLE
}

public class MusicBinder extends Binder {
public MusicService getService() {
return MusicService.this;
}
}
}


I don't set the Notification Property "OnGoing" to true, I already tried to set it to false, but this doesn't change anything!

Answer

I did a silly mistake:

I forgot to call stopForeground(false) in pause().

Here my working code:

public void pause() {
    mMediaPlayer.pause();

    stopForeground(false);

    nManager.notify(NOTIFICATION_ID, Build_Notification());

    if (mCallback != null) {
        mCallback.onPlayPause(false);
    }
}