Search code examples
androidnotificationsringtone

Set ringtone / notification tone via contentprovider (from assets)


I'm trying to set the android default ringtone or notification tone via content provider from my assets folder. Surprisingly, it works like this, but is it a legitimate way?

Uri audiouri = Uri.parse("content://"+BuildConfig.APPLICATION_ID+"/"+soundname+".mp3");
RingtoneManager.setActualDefaultRingtoneUri(a, TYPE_NOTIFICATION, audiouri );

Unfortunately, the sound name isn't shown in Android settings. enter image description here

Strangely the sound name is actually shown when I go to 'Other sounds' enter image description here

I also tried this:

Uri audiouri = Uri.parse("content://"+BuildConfig.APPLICATION_ID+"/"+soundname+".mp3");
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.TITLE, soundname);
Uri ringtoneuri = a.getContentResolver().insert(audiouri, contentValues);
RingtoneManager.setActualDefaultRingtoneUri(a, TYPE_NOTIFICATION, ringtoneuri);

resulting in a null sound (no sound is set)

third option I tried is:

Uri audiouri = MediaStore.Audio.Media.getContentUriForPath("content://"+BuildConfig.APPLICATION_ID+"/"+soundname+".mp3");
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DATA, "content://"+BuildConfig.APPLICATION_ID+"/"+soundname+".mp3");
contentValues.put(MediaStore.MediaColumns.TITLE, soundname);
Uri ringtoneuri = a.getContentResolver().insert(audiouri, contentValues);
RingtoneManager.setActualDefaultRingtoneUri(a, TYPE_NOTIFICATION, ringtoneuri);

Now the sound name is shown correctly, but no sound is actually played. I get error on logcat:

java.io.FileNotFoundException: Can't access /content:/com.mydomain.myapp/test.mp3

So it seems it's taking the value from MediaColumns.DATA which does not support Content provider paths but only real paths. Right?

enter image description here

Final question: How to set tone AND name in android settings? Preferably without copying the file to external storage.


Solution

  • So, unfortunately I did not find out how to set asset as ringtone directly, but this is a nice workaround:

    When copying asset to internal app storage or cache dir (no permissions needed for that!) I was able to set the ringtone without WRITE_EXTERNAL_STORAGE permisson.

    static void settone(int type, Sound sound, Activity a)
    {
        lastsound = sound; //global remember sound and type (alarm/ringtone/notification) 
        lasttype = type;   // if we have to get permissions first, then call this from onActivityResult
        if (canwritesystem(a))
        {
            RingtoneManager.setActualDefaultRingtoneUri(a, type, getringtoneuri(sound, a));
            Toast.makeText(a, a.getString(R.string.settonesuccess), Toast.LENGTH_LONG).show();
        }
        else a.startActivityForResult(new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS).setData(Uri.parse("package:" + a.getPackageName())),CONTEXT_SET_TONE);
    }
    
    static Uri getringtoneuri(Sound sound, Activity a)
    {
        File tonefile = new File(sound.getpath); // path could be like: /Android/data/com.company.yourapp
        ContentValues contentValues = new ContentValues();
        contentValues.put(MediaStore.MediaColumns.DATA, tonefile.getAbsolutePath());
        contentValues.put(MediaStore.MediaColumns.TITLE, sound.getDisplayName());
        contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "audio/mp3");
        contentValues.put(MediaStore.MediaColumns.SIZE, tonefile.length());
        contentValues.put(MediaStore.Audio.Media.IS_RINGTONE, true);
        contentValues.put(MediaStore.Audio.Media.IS_NOTIFICATION, true);
        contentValues.put(MediaStore.Audio.Media.IS_ALARM, true);
        contentValues.put(MediaStore.Audio.Media.IS_MUSIC, false);
        Uri generalaudiouri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
        a.getContentResolver().delete(generalaudiouri, MediaStore.MediaColumns.DATA + "='" + tonefile.getAbsolutePath() + "'", null);
        return a.getContentResolver().insert(generalaudiouri, contentValues);
    }