One of the features most wished for in one of my Cordova-based android apps was to let the users choose another sound for push notifications, or to disable sound altogether (without having to mute the whole smart phone and still keeping vibration). The Push Plugin supports custom sounds, however all sound resources have to be embedded in the app. In my case, I wanted to let the users choose among the system sounds provided by Android itself, which apparently isn’t possible without some major changes to the plugin.
Here, I’m going to outline the changes necessary to integrate Android’s native RingtonePreference dialog into a Cordova-based app to let the users choose another notification sound. I’ve published the modified plugin that should work on android projects on Github.
Configuration Dialog
Choosing the preferences for push notifications is done in a native android PreferenceScreen that is opened from within the app using a new javascript-method on the pushNotification-Object. The configuration screen is defined by a xml file stored at platforms/android/res/xml/pushsettings.xml:
The referenced strings are stored in platforms/android/res/values/strings-gcm.xml:
Notifications Light Light is switched on Light is switched off Vibration Vibration is switched on Vibration is switched off Sound Sound is switched on Sound is switched off Ring tone Choose a ring tone
Translated versions can be stored in files like platforms/android/res/values-de/strings-gcm.xml
Opening the dialog
First of all, a new activity has to be defined in the platforms/android/AndroidManifest.xml:
The Activity itself is pretty simple, just remember to replace the „CORDOVA_PACKAGE_ID“ by the id of your app (necessary to access the R.xml.pushsettings-resource):
package com.plugin.gcm; import CORDOVA_PACKAGE_ID.R; import android.os.Bundle; import android.preference.PreferenceActivity; public class PushSettingsActivity extends PreferenceActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.pushsettings); } }
This activity is called from PushPlugin.java’s execute-method, something like:
if ('showPushSettings'.equals(action)) { Intent i = new Intent(this.cordova.getActivity(), PushSettingsActivity.class); this.cordova.getActivity().startActivityForResult(i, RESULT_PUSH_SETTINGS); callbackContext.success(); }
The JavaScript-method to call this in PushNotification.js is:
PushNotification.prototype.showPushSettings = function (successCallback, errorCallback) { if (errorCallback == null) { errorCallback = function () {} } if (successCallback == null) { successCallback = function () {} } if (typeof errorCallback != "function") { console.log("PushNotification.showPushSettings failure: failure parameter not a function"); return; } if (typeof successCallback != "function") { console.log("PushNotification.showPushSettings failure: success callback parameter must be a function"); return; } cordova.exec(successCallback, errorCallback, "PushPlugin", "showPushSettings", []); };
With all these changes applied, a call to plugins.pushNotification.showPushSettings() should open the configuration dialog and let the user apply her desired notification sound. The settings are stored automatically in android’s SharedPreferences. In the source code of the plugin, I also added a getPushSettings()-method that returns the settings into JavaScript, if you ever need to query these settings.
Using the settings for the notification
The actual notification sound is triggered in GCMIntentService.java’s onMessage-method. The new code reads the settings from the SharedPreferences and acts accordingly:
SharedPreferences app_preferences = PreferenceManager.getDefaultSharedPreferences(this); boolean vibration = app_preferences.getBoolean("com.plugin.gcm.vibration", true); boolean sound = app_preferences.getBoolean("com.plugin.gcm.sound", true); boolean light = app_preferences.getBoolean("com.plugin.gcm.light", true); String ringtonePath = app_preferences.getString("com.plugin.gcm.ringtone", "defValue"); int defaults = 0; if (vibration) defaults = defaults | Notification.DEFAULT_VIBRATE; if (light) defaults = defaults | Notification.DEFAULT_LIGHTS; NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context) .setDefaults(defaults) .setSmallIcon(context.getApplicationInfo().icon) .setWhen(System.currentTimeMillis()) .setContentTitle(extras.getString("title")) .setTicker(extras.getString("title")) .setContentIntent(contentIntent) .setAutoCancel(true); if (!ringtonePath.equals("") && sound) { Uri uri = Uri.parse(ringtonePath); Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), uri); r.play(); mBuilder.setSound(null); }
I’m using the Ringtone.play() instead of the setSound()-method of NotificationCompat.Builder, as the latter one somehow didn’t actually change the sound, even with the URL of the sound provided. I haven’t yet figured out why, but there probably is a solution that’s more elegant than the one showed above.
That’s it. Have fun! 🙂
Hi ho,
do you know if there is a way to make this work with ionic framework and the cordova plugins without native approach?
regards,
Chiny1
Hello!
Is there anyway I could use this on PhoneGap Build? Thanks in advance for your answer. 🙂