Cordova-plugin-local-notifications: Cannot mute sound or vibration on Android 8.x

Created on 15 Aug 2018  路  32Comments  路  Source: katzer/cordova-plugin-local-notifications

WARNING: IF YOU IGNORE THIS TEMPLATE, WE'LL IGNORE YOUR ISSUE. YOU MUST FILL THIS IN!

Provide a general summary of the issue.

Your Environment

  • Plugin version: 0.9.0-beta.2 and HEAD
  • Platform: Android
  • OS version: 8.0.0
  • Device manufacturer / model: Samsung Galaxy S7
  • Cordova version (cordova -v): 8.0.0
  • Cordova platform version (cordova platform ls): android 7.0.0
  • Plugin config
  • Ionic Version (if using Ionic)

Expected Behavior

_Tell us what should happen_

A notification like this is scheduled:

cordova.plugins.notification.local.schedule({
  id: 
  title: 'Testing 
  text: 'Vibrate set to false, sound set to false, priority set to 
  vibrate: false,
  sound: false,
  priority: -2  // NotificationCompat.PRIORITY_MIN
});

When fired, this notification should show up in the tray, but no sound or vibration is played.

Actual Behavior

_Tell us what happens instead_
If the system notification sound level is not mute/vibrate, the phone plays the default notification sound when the notification appears.

If the system notification sound level is vibrate, the phone vibrates when the notification appears.

Steps to Reproduce

_Reproduce this issue; include code to reproduce, if relevant_

Schedule a notification with vibrate=false, sound=false, priority=-2

cordova.plugins.notification.local.schedule({
    id: 0,
    title: 'Testing notification',
    text: 'Vibrate set to false, sound set to false, priority set to min',
    vibrate: false,
    sound: false,
    priority: -2
});

I have a minimal example in this repository, it's just the hello world app that fires on deviceready: https://github.com/eric-zeng/no-vibrate

Context

_What were you trying to do?_

I'm trying to show notifications that show up silently without disturbing the user. It should make no sound or vibration.

Debug logs

_Include iOS / Android logs_

  • ios XCode logs
  • Android: $ adb logcat
08-14 15:12:24.629  1403  1403 I CordovaActivity: Apache Cordova native platform version 7.0.0 is starting
08-14 15:12:24.629  1403  1403 D CordovaActivity: CordovaActivity.onCreate()
08-14 15:12:25.368  1403  1403 D CordovaWebViewImpl: >>> loadUrl(file:///android_asset/www/index.html)
08-14 15:12:25.423  1403  1403 D CordovaActivity: Started the activity.
08-14 15:12:25.437  1403  1403 D CordovaActivity: Resumed the activity.
08-14 15:12:25.516  1403  1403 D CordovaWebViewImpl: onPageDidNavigate(file:///android_asset/www/index.html)
08-14 15:12:26.365  1403  1403 D CordovaWebViewImpl: onPageFinished(file:///android_asset/www/index.html)
08-14 15:12:26.655  1403  1530 D local-notification: Next trigger at: Tue Aug 14 15:12:26 PDT 2018
08-14 15:12:26.695  1403  1530 W Notification: Use of stream types is deprecated for operations other than volume control
08-14 15:12:26.695  1403  1530 W Notification: See the documentation of setSound() for what to use instead with android.media.AudioAttributes to qualify your playback use case
08-14 15:12:26.701  1403  1530 D Notification: allPendingIntents
08-14 15:12:26.746  3986  5457 D Notification: allPendingIntents
08-14 15:12:26.747  3986  5371 D Notification: allPendingIntents
08-14 15:12:26.748  3986  5371 D Notification: allPendingIntents
08-14 15:12:26.750  3986  5457 D Notification: allPendingIntents
08-14 15:12:26.754  3986  5457 D Notification: allPendingIntents
08-14 15:12:26.757  3986  5371 D Notification: allPendingIntents
08-14 15:12:26.761  1403  1403 D CordovaWebViewImpl: >>> loadUrl(javascript:cordova.plugins.notification.local.fireEvent("trigger",{"id":0,"title":"Testing notification","text":"Vibrate set to false, sound set to false, priority set to min","vibrate":false,"sound":false,"priority":-2,"actions":[],"attachments":[],"autoClear":true,"clock":true,"defaults":0,"groupSummary":false,"launch":true,"led":true,"lockscreen":true,"number":0,"progressBar":{"enabled":false,"value":0,"maxValue":100,"indeterminate":false},"silent":false,"smallIcon":"res:\/\/icon","timeoutAfter":false,"trigger":{"type":"calendar"},"wakeup":true,"meta":{"plugin":"cordova-plugin-local-notification","version":"0.9-beta.3"}},{"event":"trigger","foreground":true,"queued":false,"notification":0}))
08-14 15:12:26.766  3986  5457 D Notification: allPendingIntents
08-14 15:12:26.775  1403  1403 D CordovaWebViewImpl: >>> loadUrl(javascript:cordova.plugins.notification.local.fireEvent("add",{"id":0,"title":"Testing notification","text":"Vibrate set to false, sound set to false, priority set to min","vibrate":false,"sound":false,"priority":-2,"actions":[],"attachments":[],"autoClear":true,"clock":true,"defaults":0,"groupSummary":false,"launch":true,"led":true,"lockscreen":true,"number":0,"progressBar":{"enabled":false,"value":0,"maxValue":100,"indeterminate":false},"silent":false,"smallIcon":"res:\/\/icon","timeoutAfter":false,"trigger":{"type":"calendar"},"wakeup":true,"meta":{"plugin":"cordova-plugin-local-notification","version":"0.9-beta.3"}},{"event":"add","foreground":true,"queued":false,"notification":0}))
08-14 15:12:35.703  5346  5346 D Notification: allPendingIntents
08-14 15:12:35.723  3986  5371 D Notification: allPendingIntents
08-14 15:12:35.724  3986  5371 D Notification: allPendingIntents
08-14 15:12:35.724  3986  5457 D Notification: allPendingIntents
08-14 15:12:35.725  3986  7209 D Notification: allPendingIntents
08-14 15:12:35.726  3986  5457 D Notification: allPendingIntents
08-14 15:12:35.726  3986  5371 D Notification: allPendingIntents
08-14 15:12:35.727  3986  6719 D Notification: allPendingIntents

Most helpful comment

I am using Android 8 and vibration is present too !

All 32 comments

I also reproduced this issue on a Nexus 5X, Android 8.1.0. Do the vibrate and sound properties not work at all on Android 8+?

I figured out what's going on, turns out that this plugin only sends notifications to a single notification channel, which has the default notification importance level. In Android 8+, you can't adjust things like sound and vibration per-notification, it is set by the importance for the whole channel. So none of the options set in the JavaScript side do anything.

The right way to do this in the plugin would be to have an API that allowed you to create channels and set the importance level. I didn't have enough cycles to implement this, so I hardcoded another channel into the plugin with a lower importance level, and send the notifications that I wanted as quiet to that channel.

If it's helpful to anyone, you can see what I did in my fork:
https://github.com/eric-zeng/cordova-plugin-local-notifications/commit/24c92f3b2546aae353ad51ac362c8d4a6e28a8bd

Get the working code from here

@Steffaan - the above link suggested by you does NOT contain compiling plugin.
Here is the error log during application compilation:

:app:compileDebugJavaWithJavac
.\frontend\platforms\android\app\src\main\java\de\appplant\cordova\plugin\notification\Manager.java:49: error: cannot find symbol
import static de.appplant.cordova.plugin.notification.Options;
                                        ^
  symbol:   class notification
  location: package de.appplant.cordova.plugin
.\frontend\platforms\android\app\src\main\java\de\appplant\cordova\plugin\notification\Manager.java:49: error: static import only from classes and interfaces
import static de.appplant.cordova.plugin.notification.Options;
^
.\frontend\platforms\android\app\src\main\java\de\appplant\cordova\plugin\notification\Manager.java:126: error: isWithoutLights() has private access in Options
                if(!options.isWithoutLights()) channel.enableLights(true);
                           ^
.\frontend\platforms\android\app\src\main\java\de\appplant\cordova\plugin\notification\Manager.java:127: error: isWithVibration() has private access in Options
                channel.enableVibration(options.isWithVibration());
                                               ^
.\frontend\platforms\android\app\src\main\java\de\appplant\cordova\plugin\notification\Manager.java:129: error: isWithoutSound() has private access in Options
        if(options.isWithoutSound()) {
                  ^
.\frontend\platforms\android\app\src\main\java\de\appplant\cordova\plugin\notification\Manager.java:132: error: method setSound in class NotificationChannel cannot be applied to given types;
                        channel.setSound(options.getSound());
                               ^
  required: Uri,AudioAttributes
  found: Uri
  reason: actual and formal argument lists differ in length
.\frontend\platforms\android\app\src\main\java\de\appplant\cordova\plugin\localnotification\TriggerReceiver.java:75: error: createDefaultChannel(Options) has private access in Manager
                manager.createDefaultChannel(options);
                       ^
Note: Some input files use or override a deprecated API. FAILED
33 actionable tasks: 33 executed

Note: Recompile with -Xlint:deprecation for details.
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
7 errors

FAILURE: Build failed with an exception.

@angel1st my apologies, try again now..

@Steffaan - something is still wrong on this plugin fork. Let me give you the steps, I did and the output I have received:

  1. Remove cordova-plugin-local-notification, so I can fetch yours:

cordova plugin rm cordova-plugin-local-notification

  1. Try to add your plugin
    cordova plugin add https://github.com/Steffaan/cordova-plugin-local-notifications.git
    the above gives me an error:
Error during processing of action! Attempting to revert...
Failed to install 'cordova-plugin-local-notification': CordovaError: Uh oh!
".\frontend\platforms\android\app\src\main\res\xml\localnotification_provider_paths.xml" already exists!
    at copyNewFile (.\frontend\platforms\android\cordova\lib\pluginHandlers.js:261:45)
    at install (.\frontend\platforms\android\cordova\lib\pluginHandlers.js:51:17)
    at ActionStack.process (.\frontend\platforms\android\cordova\node_modules\cordova-common\src\ActionStack.js:56:25)
    at PluginManager.doOperation (.\frontend\platforms\android\cordova\node_modules\cordova-common\src\PluginManager.js:114:20)
    at PluginManager.addPlugin (.\frontend\platforms\android\cordova\node_modules\cordova-common\src\PluginManager.js:144:17)
    at .\frontend\platforms\android\cordova\Api.js:247:74
    at _fulfilled (.\frontend\platforms\android\cordova\node_modules\q\q.js:854:54)
    at .\frontend\platforms\android\cordova\node_modules\q\q.js:883:30
    at Promise.promise.promiseDispatch (.\frontend\platforms\android\cordova\node_modules\q\q.js:816:13)
    at .\frontend\platforms\android\cordova\node_modules\q\q.js:570:49
  1. Then, I decide to remove both android and ios platforms, add the plugin and then add the platforms, so I did:
    > cordova platform rm android
    > cordova platform rm ios
    > cordova plugin add https://github.com/Steffaan/cordova-plugin-local-notifications.git
    then, I have got a new error:
(node:32712) UnhandledPromiseRejectionWarning: CordovaError: Failed to fetch plugin https://github.com/Steffaan/cordova-plugin-local-notifications.git via registry.
Probably this is either a connection problem, or plugin spec is incorrect.
Check your connection and plugin name/version/URL.
Failed to get absolute path to installed module
    at .\AppData\Roaming\npm\node_modules\cordova\node_modules\cordova-lib\src\plugman\fetch.js:173:37
    at _rejected (.\AppData\Roaming\npm\node_modules\cordova\node_modules\q\q.js:864:24)
    at .\AppData\Roaming\npm\node_modules\cordova\node_modules\q\q.js:890:30
    at Promise.when (.\AppData\Roaming\npm\node_modules\cordova\node_modules\q\q.js:1142:31)
    at Promise.promise.promiseDispatch (.\AppData\Roaming\npm\node_modules\cordova\node_modules\q\q.js:808:41)
    at .\AppData\Roaming\npm\node_modules\cordova\node_modules\q\q.js:624:44
    at runSingle (.\AppData\Roaming\npm\node_modules\cordova\node_modules\q\q.js:137:13)
    at flush (.\AppData\Roaming\npm\node_modules\cordova\node_modules\q\q.js:125:13)
    at process._tickCallback (internal/process/next_tick.js:61:11)
(node:32712) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:32712) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

The bottom line - the fork still does not work.
My (wild) guess is - you have to adjust both package.json and/or plugin.xml file, otherwise it won't work.

@angel1st

Hello, your first issue is not a problem within the fork, same thing happens in the master version of katzer. The xml file is not deleted after removing the plugin.

I don't have the issue fetching the plugin, are you sure everything is setup correctly on your environment?

Try cordova plugin add https://github.com/Steffaan/cordova-plugin-local-notifications

image

@Steffaan - ok, I have deleted local-notification.xml file from .\platforms\android\app\src\main\res\xml,
then, I have got following:

cordova plugin add https://github.com/Steffaan/cordova-plugin-local-notifications
(node:21048) UnhandledPromiseRejectionWarning: CordovaError: Failed to fetch plugin https://github.com/Steffaan/cordova-plugin-local-notifications via registry.
Probably this is either a connection problem, or plugin spec is incorrect.
Check your connection and plugin name/version/URL.

... please note Probably this is either a connection problem, or plugin spec is incorrect and I am pretty sure, I have no connection problems, since I am able to fetch any other plugin from registry. On the other hand, your both package.json and plugin.xml files contain urls and ids from the original plugin, this is why was my guess.
Anyway - I can confirm, I cannot add your plugin.

@angel1st try the --nofetch parameter, I'm guessing your cordova version is different.

cordova plugin add https://github.com/Steffaan/cordova-plugin-local-notifications --nofetch

Thanks, @Steffaan - I finally managed to install your version. Now, however, I have another question :-)
My initial intention was to schedule notification with vibration and LED blink. For the purpose, this is how I prepare the plugin, right after deviceready is fired:

window.cordova.plugins.notification.local.setDefaults({
    vibrate: true,
    foreground: false,
    led: { color: '#FF00FF', on: 500, off: 500 }
});

then, when the notification is required, I just schedule it like that:

window.cordova.plugins.notification.local.schedule({
     title: placeStrTitle,
     text: placeStr
});

All tests are done on Samsung S8 / Android 8.0.0
As a result - I have the notification, but neither phone vibrates nor LED flashes. So basically, what I have got as an end result is essentially the same, I have got with katzet plugin version... any idea, why this one happens? Just to clarify - I can confirm, I have permission (hasPermission returns true).
I guess if you can share some sample code, which is confirmed as working on your end will be in great help...
One additional question - did you know / find any documentation on the plugin - it has a lot of properties, but none of these are properly explained into the readme file...

@angel1st You would be better of by using the fork I made, I will update and maintain it since we use the plugin for our own apps too.

But the problem with the katzer version is that Android 8 uses notification channels, where all functions need to be enabled before you can use them. That's why your properties are not even used, even when you declare them.

What I did in the fork is setting the channel to HIGH_PRIORITY, this method prevents the app from ignoring the notifications when in Doze mode.

The changes needed to make the vibration and sound work again, is to pass the paramters to the channel before sending out notifications.

channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, IMPORTANCE_HIGH);
  if(!options.isSilent()) channel.setBypassDnd(true);
  if(!options.isWithoutLights()) channel.enableLights(true);
  channel.enableVibration(options.isWithVibration());
  channel.setLightColor(options.getLedColor());
  if(options.isWithoutSound()) {
      channel.setSound(null, null);
  } else {
      channel.setSound(options.getSound(), null);
  }

With the changes shown in the code above, you'll be able to make the notification silent, enable / disable vibration, enable / disable LED, all of those options which stopped working with Android 8.

To use the changes I recommend you to trigger notifications with all properties included. This is an example of our integration (I put some comments in the code for you):

cordova.plugins.notification.local.schedule({
      id: 1,
      title: 'Title of your notification',
      text: 'Text of your notification',
      sticky: true, // Only use this is you want your notification to be sticky / ongoing!
      lockscreen: true, // Only use this if you want the notification to be shown in lockscreen!
      foreground: true, // Only use this if you want to show the notification when app is in foreground
      priority: 2, // High priority
      actions: [
            { id: 'acceptPush', title: 'Accept' }, // Example for an action button
            { id: 'denyPush', title: 'Deny' } // Example for an action button
      ]
});

I also fixed /added the issue https://github.com/katzer/cordova-plugin-local-notifications/issues/1671 in my fork.

If you have any questions about the properties just let me know and I can explain them.

Good luck and I hope this helps you out :)

@Steffaan - thanks again for the feedback, mate!
Looking at the above code snippets you posted, I have few questions:

  1. I assume, the first code snippet has to be inside my app, hasn't it?
  2. Where does options come from into your channel setup (first snippet)?
  3. Into the second code snippet (the actual notification schedule), I don't see channel to be passed as a parameter what so ever - hence, I cannot see the relation between the channel setup and the notification scheduled.

@Steffaan , First of all i would like to thank you for your pointers, totally saved a lot of time.

I am facing the same problem with @angel1st , i have done as you have instructed in your example, plus adding sound,led & vibration values to true yet the notifications are still without sound,led and vibration.

I also tested this on an s8, maybe the culprit here is the phone? I will try in the next days to test this in more 8+ devices.

Guys, I have one other case re local notification. Here is the scenario - While app is running, I am receiving local notification and it stays on the notification area. Now, if I click on the notification, while the app is running (either in front or background mode), it will trigger click event, so I can handle this notification according to app logic. Then, I close the app. The notification is still on the notification area. So far so good.
Now, if I open notification drawer and click on the notification, it will load the app, however, I don't see any local-notification event being fired, hence I am not able to handle a specific notification type according to app logic.
Any thoughts how this might be done?

Hi @Steffaan
Android 8.1. I created empty project, added your plugin, then added platform android 7.1, used the code from your snippet, but in result: no sound, but vibration is present. Then I changed code and explisitly set sound to true and vibrate to false, result is the same: no sound, but vibration is present.
In my working project with any values set to "sound" and "vibrate" - sound is always enabled and vibrating is not.
I think, maybe for empty project, application can't run default sound and vibrating instead...

Here is a snippet for notification in empty project:

cordova.plugins.notification.local.schedule({
            id: 1,
            title: 'Title of your notification',
            text: 'Text of your notification',
            lockscreen: true, // Only use this if you want the notification to be shown in lockscreen!
            foreground: true, // Only use this if you want to show the notification when app is in foreground
            priority: 2, // High priority
            actions: [
                { id: 'acceptPush', title: 'Accept' }, // Example for an action button
                { id: 'denyPush', title: 'Deny' } // Example for an action button
            ],
            sound: true,
            vibrate: false,
        });

I am using Android 8 and vibration is present too !

@hordesalik @klochko7

Just to be sure, your phone isn't on silent mode is it?

If it is that could be the reason that your not hearing the default sound and get a vibration instead.

Either way I'll check it out myself and will fix the issue if necessary 馃憤

Sure, it is not in silent mode. I tested in 2 different apps like I described above... So I heard sound in another one

I have the same issue ! I am using Samsung Galaxy android 8 and cannot mute sound or vibration.

@klochko7, have you tried Steffaan's fork? The problem you described is the original issue. Please look at the link to the fork few comments above

@hordesalik

Found it, the channel always called options.getSound(), so that's always a null value in case of sound: true. Changed it to use the default sound in case the sound property is set to true.

Just tested the changes in an empty cordova app and works like it should.

Get the latest version from https://github.com/Steffaan/cordova-plugin-local-notifications and let me know if it fixes the issue for you.

Steffaan, I am using such code... but cannot mute vibration on android 8.

        win.cordova.plugins.notification.local.schedule({
          id: 1,
          title: 'Downloading',
          progressBar:{ value: 0 },
          vibrate: false,
          sound: false
        });

@klochko7

Seems to be a bug in the Android 8 notification system.

Fixed now, get the latest version & make sure to uninstall your app first or reboot your phone for the changes to take effect.

Steffaan, good day ! I install latest version and if I sound off on my phone vibration is on, if switch sound on vibration is off. Is it normal ?

@klochko7 that's just normal behaviour of a mobile device. Most of them vibrate when the phone is in silent mode. But if your using the code snippet from your previous comment, it shouldn't play any sound or vibrate at all..

If it still vibrates, then you might want to check out if you actually run the latest version of my fork.

If your sure that your running the latest version, you might want to uninstall your app before installing the new version (as I mentioned in my previous comment)

issue created in fork repository

Steffaan, Yes, I am using the code snippet from my previous comment. I downloaded latest zip file and unzip it in my project folder. Vibrate play.

@Steffaan Thanks for your version. I'm having trouble with the Channels on Android 8+ as well. The Katzer version was only playing devices' default sound every time. I just tried your version and now I can get it to have no sound, but I want one notification to have custom sound and vibration. Do I need to set priority in the notification settings, so that it goes to High Priority? or something else? Thank you!

@Steffaan Nevermind, I think I have your code working now. I did not have a channel and priority set correctly for my notifications. It appears to be mostly working on Android 8, although vibrate is not working consistently for me.

Also not working in Android Pie.
@katzer can you tell us, it will be fixed or not?

Was this page helpful?
0 / 5 - 0 ratings