diff --git a/api/system-current.txt b/api/system-current.txt index f5e7523049484..de96c19ef6bc9 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3648,6 +3648,10 @@ package android.media { method public void stop(); } + public class RingtoneManager { + method @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) public static void ensureDefaultRingtones(@NonNull android.content.Context); + } + } package android.media.audiopolicy { diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java index ff40442204285..9064e6891be69 100644 --- a/media/java/android/media/RingtoneManager.java +++ b/media/java/android/media/RingtoneManager.java @@ -22,6 +22,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.annotation.WorkerThread; import android.app.Activity; @@ -40,9 +41,11 @@ import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.MediaStore; +import android.provider.MediaStore.MediaColumns; import android.provider.Settings; import android.provider.Settings.System; import android.util.Log; @@ -1097,4 +1100,62 @@ public class RingtoneManager { return null; } } + + /** + * Ensure that ringtones have been set at least once on this device. This + * should be called after the device has finished scanned all media on + * {@link MediaStore#VOLUME_INTERNAL}, so that default ringtones can be + * configured. + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) + public static void ensureDefaultRingtones(@NonNull Context context) { + for (int type : new int[] { + TYPE_RINGTONE, + TYPE_NOTIFICATION, + TYPE_ALARM, + }) { + // Skip if we've already defined it at least once, so we don't + // overwrite the user changing to null + final String setting = getDefaultRingtoneSetting(type); + if (Settings.System.getInt(context.getContentResolver(), setting, 0) != 0) { + continue; + } + + // Try finding the scanned ringtone + final String filename = getDefaultRingtoneFilename(type); + final Uri baseUri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI; + try (Cursor cursor = context.getContentResolver().query(baseUri, + new String[] { MediaColumns._ID }, + MediaColumns.DISPLAY_NAME + "=?", + new String[] { filename }, null)) { + if (cursor.moveToFirst()) { + final Uri ringtoneUri = context.getContentResolver().canonicalizeOrElse( + ContentUris.withAppendedId(baseUri, cursor.getLong(0))); + RingtoneManager.setActualDefaultRingtoneUri(context, type, ringtoneUri); + Settings.System.putInt(context.getContentResolver(), setting, 1); + } + } + } + } + + private static String getDefaultRingtoneSetting(int type) { + switch (type) { + case TYPE_RINGTONE: return "ringtone_set"; + case TYPE_NOTIFICATION: return "notification_sound_set"; + case TYPE_ALARM: return "alarm_alert_set"; + default: throw new IllegalArgumentException(); + } + } + + private static String getDefaultRingtoneFilename(int type) { + switch (type) { + case TYPE_RINGTONE: return SystemProperties.get("ro.config.ringtone"); + case TYPE_NOTIFICATION: return SystemProperties.get("ro.config.notification_sound"); + case TYPE_ALARM: return SystemProperties.get("ro.config.alarm_alert"); + default: throw new IllegalArgumentException(); + } + } }