Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android O - Notification Channels - Change Vibration Pattern or Sound Type

Tags:

With Android O we get the "Notification Channels".

As far as I understand that means that the user can't set the notification tone or other related Notification settings inside the APP anymore .

The user needs to go to the "Notification Channels Setting" and change the tone or vibration etc. here because all methods from the NotificationBuilder like setSound are getting ignored.

So there is really NO way to change the tone to silent via code?
Or to change the vibration pattern via code?

For example the user have the ability to set the vibration pattern in my app.
Or he can pick tones from the alarm type instead of the notification type.

All this is not possible anymore?
Is this right or is there any way to do this?

like image 243
chrisonline Avatar asked Jul 13 '17 13:07

chrisonline


People also ask

What are advantages of notification channel Android?

What Are the Benefits of Using Notification Channels? By adding notification channels to Android, Google allowed end users to control their receipt of push messages, so that they can be alerted to the types of messages they want most, while opting out of the ones that don't interest them.

What is a notification channel Android?

What Are Notification Channels? Notification channels enable us app developers to group our notifications into groups—channels—with the user having the ability to modify notification settings for the entire channel at once.


2 Answers

You can still offer sound and vibration customization in your app, but it requires a different approach. In short, the idea is to play sound and vibration manually in Android O instead of using the notification channel (it's easier than it seems).

This is how I did it:

NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId);  // builder.setSmallIcon(...) // builder.setContentTitle(...) // builder.setContentText(...)  if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {      // play vibration     vibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);     vibrator.vibrate(VibrationEffect.createWaveform(vibrationPattern, -1));      // play sound     Intent serviceIntent = new Intent(context, SoundService.class);     serviceIntent.setAction("ACTION_START_PLAYBACK");     serviceIntent.putExtra("SOUND_URI", soundUri.toString());     context.startForegroundService(serviceIntent);      // the delete intent will stop the sound when the notification is cleared     Intent deleteIntent = new Intent(context, SoundService.class);     deleteIntent.setAction("ACTION_STOP_PLAYBACK");     PendingIntent pendingDeleteIntent =             PendingIntent.getService(context, 0, deleteIntent, 0);     builder.setDeleteIntent(pendingDeleteIntent);  } else {      builder.setVibrate(vibrationPattern);     builder.setSound(soundUri);  }  notificationManager.notify(notificationId, builder.build()); 

SoundService.class is the place where I play the sound with MediaPlayer:

public class SoundService extends Service {      MediaPlayer mMediaPlayer;      @Override     public IBinder onBind(Intent intent) {         return null;     }      public int onStartCommand(Intent intent, int flags, int startId) {          // foreground notification         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {             NotificationCompat.Builder builder =                 new NotificationCompat.Builder(this, otherChannelId);             builder.setSmallIcon(...)                     .setContentTitle(...)                     .setContentText(...)                     .setAutoCancel(true);             startForeground(foregroundNotificationId, builder.build());         }          // check action         String action = intent.getAction();         switch (action) {             case "ACTION_START_PLAYBACK":                 startSound(intent.getStringExtra("SOUND_URI"));                 break;             case "ACTION_STOP_PLAYBACK":                 stopSound();                 break;         }          // service will not be recreated if abnormally terminated         return START_NOT_STICKY;     }      private void startSound(String uriString) {          // parse sound         Uri soundUri;         try {             soundUri = Uri.parse(uriString);         } catch (Exception e) {             cleanup();             return;         }          // play sound         if (mMediaPlayer == null) {             mMediaPlayer = new MediaPlayer();             mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {                 @Override                 public void onPrepared(MediaPlayer mp) {                     mp.start();                 }             });             mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {                 @Override                 public void onCompletion(MediaPlayer mediaPlayer) {                     cleanup();                 }             });         }         try {             mMediaPlayer.setDataSource(this, soundUri);             mMediaPlayer.prepareAsync();         } catch (Exception e) {             cleanup();         }      }      private void stopSound() {         if (mMediaPlayer != null) {             mMediaPlayer.stop();             mMediaPlayer.release();             mMediaPlayer = null;         }         cleanup();     }      private void cleanup() {         stopSelf();     }  } 

Recommendations

  • Create your notification channel with IMPORTANCE_DEFAULT (for the user this is 'High'), a null sound (setSound(null,null)) and a null vibration (setVibrationPattern(null)) and explain in the channel description that this is the recommended setting in order to avoid conflicts with the app's own customization.
  • Turn the whole thing into your favor: instead of removing a feature, give users a new one. You can give them the chance to use your customization features or the notification channel features (for example, you can check the current channel importance and depending on the level you can use one thing or the other).

Foreground notification

Starting Android O, services started from the background must be started as foreground services. This means SoundService needs a foreground notification. You have some options for this:

  • Create a nice foreground notification with a button that says 'Stop playback' so that the user can stop the sound without removing the notification that started it.

  • Create a simple notification and send it to a disabled channel (you can create disabled channels if you create them with IMPORTANCE_NONE). Doing this, the default system 'App is running in the background' notification will appear instead of your foreground notification, but users can hide this notification from the status bar if they want.

EDIT: in Android 8.1 it seems that creating a disabled channel with IMPORTANCE_NONE is not useful, as the channel will be enabled automatically when you send a notification. It may be better to create it with IMPORTANCE_LOW from the beginning and let users change the importance if they want.

like image 182
jmart Avatar answered Oct 24 '22 19:10

jmart


Might help in your case. If you have one notification displayed you can disable sound when updating this notification by setting .setOnlyAlertOnce(true). This solution works only when updating notification.

like image 23
Jacek Marchwicki Avatar answered Oct 24 '22 18:10

Jacek Marchwicki