Xamarin.Android Cannot use recorded custom sound for push notifications in Android 10 (Q)

Cdn_EuroCdn_Euro Member ✭✭✭
edited October 8 in Xamarin.Android

This used to work, record a sound in order to use for the custom sound for a push notification channel. Now it does not anymore.
What changed please, why would this not work anymore, there is no sound when notification comes in?

In order to use a recorded sound for push notifications, I used to copy it to external storage from where it can be accessed at runtime like this:

the path for an external path was like this:

/storage/emulated/0/customNotificationSoundRecording.wav

public async void CopyRecordingToExternalStorage(string filePath)
        {
            var recordingFileExternalPath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path, AppConstants.CUSTOM_ALERT_FILENAME);

             // made some other attempts with different paths.
            // var recordingFileExternalPath = Path.Combine(FileSystem.AppDataDirectory, AppConstants.CUSTOM_ALERT_FILENAME);
            //var recordingFileExternalPath = Path.Combine(Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryAlarms).AbsolutePath, AppConstants.CUSTOM_ALERT_FILENAME);

            var storageStatus = await CrossPermissions.Current.CheckPermissionStatusAsync(Plugin.Permissions.Abstractions.Permission.Storage);

            if (storageStatus != Plugin.Permissions.Abstractions.PermissionStatus.Granted)
            {
                var results = await CrossPermissions.Current.RequestPermissionsAsync(new[] { Plugin.Permissions.Abstractions.Permission.Storage });
                storageStatus = results[Plugin.Permissions.Abstractions.Permission.Storage];
            }

            if (storageStatus == Plugin.Permissions.Abstractions.PermissionStatus.Granted)
            {
                try
                {
                    if (File.Exists(recordingFileExternalPath))  // if file exists already in external storage
                    {
                        File.Delete(recordingFileExternalPath); // erase the file
                    }

                    File.Copy(filePath, recordingFileExternalPath); // and overwrite with new one
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
            else
            {
                UserDialogs.Instance.Alert("Permission to write to External Storage denied, cannot save settings.", "Permission Denied", "Ok");
            }             
        }

And then I would create a channel with that sound like this:

private void createCustomNotificationChannel()
        {
            try
            {
                // the custom channel
                var urgentChannelName = GetString(Resource.String.noti_chan_custom);
                var customChannelDescription = GetString(Resource.String.noti_chan_custom_description);

                long[] customVibrationPattern = { 100, 30, 100, 30, 100, 200, 200, 30, 200, 30, 200, 200, 100, 30, 100, 30, 100, 100, 30, 100, 30, 100, 200, 200, 30, 200, 30, 200, 200, 100, 30, 100, 30, 100 };

                // Creating an Audio Attribute
                var alarmAttributes = new AudioAttributes.Builder()
                    .SetContentType(AudioContentType.Sonification)
                    .SetUsage(AudioUsageKind.Notification).Build();

                var alarmSourcePath = System.IO.Path.Combine(Android.OS.Environment.ExternalStorageDirectory.Path, AppConstants.CUSTOM_ALERT_FILENAME);

                 // also tried here with other paths
                // var alarmSourcePath = Path.Combine(FileSystem.AppDataDirectory, AppConstants.CUSTOM_ALERT_FILENAME);
                // var alarmSourcePath = System.IO.Path.Combine(Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryAlarms).AbsolutePath, AppConstants.CUSTOM_ALERT_FILENAME);

                var urgentAlarmUri = Android.Net.Uri.Parse(alarmSourcePath);

                bool soundFileExists = File.Exists(alarmSourcePath);

                var chan3 = new NotificationChannel(TERTIARY_CHANNEL_ID, urgentChannelName, NotificationImportance.High)
                {
                    Description = customChannelDescription
                };

                // set the urgent channel properties
                chan3.EnableLights(true);
                chan3.LightColor = Android.Graphics.Color.Red;
                chan3.SetSound(urgentAlarmUri, alarmAttributes);
                chan3.EnableVibration(true);
                chan3.SetVibrationPattern(customVibrationPattern);
                chan3.SetBypassDnd(true);
                chan3.LockscreenVisibility = NotificationVisibility.Public;

                var manager = (NotificationManager)GetSystemService(NotificationService);

                // create chan1  which is the urgent notifications channel
                manager.CreateNotificationChannel(chan3);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

Answers

  • LeonLuLeonLu Member, Xamarin Team Xamurai

    I used to copy it to external storage from where it can be accessed at runtime like this:

    If you use android 10 ,by default, such apps can see only their app-specific directory ,to give users more control over their files and to limit file clutter, apps targeting Android 10 (API level 29) and higher are given scoped access into an external storage device, or scoped storage, It's a best practice to use scoped storage unless your app needs access to a file that doesn't reside in either the app-specific directory or the MediaStore.

    If you don't want change, you could try to add android:requestLegacyExternalStorage="true" to your element in the manifest.

    Leo have give you update in the SO.
    https://stackoverflow.com/questions/58280428/xamarin-android-cannot-use-recorded-custom-sound-for-push-notifications-in-andro

Sign In or Register to comment.