[RingtoneManager] API to delete custom ringtones

Given a Uri, if it is a media file in one of the external ringtone
storages, this API deletes its file and database entry.

Test: manual - associated CL
Bug: 30658854
Change-Id: I987bd18577960f9a2b02ce37a4a2d5d033d7a969
This commit is contained in:
Andre Lago
2016-09-30 17:02:57 +01:00
committed by Robin Lee
parent 7c8ccb3ce4
commit 178693a5df

View File

@@ -678,7 +678,29 @@ public class RingtoneManager {
return null;
}
/**
* Look up the path for a given {@link Uri} referring to a ringtone sound (TYPE_RINGTONE,
* TYPE_NOTIFICATION, or TYPE_ALARM). This is saved in {@link MediaStore.Audio.Media#DATA}.
*
* @return a {@link File} pointing at the location of the {@param uri} on disk, or {@code null}
* if there is no such file.
*/
private File getRingtonePathFromUri(Uri uri) {
// Query cursor to get ringtone path
final String[] projection = {MediaStore.Audio.Media.DATA};
setFilterColumnsList(TYPE_RINGTONE | TYPE_NOTIFICATION | TYPE_ALARM);
String path = null;
try (Cursor cursor = query(uri, projection, constructBooleanTrueWhereClause(mFilterColumns),
null, null)) {
if (cursor != null && cursor.moveToFirst()) {
path = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
}
}
return path != null ? new File(path) : null;
}
/**
* Disables Settings.System.SYNC_PARENT_SOUNDS, copying the parent's ringtones to the current
* profile
@@ -785,9 +807,43 @@ public class RingtoneManager {
}
private static boolean isInternalRingtoneUri(Uri uri) {
Uri uriWithoutUserId = ContentProvider.getUriWithoutUserId(uri);
return uriWithoutUserId == null ? false : uriWithoutUserId.toString()
.startsWith(MediaStore.Audio.Media.INTERNAL_CONTENT_URI.toString());
return isRingtoneUriInStorage(uri, MediaStore.Audio.Media.INTERNAL_CONTENT_URI);
}
private static boolean isExternalRingtoneUri(Uri uri) {
return isRingtoneUriInStorage(uri, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI);
}
private static boolean isRingtoneUriInStorage(Uri ringtone, Uri storage) {
Uri uriWithoutUserId = ContentProvider.getUriWithoutUserId(ringtone);
return uriWithoutUserId == null ? false
: uriWithoutUserId.toString().startsWith(storage.toString());
}
/** @hide */
public boolean isCustomRingtone(Uri uri) {
if(!isExternalRingtoneUri(uri)) {
// A custom ringtone would be in the external storage
return false;
}
final File ringtoneFile = (uri == null ? null : getRingtonePathFromUri(uri));
final File parent = (ringtoneFile == null ? null : ringtoneFile.getParentFile());
if (parent == null) {
return false;
}
final String[] directories = {
Environment.DIRECTORY_RINGTONES,
Environment.DIRECTORY_NOTIFICATIONS,
Environment.DIRECTORY_ALARMS
};
for (final String directory : directories) {
if (parent.equals(Environment.getExternalStoragePublicDirectory(directory))) {
return true;
}
}
return false;
}
/**
@@ -871,6 +927,39 @@ public class RingtoneManager {
}
}
/**
* Deletes the actual file in the Uri and its ringtone database entry if the Uri's actual path
* is in one of the following directories: {@link android.is.Environment#DIRECTORY_RINGTONES},
* {@link android.is.Environment#DIRECTORY_NOTIFICATIONS} or
* {@link android.is.Environment#DIRECTORY_ALARMS}.
*
* The given Uri must be a ringtone Content Uri.
*
* Keep in mind that if the ringtone deleted is a default ringtone, it will still live in the
* ringtone cache file so it will be playable from there. However, if an app uses the ringtone
* as its own ringtone, it won't be played, which is the same behavior observed for 3rd party
* custom ringtones.
*
* @hide
*/
public boolean deleteExternalRingtone(Uri uri) {
if(!isCustomRingtone(uri)) {
// We can only delete custom ringtones in the default ringtone storages
return false;
}
// Save the path of the ringtone before deleting from our content resolver.
final File ringtoneFile = getRingtonePathFromUri(uri);
try {
if (ringtoneFile != null && mContext.getContentResolver().delete(uri, null, null) > 0) {
return ringtoneFile.delete();
}
} catch (SecurityException e) {
Log.d(TAG, "Unable to delete custom ringtone", e);
}
return false;
}
/**
* Try opening the given ringtone locally first, but failover to
* {@link IRingtonePlayer} if we can't access it directly. Typically happens