39

In my hybrid Cordova Android app targeting API 23+ I want to use a custom sound for notifications. To that end I have done the following

  • In plugin.xml file for the single custom plugin I use in the app I declare <resource-file src="src/android/res/unysound.mp3" target="res/raw/mysound.mp3" />'.

Opening the APK as a zip archive I see that the mp3 file has in fact ended up in `res/raw/mysound.mp3'. - When building the notification I do the following

    Notification notification = new Notification.Builder(context)
    .setDefaults(0) //turns off ALL defaults
    .setVibrate(vibrate)  /sets to vibrate
    ....
    .setSound(uri).build();

where

Uri uri = Uri.parse("android.resource://" + ctxt.getPackageName() + "/raw/mysound.mp3");

This appears to be the recipe indicated in a number of articles I find on a spot of googling and even in other threads on SO. And yet, when I issue a notification I do not hear the expected sound. What might I be doing wrong?


The answer below does not help since in the context of my hybrid Cordova app with a custom plugin attempting to build the APK throws up an error along the lines of class R not known/found...

DroidOS
  • 8,530
  • 16
  • 99
  • 171

8 Answers8

55

below code will help you:

 String CHANNEL_ID="1234";

    Uri soundUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://"+ getApplicationContext().getPackageName() + "/" + R.raw.mysound);
    NotificationManager mNotificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE); 
    
  //For API 26+ you need to put some additional code like below:
    NotificationChannel mChannel;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                mChannel = new NotificationChannel(CHANNEL_ID, Utils.CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
                mChannel.setLightColor(Color.GRAY);
                mChannel.enableLights(true);
                mChannel.setDescription(Utils.CHANNEL_SIREN_DESCRIPTION);
                AudioAttributes audioAttributes = new AudioAttributes.Builder()
                        .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                        .setUsage(AudioAttributes.USAGE_NOTIFICATION)
                        .build();
                mChannel.setSound(soundUri, audioAttributes);
    
                if (mNotificationManager != null) {
                    mNotificationManager.createNotificationChannel( mChannel );
                }
        }

   //General code:
     NotificationCompat.Builder status = new NotificationCompat.Builder(getApplicationContext(),CHANNEL_ID);     
                          status.setAutoCancel(true)
                                .setWhen(System.currentTimeMillis())
                                .setSmallIcon(R.drawable.logo)
                                //.setOnlyAlertOnce(true)
                                .setContentTitle(getString(R.string.app_name))
                                .setContentText(messageBody)
                                .setVibrate(new long[]{0, 500, 1000})
                                .setDefaults(Notification.DEFAULT_LIGHTS )
                                .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE+ "://" +mContext.getPackageName()+"/"+R.raw.apple_ring))
                                .setContentIntent(pendingIntent)
                                .setContent(views);
                        
                        mNotificationManager.notify(major_id, status.build());

where mysound is my ringtone which is put under res/raw folder.

Note: you have to only put name of ringtone without extension like raw/mysound

Note: In Android Oreo you must change your channel ID to changes take effect. And before Oreo version, using ".setDefaults()" seens prevent custom sound to play.

Ketan Patel
  • 2,155
  • 19
  • 27
  • 1
    I am accepting your answer because it came closest to identifying the underlying issue - it is the extension `mp3` that was causing the problem. Without the extension my original code delivers the desired result. Note that in a Cordova app `R.java` is not recognized so what you have shown above is not truly applicable. – DroidOS Mar 06 '18 at 14:34
  • Why would you call `setDefaults` twice? – Jannie Theunissen Sep 13 '18 at 13:36
  • 2
    I couldn't find `CONTENT_TYPE_NOTIFICATION` in `AudioAttributes` so I've omit that and the solution still works. – Karzel Apr 03 '19 at 06:35
  • 4
    In Android Oreo you must change your channel ID to changes take effect. And before Oreo version, using ".setDefaults()" seens prevent custom sound to play. – ThiagoYou Jul 01 '19 at 16:31
  • @ThiagoYou this is must. I spent one day just to rectify this issue. – Arth Tilva Jul 03 '19 at 10:48
  • I;ve used setSound() on my notification channel and passed in the sound Uri and the audioAttribute but still no sound. I have uninstalled and installed the app multiple times and yet no way forward. – nelsola Sep 10 '20 at 07:05
  • 1
    Please add @ThiagoYou comment to your answer as a note. it saved me a lot of time. – MehranB Aug 14 '21 at 15:19
  • i saw extension issue problem after 2 hours trying :'( – gturedi Mar 02 '22 at 12:09
34
  1. Try clearing data (or fresh install)
  2. Trying this again

The settings are set the first time you create the channel and then not modified unless you do it manually by fresh install or clearing data.

For more info on this read the top answer here: Android Oreo notification keep making Sound even if I do not set sound. On Older version, works perfectly

  • 4
    I was getting frustrated that whatever sound or vibration settings I add to `NotificationCompat.Builder` or `NotificationChannel` it make no difference, until I cleared the app data and suddenly it worked. Thanks, your answer saved my day. – razz Feb 14 '20 at 20:59
  • 2
    I spent hours trying to figure out why nothing is changing you saved my day, thank you – Zakaria M. Jawas May 04 '20 at 12:30
  • How to solve this issue, i had set vibration as a user preference so based on that user will change, but it works only for the fresh install – livemaker Aug 17 '20 at 07:08
22

For API 26+ you need to set the sound on the notification channel:

Uri soundUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://"+ getApplicationContext().getPackageName() + "/" + R.raw.siren);
NotificationManager mNotificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
    NotificationChannel mChannel;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            mChannel = new NotificationChannel(Utils.CHANNEL_SIREN_ID, Utils.CHANNEL_SIREN_NAME, NotificationManager.IMPORTANCE_HIGH);
            mChannel.setLightColor(Color.GRAY);
            mChannel.enableLights(true);
            mChannel.setDescription(Utils.CHANNEL_SIREN_DESCRIPTION);
            AudioAttributes audioAttributes = new AudioAttributes.Builder()
                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                    .setUsage(AudioAttributes.USAGE_NOTIFICATION)
                    .build();
            mChannel.setSound(soundUri, audioAttributes);

            if (mNotificationManager != null) {
                mNotificationManager.createNotificationChannel( mChannel );
            }
    }

    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, Utils.CHANNEL_SIREN_ID)
            .setSmallIcon(R.drawable.ic_stat_maps_local_library)
            .setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), R.mipmap.ic_launcher))
            .setTicker(title)
            .setContentTitle(contentTitle)
            .setContentText(contentText)
            .setAutoCancel(true)
            .setLights(0xff0000ff, 300, 1000) // blue color
            .setWhen(System.currentTimeMillis())
            .setPriority(NotificationCompat.PRIORITY_DEFAULT);

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            mBuilder.setSound(soundUri);
    }

    int NOTIFICATION_ID = 1; // Causes to update the same notification over and over again.
    if (mNotificationManager != null) {
        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
    }
Dimitar Darazhanski
  • 2,188
  • 20
  • 22
  • 1
    ```mChannel.setSound(soundUri, audioAttributes);``` is what made the sound work in Oreo – 2mia Oct 17 '18 at 14:54
  • 3
    Thanks for this, This is not great, cause what if we want different sounds for different notifications within a channel. – Zapnologica Oct 29 '18 at 16:47
14

you can call this method while handling notification

    public void playNotificationSound() {
    try {
        Uri alarmSound = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE
                + "://" + mContext.getPackageName() + "/raw/notification");
        Ringtone r = RingtoneManager.getRingtone(mContext, alarmSound);
        r.play();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
Uma Achanta
  • 3,669
  • 4
  • 22
  • 49
  • 3
    An upvote here because I suspect that using `ContentResolver` as opposed to `android.resource://` is a more future proof way of doing things. – DroidOS Mar 06 '18 at 14:36
  • 1
    What you are doing here - via RingToneManager - works but it is not right and should not have to be done given that Notification.Builder has its own method to `setSound` – DroidOS Mar 07 '18 at 13:24
  • 10
    Yea there are a lot of things in Android that should not have to be done, I have learned over the past 4 years, don't assume anything works properly or is done already for you in Android until you see it with your own eyes...FYI – JamisonMan111 Aug 27 '18 at 01:50
  • The only method that worked for me. – FreddicMatters Nov 24 '21 at 20:30
5
 Notification.Builder builder = new Notification.Builder(context);
    builder.setContentTitle(mTitle);
    builder.setContentText(mContentText);
    builder.setSmallIcon(R.mipmap.ic_launcher);

    builder.setSound(Settings.System.DEFAULT_NOTIFICATION_URI);
    builder.setVibrate(new long[] { 1000, 1000, 1000, 1000, 1000 });
    builder.setDefaults(Notification.DEFAULT_ALL);

Use this to work with sound, I hope it will solve your problem, Cheers!

Aleesha Kanwal
  • 187
  • 2
  • 9
1

Use this for setting sound

Uri defaultSoundUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + mContext.getPackageName() + "/raw/mysound");


NotificationCompat.Builder mBuilder =
                new NotificationCompat.Builder(mContext)
                        .setContentIntent(mainPIntent)
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setLargeIcon(BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.ic_launcher))
                        .setContentTitle("" + title)
                        .setAutoCancel(true)
                        .setSound(defaultSoundUri)
                        .setContentText("" + body);

        NotificationManager mNotificationManager =
                (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
        mNotificationManager.notify(title, NOTIFICATION_ID, mBuilder.build());
Ashish Pardhiye
  • 510
  • 4
  • 13
0

You are accessing the sound in a subfolder in the resources

change the source of your uri to

Uri uri = Uri.parse("android.resource://" + context.getPackageName() + "/" + R.raw.siren);

For the default sound, use:

notification.defaults |= Notification.DEFAULT_SOUND;
Lucem
  • 2,912
  • 3
  • 20
  • 33
  • The only problem is that when use `R.raw.mysound.mp3` I cannot get the app to compile - the error `R cannot be resolved to a variable`. Remember that I have a Cordova project with a custom plugin. I am putting the notification, setsound etc code in that plugin along with the sound resource in question – DroidOS Feb 26 '18 at 12:33
0

I am not sure but i think issue is that you are doing the wrong way "/raw/mysound.mp3 :

Uri uri = Uri.parse("android.resource://" + ctxt.getPackageName() + "/raw/mysound.mp3");

First add the permission in manifest : uses-permission android:name="android.permission.VIBRATE" /> then you can set the default sound like :-

Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
mBuilder.setSound(alarmSound);

and for vibration:

mBuilder.setVibrate(new long[] { 1000, 1000});

for custom sound, put mp3 file on this path:Res\raw\sound.mp3 and then

Notification notification = builder.build();
 notification.sound = Uri.parse("android.resource://"
        + context.getPackageName() + "/" + R.raw.sound);
aj0822ArpitJoshi
  • 1,142
  • 1
  • 9
  • 25