Is this a platform bug or some problem in my implementation? It appears to be regardless of importance level. Version of Android is 8.1.0. Target SDK is 22 (I am stuck on that unfortunately).
val defaultChannelId = AppConstants.NOTIFICATION_DEFAULT_ID
val defaultChannelName = "New Orders - high priority"
val defaultChannel = NotificationChannel(
defaultChannelId,
defaultChannelName,
NotificationManager.IMPORTANCE_HIGH
)
defaultChannel.setSound(defaultSound, attributes)
defaultChannel.description = "When a new order arrives"
val notificationManager = NotificationManagerCompat.from(this)
notificationManager.createNotificationChannel(defaultChannel)
On button click:
Notification appears:
val builder = NotificationCompat.Builder(requireContext(), AppConstants.NOTIFICATION_DEFAULT_ID).apply {
setContentTitle("New Order Received")
setContentText("Fetching order...$payload")
setSmallIcon(R.drawable.outline_receipt_white_24)
setSound(Uri.parse("android.resource://" + activity?.packageName + "/" + R.raw.notification_decorative))
setCategory(NotificationCompat.CATEGORY_STATUS)
priority = NotificationCompat.PRIORITY_HIGH
setProgress(0, 0, true)
}
val notificationManager = NotificationManagerCompat.from(requireContext())
notificationManager.notify(payload, builder.build())
Notification does not appear:
val builder = NotificationCompat.Builder(requireContext(), AppConstants.NOTIFICATION_DEFAULT_ID).apply {
setContentTitle("New Order Received")
setContentText("Fetching order...$payload")
setSound(Uri.parse("android.resource://" + activity?.packageName + "/" + R.raw.notification_decorative))
setCategory(NotificationCompat.CATEGORY_STATUS)
priority = NotificationCompat.PRIORITY_HIGH
setProgress(0, 0, true)
}
val notificationManager = NotificationManagerCompat.from(requireContext())
notificationManager.notify(payload, builder.build())
Is this a platform bug or some problem in my implementation?
Neither, assuming that you are implying that the bug is in Oreo. You were always supposed to supply a small icon to show in the status bar. There was a bug in older versions of Android whereby you could hack a Notification such that it would not show such an icon. Malware authors thought this was great, and Google eventually fixed it.
Related
I'm trying to add a style to my push notification (in this case, I add a bold "WARNING!" text). It works when my app received a notification in foreground condition, but it doesn't when in background. Do I miss something here ?
val body = "WARNING! $notifBody"
val bodyBold: Spannable = SpannableString(body)
bodyBold.setSpan(StyleSpan(Typeface.BOLD), 0, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
builder.setSmallIcon(R.drawable.ic_logo_home)
.setLargeIcon(
BitmapFactory.decodeResource(
this.resources,
R.drawable.ic_logo_home
)
)
.setContentIntent(pendingIntent)
.setStyle(NotificationCompat.BigTextStyle()
.setBigContentTitle(notifTitle)
.bigText(bodyBold))
.setDefaults(Notification.DEFAULT_VIBRATE)
builder.priority = NotificationCompat.PRIORITY_HIGH
notificationManager.notify(Random().nextInt(), builder.build())
I am struggling with this problem for a banch days and cannot find proper way to do it.
I would like to set default channel settings (like sound on, lights on, vibration, lock screen notification etc.)
When I create a channel (already tried with different channel id and different package names) I always get channel with only vibration on - rest of stuff is off.
I try to create channel with this code (changing importance value makes no change in new channels):
object DefaultNotificationChannel {
#RequiresApi(Build.VERSION_CODES.O)
fun createChannel(applicationContext: Context) {
val notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val sound = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + applicationContext.packageName + "/" + R.raw.notification)
createNotificationChannel(applicationContext, notificationManager, sound)
}
#TargetApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(applicationContext: Context, notificationManager: NotificationManager, sound: Uri) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = applicationContext.getString(R.string.notification_channel_name)
val id = applicationContext.getString(R.string.default_notification_channel_id)
val importance = NotificationManager.IMPORTANCE_HIGH
val channel = NotificationChannel(id, name, importance)
channel.enableLights(true)
channel.lightColor = Color.RED
channel.enableVibration(true)
val attributes = AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
.build()
channel.setSound(sound, attributes)
channel.enableVibration(true)
channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
notificationManager.createNotificationChannel(channel)
}
}
}
I know that once channel is created the app cannot change its settings - thats why I already have tried with different ids and pacakge names.
I also have tried with application example from (Google Codelabs Notification Channels and Badges) but with the same results.
I already noticed that in some others phones everythig is ok, with Importance.HIGHT - all of switch are turned on - but not on my device.
When I install apps like Whatsapp or Viber, they channels have all settings already on - so I guess it is possible to do automatically.
I know I can always add button to open channel settings in my app, but it will be better to do it automatically when channel is registered.
Thanks in advance! :)
i have a { N } app that should trigger notifications.
i'm using the notificationChannel but i keep getting the same error when the app crushed.
"System.err: TypeError: android.NotificationChannel is not a constructor"
my code is :
android.app.job.JobService.extend("com.tns.notifications.MyJobService", {
onStartJob: function(params) {
console.log("Job execution ...");
// Do something useful here, fetch data and show notification for example
var utils = require("utils/utils");
var context = utils.ad.getApplicationContext();
// var res=GeofenceService.mainFunction()
// console.log("res",res)
var builder = new android.app.Notification.Builder(context);
builder.setContentTitle("Scheduled Notification")
.setAutoCancel(true)
.setColor(android.R.color.holo_purple)//getResources().getColor(R.color.colorAccent))
.setContentText("This notification has been triggered by Notification Service")
.setVibrate([100, 200, 100])
.setSmallIcon(android.R.drawable.btn_star_big_on);
// will open main NativeScript activity when the notification is pressed
var mainIntent = new android.content.Intent(context, com.tns.NativeScriptActivity.class);
var mNotificationManager = context.getSystemService(android.content.Context.NOTIFICATION_SERVICE);
// The id of the channel.
const channelId = "my_channel_01";
// The user-visible name of the channel.
const name = "Channel name";
// The user-visible description of the channel.
const description = "Channel description";
const importance = android.app.NotificationManager.IMPORTANCE_LOW;
const mChannel = new android.app.NotificationChannel(channelId, name,importance);
// Configure the notification channel.
mChannel.setDescription(description);
mChannel.enableLights(true);
// Sets the notification light color for notifications posted to this
// channel, if the device supports this feature.
mChannel.setLightColor(android.graphics.Color.RED);
mChannel.enableVibration(true);
mNotificationManager.createNotificationChannel(mChannel);
builder.setChannelId(channelId);
mNotificationManager.notify(1, builder.build());
return false;
},
onStopJob: function() {
console.log("Stopping job ...");
}
});
the error coming from this row :
const mChannel = new android.app.NotificationChannel(channelId, name,importance);
why is he telling me that NotificationChannel is not a constructor?
what did i missed ?
this is where i got this code and it seems to work for other people.
https://github.com/NativeScript/sample-android-background-services
Edit:
i just checked my API Level and its 26 so even with the if statement before the channel line its crushing.
when im looking at my platforms folder in the android manifest i see this :
<uses-sdk
android:minSdkVersion="17"
android:targetSdkVersion="25"/>
why its 25 ?
android.app.NotificationChannel is available only on API Level 26 and above (Android 8.0 - Oreo). If you are using an earlier version, it will throw that error.
You must check the version before you access those apis, something like
if (android.os.Build.VERSION.SDK_INT >= 26) {
const mChannel = new android.app.NotificationChannel(channelId, name,importance);
}
Update:
You must set your target SDK to a higher version, at least 26. You will not be even able to upload your APK to Google Play if you are targeting a lower version since August 2018.
I am trying to play a custom sound on the Android platform when a local notification is being displayed, the code below is based on the Xamarin Local Notification Documentation, but some fields I'm being nagged are obsolete/deprecated.
In particular, SetSound 😢
I have however tried using SetSound in the hope that it could still work, even if deprecated. But I am not sure how to reference either the mp3 files in the Android / Xamarin 'Asset' folder or the copy that I have in Android / Xamarin 'Resources/raw' folder.
/Asset contents has build action AndroidAsset
/Resources/raw contents has build action AndroidResource
This line is what is causing me the headaches ...
.SetSound(Android.Net.Uri.Parse("android.resource://MyAssemblyName.Droid/Assets/filename"));
also tried
.SetSound(Android.Net.Uri.Parse("android.resource://MyAssemblyName.Resources/raw/filename"));
Q1) What do I need to do to correctly play a custom notification sound using either the Assets or Resources folder?
Q2) Because SetSound deprecated, what am I meant to do instead?
I have cheated, partially successfully, I have a Xamarin Plugin that plays sounds, which references the same files in the portable class library (PCL) and that mechanism works (when un-commented), but only if the app is in the foreground.
It seems that my scheduled local notifications do not trigger if I swipe to 'kill' the app, even though the app will not die because I have a persistent notification that prevents the app closing (until a certain time in the future that releases the persistent notification which could be minutes later).
Q3) Why don't the scheduled local notifications trigger once the user swipes the app, even though a persistent system notification keeps the app running? Here's how that persistent notification is set up. If it wasn't for this issue I could probably get by with the hack detailed above to play the sound from the PCL.
var activity = new Intent(Android.App.Application.Context, typeof(MainActivity));
var pIntent = PendingIntent.GetActivity(this, 0, activity, 0);
var notification = new Notification.Builder(this)
.SetContentTitle("Persistent Notification Test")
.SetContentText("This is always running to ensure that you are safe.")
.SetSmallIcon(Resource.Drawable.icon)
.SetOngoing(true)
.SetDefaults(0) // no sounds
.SetContentIntent(pIntent)
.Build();
// Enlist this instance of the service as a foreground service
StartForeground(SERVICE_RUNNING_NOTIFICATION_ID, notification);
For those interested, the commented out line
// PlatformDifferences.PlaySound(soundFilename, Logger);
calls through to this method that uses the SimpleAudioPlayer plugin
public virtual void PlaySound(string soundFilenameExcludingPath, Logger logger) {
var assembly = IntrospectionExtensions.GetTypeInfo(typeof(App)).Assembly;
Stream audioStream = assembly.GetManifestResourceStream("<my-pcl-assembly-name>.Sounds." + soundFilenameExcludingPath);
if (audioStream != null)
{
logger.Log(this, "playing sound:" + soundFilenameExcludingPath);
var player = Plugin.SimpleAudioPlayer.CrossSimpleAudioPlayer.Current;
player.Load(audioStream);
player.Play();
}
else
{
logger.Log(this, "failed - playing sound:" + soundFilenameExcludingPath);
}
}
Here's a screenshot that shows my project structure
And here's the method that I invoke whenever I want to display a notification, whether because I wanted a scheduled local notification, or because I've received a push notification and wish to show the details to the user.
private async Task DisplayLocalNotification(String title, String message, String soundFilename)
{
Logger.Log(this, "DisplayLocalNotification title:" + title + " message:" + message);
// Ensure the main activity is lauched when the app is started.
Intent secondIntent = new Intent(Android.App.Application.Context, typeof(MainActivity));
Notification.BigTextStyle textStyle = new Notification.BigTextStyle();
textStyle.BigText(message);
int length = message.Length;
if (length > 80)
{
length = 80;
}
textStyle.SetSummaryText(message.Substring(0, length));
const int pendingIntentId = 0;
PendingIntent pendingEventForMainActivity =
PendingIntent.GetActivity(Android.App.Application.Context, pendingIntentId, secondIntent, PendingIntentFlags.OneShot);
Notification.Builder builder = new Notification.Builder(Android.App.Application.Context)
.SetContentTitle(title)
.SetContentText(message)
.SetAutoCancel(true)
.SetContentIntent(pendingEventForMainActivity)
//.SetWhen () // - Now
.SetSmallIcon(Resource.Drawable.icon)
.SetVisibility(NotificationVisibility.Public)
.SetCategory(Notification.CategoryEvent)
.SetStyle(textStyle)
//.SetSound(Asset);?? What import?
//.SetSound(RingtoneManager.) ?? Looks like it's a fixed list of alert sounds
.SetDefaults(NotificationDefaults.Sound | NotificationDefaults.Vibrate) // << DEPRECATD
.SetSound(Android.Net.Uri.Parse("android.resource://My-Assembly.Droid/Assets/" + soundFilename)); // << DEPECATD
// Hack - Works (if in foreground, but no if swipe-to-kill)...
// PlatformDifferences.PlaySound(soundFilename, Logger);
// Example: .SetSound(Uri.Parse("android.resource://" + this.PackageName + "/Raw/" + Resource.Raw.woop));
if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
{
builder.SetSmallIcon(Resource.Drawable.icon);// Resource.Drawable.icon_transparent);
}
else
{
builder.SetSmallIcon(Resource.Drawable.icon);
}
// Create a task stack builder to manage the back stack:
TaskStackBuilder stackBuilder = TaskStackBuilder.Create(Android.App.Application.Context);
// Add all parents of SecondActivity to the stack:
stackBuilder.AddParentStack(Java.Lang.Class.FromType(typeof(MainActivity)));
// Push the intent that starts SecondActivity onto the stack:
stackBuilder.AddNextIntent(secondIntent);
// Build the notification:
Notification androidNotification = builder.Build();
NotificationManager notificationManager =
Android.App.Application.Context.GetSystemService(Android.Content.Context.NotificationService) as NotificationManager;
// Publish the notification:
int notificationId = await StorageService.increment(Constants.STORAGE_KEY_NOTIFICATION_COUNTER);
notificationManager.Notify(notificationId, androidNotification);
Console.Out.WriteLine("DisplayLocalNotification title:" + title + " message:" + message + " published as id:" + notificationId + "?");
}
Please refer to the comments from #SushiHangover
Your screen shot is showing a API-27 device and if targetSdkVersion
was set, you would be required to use NotificationChannels (you would
need to if/else test the API levels as in my linked example). I have
seen a lot of different type of notification failures on different
(API-26+) devices, even notifications in the emulators behave
different when not using NotificationChannels.
So I am making my app compatible with Oreo and facing issue with notification.
I added notification channel according to documentation and everything is working smooth except notification keep making sound on every posting, tried setting defaults to 0 as well.
I am testing my app in emulator, any help is highly appreciated.
Used this code for creating channel
NotificationCompat.Builder builder = new NotificationCompat.Builder(PlayerService.this, "channel_01")
.setAutoCancel(false)
.setContentIntent(pendingIntent)
.setContent(viewsSmall)
.setCustomBigContentView(viewsExpanded)
.setDeleteIntent(pSwipeToDismiss);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
builder.setVisibility(Notification.VISIBILITY_PUBLIC);
}
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
builder.setPriority(Notification.PRIORITY_MAX);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
/* Create or update. */
NotificationChannel channel = new NotificationChannel("channel_01",
"Playback Notification",
NotificationManager.IMPORTANCE_DEFAULT);
mNotificationManager.createNotificationChannel(channel);
mBuilder.setChannelId("channel_01");
}
final Notification notification = builder.build();
startForeground(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE,notification);
Take a look at the notification channel settings (swipe your notification and press the settings icon under it and then select your channel). Those settings are set the first time you create the channel and then not modified unless you do it manually in the device (at least that is my experience from uninstalling and reinstalling my app to see what settings I get by default).
Basically, channel.setSound(null, null) will only have effect when you create the channel on a fresh installation. That might be what they try to explain in the official guide:
Attempting to create an existing notification channel with its original values performs no operation
If you tried to follow that guide and set NotificationManager.IMPORTANCE_HIGH and didn't use channel.setSound(null, null), the channel would get importance level Urgent Make sound and pop on screen with the default sound.
^Benjamin answer works but he is missing some important detail! You must change your channel ID each time you adjust your code or Oreo will not make the changes. Not sure why.
My code below and you can see where the chnage must be made with this <-------here
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String channelID = "My Channel I"; <-------here
String appName = mContext.getResources().getString(R.string.app_name);
NotificationCompat.Builder notificationCompatBuilder = new NotificationCompat.Builder(mContext );
notificationCompatBuilder
.setOngoing(true)
.setContentTitle(mContext.getResources().getString(R.string.app_name))
.setContentText(mContext.getString(R.string.clocked_in))
.setSmallIcon(R.drawable.ic_action_name)
.setChannelId(channelID)
.setSound(null);
NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel notificationChannel = new NotificationChannel(channelID, appName, NotificationManager.IMPORTANCE_LOW);
notificationChannel.setSound(null, null);
notificationManager.createNotificationChannel(notificationChannel);
notificationManager.notify(ONGOINGNOTIFICATION_ID, notificationCompatBuilder.build());
}
Replace your code with this
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
/* Create or update. */
NotificationChannel channel = new NotificationChannel("channel_01",
"Playback Notification",
NotificationManager.IMPORTANCE_LOW);
channel.setSound(null, null);
mNotificationManager.createNotificationChannel(channel);
mBuilder.setChannelId("channel_01");
}
My scene is the first time there is a sound, and the update notification does not require a sound.
I use this setOnlyAlertOnce() method
Reference: https://developer.android.com/training/notify-user/build-notification#Updating
Test pass version 26