Support for Android Marshmallow's permission system

This commit is contained in:
Karim Abou Zeid 2015-08-18 23:47:23 +02:00
commit 6f3617650a
12 changed files with 305 additions and 176 deletions

View file

@ -77,29 +77,36 @@ public class AlbumLoader {
return new Album(id, albumName, artist, artistId, songCount, year);
}
@Nullable
public static Cursor makeAlbumCursor(@NonNull final Context context, final String selection, final String[] values) {
return makeAlbumCursor(context, selection, values, PreferenceUtil.getInstance(context).getAlbumSortOrder());
}
@Nullable
public static Cursor makeAlbumCursor(@NonNull final Context context, final String selection, final String[] values, final String sortOrder) {
return makeAlbumCursor(context, MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, selection, values, sortOrder);
}
@Nullable
public static Cursor makeAlbumCursor(@NonNull final Context context, @NonNull final Uri contentUri, final String selection, final String[] values, final String sortOrder) {
return context.getContentResolver().query(contentUri,
new String[]{
try {
return context.getContentResolver().query(contentUri,
new String[]{
/* 0 */
BaseColumns._ID,
BaseColumns._ID,
/* 1 */
AlbumColumns.ALBUM,
AlbumColumns.ALBUM,
/* 2 */
AlbumColumns.ARTIST,
AlbumColumns.ARTIST,
/* 3 */
AudioColumns.ARTIST_ID,
AudioColumns.ARTIST_ID,
/* 4 */
AlbumColumns.NUMBER_OF_SONGS,
AlbumColumns.NUMBER_OF_SONGS,
/* 5 */
AlbumColumns.FIRST_YEAR,
}, selection, values, sortOrder);
AlbumColumns.FIRST_YEAR,
}, selection, values, sortOrder);
} catch (SecurityException e) {
return null;
}
}
}

View file

@ -21,11 +21,15 @@ public class ArtistAlbumLoader {
}
public static Cursor makeArtistAlbumCursor(@NonNull final Context context, final int artistId) {
return AlbumLoader.makeAlbumCursor(context,
MediaStore.Audio.Artists.Albums.getContentUri("external", artistId),
null,
null,
PreferenceUtil.getInstance(context).getArtistAlbumSortOrder()
);
try {
return AlbumLoader.makeAlbumCursor(context,
MediaStore.Audio.Artists.Albums.getContentUri("external", artistId),
null,
null,
PreferenceUtil.getInstance(context).getArtistAlbumSortOrder()
);
} catch (SecurityException e) {
return null;
}
}
}

View file

@ -74,17 +74,22 @@ public class ArtistLoader {
return new Artist(id, artistName, albumCount, songCount);
}
@Nullable
public static Cursor makeArtistCursor(@NonNull final Context context, final String selection, final String[] values) {
return context.getContentResolver().query(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
new String[]{
try {
return context.getContentResolver().query(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
new String[]{
/* 0 */
BaseColumns._ID,
BaseColumns._ID,
/* 1 */
ArtistColumns.ARTIST,
ArtistColumns.ARTIST,
/* 2 */
ArtistColumns.NUMBER_OF_ALBUMS,
ArtistColumns.NUMBER_OF_ALBUMS,
/* 3 */
ArtistColumns.NUMBER_OF_TRACKS
}, selection, values, PreferenceUtil.getInstance(context).getArtistSortOrder());
ArtistColumns.NUMBER_OF_TRACKS
}, selection, values, PreferenceUtil.getInstance(context).getArtistSortOrder());
} catch (SecurityException e) {
return null;
}
}
}

View file

@ -21,13 +21,17 @@ public class ArtistSongLoader {
}
public static Cursor makeArtistSongCursor(@NonNull final Context context, final int artistId) {
return SongLoader.makeSongCursor(
context,
MediaStore.Audio.AudioColumns.ARTIST_ID + "=?",
new String[]{
String.valueOf(artistId)
},
PreferenceUtil.getInstance(context).getArtistSongSortOrder()
);
try {
return SongLoader.makeSongCursor(
context,
MediaStore.Audio.AudioColumns.ARTIST_ID + "=?",
new String[]{
String.valueOf(artistId)
},
PreferenceUtil.getInstance(context).getArtistSongSortOrder()
);
} catch (SecurityException e) {
return null;
}
}
}

View file

@ -75,13 +75,18 @@ public class PlaylistLoader {
return new Playlist(id, name);
}
@Nullable
public static Cursor makePlaylistCursor(@NonNull final Context context, final String selection, final String[] values) {
return context.getContentResolver().query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
new String[]{
try {
return context.getContentResolver().query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
new String[]{
/* 0 */
BaseColumns._ID,
BaseColumns._ID,
/* 1 */
PlaylistsColumns.NAME
}, selection, values, MediaStore.Audio.Playlists.DEFAULT_SORT_ORDER);
PlaylistsColumns.NAME
}, selection, values, MediaStore.Audio.Playlists.DEFAULT_SORT_ORDER);
} catch (SecurityException e) {
return null;
}
}
}

View file

@ -45,30 +45,34 @@ public class PlaylistSongLoader {
}
public static Cursor makePlaylistSongCursor(@NonNull final Context context, final int playlistId) {
return context.getContentResolver().query(
MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId),
new String[]{
try {
return context.getContentResolver().query(
MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId),
new String[]{
/* 0 */
MediaStore.Audio.Playlists.Members.AUDIO_ID,
MediaStore.Audio.Playlists.Members.AUDIO_ID,
/* 1 */
AudioColumns.TITLE,
AudioColumns.TITLE,
/* 2 */
AudioColumns.ARTIST,
AudioColumns.ARTIST,
/* 3 */
AudioColumns.ALBUM,
AudioColumns.ALBUM,
/* 4 */
AudioColumns.DURATION,
AudioColumns.DURATION,
/* 5 */
AudioColumns.TRACK,
AudioColumns.TRACK,
/* 6 */
AudioColumns.ALBUM_ID,
AudioColumns.ALBUM_ID,
/* 7 */
AudioColumns.ARTIST_ID,
AudioColumns.ARTIST_ID,
/* 8 */
AudioColumns.DATA,
AudioColumns.DATA,
/* 9 */
MediaStore.Audio.Playlists.Members._ID
}, SongLoader.BASE_SELECTION, null,
MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER);
MediaStore.Audio.Playlists.Members._ID
}, SongLoader.BASE_SELECTION, null,
MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER);
} catch (SecurityException e) {
return null;
}
}
}

View file

@ -13,6 +13,8 @@ import com.kabouzeid.gramophone.util.PreferenceUtil;
import java.util.ArrayList;
import hugo.weaving.DebugLog;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
@ -77,36 +79,43 @@ public class SongLoader {
return new Song(id, albumId, artistId, songName, artist, album, duration, trackNumber, data);
}
@Nullable
public static Cursor makeSongCursor(@NonNull final Context context, final String selection, final String[] values) {
return makeSongCursor(context, selection, values, PreferenceUtil.getInstance(context).getSongSortOrder());
}
@DebugLog
@Nullable
public static Cursor makeSongCursor(@NonNull final Context context, @Nullable final String selection, final String[] values, final String sortOrder) {
String baseSelection = BASE_SELECTION;
if (selection != null && !selection.trim().equals("")) {
baseSelection += " AND " + selection;
}
return context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
new String[]{
try {
return context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
new String[]{
/* 0 */
BaseColumns._ID,
BaseColumns._ID,
/* 1 */
AudioColumns.TITLE,
AudioColumns.TITLE,
/* 2 */
AudioColumns.ARTIST,
AudioColumns.ARTIST,
/* 3 */
AudioColumns.ALBUM,
AudioColumns.ALBUM,
/* 4 */
AudioColumns.DURATION,
AudioColumns.DURATION,
/* 5 */
AudioColumns.TRACK,
AudioColumns.TRACK,
/* 6 */
AudioColumns.ARTIST_ID,
AudioColumns.ARTIST_ID,
/* 7 */
AudioColumns.ALBUM_ID,
AudioColumns.ALBUM_ID,
/* 8 */
AudioColumns.DATA
}, baseSelection, values, sortOrder);
AudioColumns.DATA
}, baseSelection, values, sortOrder);
} catch (SecurityException e) {
return null;
}
}
}

View file

@ -4,7 +4,6 @@ import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@ -139,7 +138,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
private boolean isServiceInUse;
private static String getTrackUri(@NonNull Song song) {
return ContentUris.withAppendedId(android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, song.id).toString();
return MusicUtil.getSongUri(song.id).toString();
}
@Override

View file

@ -1,14 +1,19 @@
package com.kabouzeid.gramophone.ui.activities.base;
import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.widget.Toast;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.interfaces.MusicServiceEventListener;
@ -17,24 +22,53 @@ import com.kabouzeid.gramophone.service.MusicService;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import hugo.weaving.DebugLog;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public abstract class AbsMusicServiceActivity extends AbsBaseActivity implements ServiceConnection, MusicServiceEventListener {
public static final String TAG = AbsMusicServiceActivity.class.getSimpleName();
public static final int REQUEST_EXTERNAL_STORAGE_PERMISSION = 0;
private final ArrayList<MusicServiceEventListener> mMusicServiceEventListener = new ArrayList<>();
private MusicPlayerRemote.ServiceToken serviceToken;
private MusicStateReceiver musicStateReceiver;
private boolean receiverRegistered;
private boolean hasExternalStoragePermission;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
checkExternalStoragePermissions();
serviceToken = MusicPlayerRemote.bindToService(this, this);
}
@Override
protected void onResume() {
super.onResume();
// the handler is necessary to avoid "java.lang.RuntimeException: Performing pause of activity that is not resumed"
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
recreateIfPermissionsChanged();
}
}, 200);
}
protected void recreateIfPermissionsChanged() {
if (didPermissionsChanged()) {
recreate();
}
}
private boolean didPermissionsChanged() {
return hasExternalStoragePermission != hasExternalStoragePermission();
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (!receiverRegistered) {
@ -161,4 +195,30 @@ public abstract class AbsMusicServiceActivity extends AbsBaseActivity implements
}
}
}
private void checkExternalStoragePermissions() {
hasExternalStoragePermission = hasExternalStoragePermission();
if (hasExternalStoragePermission) {
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_EXTERNAL_STORAGE_PERMISSION);
}
}
private boolean hasExternalStoragePermission() {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED;
}
@DebugLog
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_EXTERNAL_STORAGE_PERMISSION) {
for (int grantResult : grantResults) {
if (grantResult == PackageManager.PERMISSION_GRANTED) {
recreate();
return;
}
}
Toast.makeText(AbsMusicServiceActivity.this, "You must grant permission to external storage in order to explore your music", Toast.LENGTH_SHORT).show();
}
}
}

View file

@ -86,22 +86,25 @@ public class MusicUtil {
return;
}
Cursor cursor = resolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.MediaColumns.TITLE},
BaseColumns._ID + "=?",
new String[]{String.valueOf(id)},
null);
try {
if (cursor != null && cursor.getCount() == 1) {
cursor.moveToFirst();
Settings.System.putString(resolver, Settings.System.RINGTONE, uri.toString());
final String message = context.getString(R.string.x_has_been_set_as_ringtone, cursor.getString(0));
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
} finally {
if (cursor != null) {
cursor.close();
Cursor cursor = resolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.MediaColumns.TITLE},
BaseColumns._ID + "=?",
new String[]{String.valueOf(id)},
null);
try {
if (cursor != null && cursor.getCount() == 1) {
cursor.moveToFirst();
Settings.System.putString(resolver, Settings.System.RINGTONE, uri.toString());
final String message = context.getString(R.string.x_has_been_set_as_ringtone, cursor.getString(0));
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
} finally {
if (cursor != null) {
cursor.close();
}
}
} catch (SecurityException ignored) {
}
}
@ -174,46 +177,50 @@ public class MusicUtil {
}
}
selection.append(")");
final Cursor cursor = context.getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection.toString(),
null, null);
if (cursor != null) {
// Step 1: Remove selected tracks from the current playlist, as well
// as from the album art cache
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
final int id = cursor.getInt(0);
final Song song = SongLoader.getSong(context, id);
MusicPlayerRemote.removeFromQueue(song);
cursor.moveToNext();
}
// Step 2: Remove selected tracks from the database
context.getContentResolver().delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
selection.toString(), null);
// Step 3: Remove files from card
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
final String name = cursor.getString(1);
try { // File.delete can throw a security exception
final File f = new File(name);
if (!f.delete()) {
// I'm not sure if we'd ever get here (deletion would
// have to fail, but no exception thrown)
Log.e("MusicUtils", "Failed to delete file " + name);
}
try {
final Cursor cursor = context.getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection.toString(),
null, null);
if (cursor != null) {
// Step 1: Remove selected tracks from the current playlist, as well
// as from the album art cache
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
final int id = cursor.getInt(0);
final Song song = SongLoader.getSong(context, id);
MusicPlayerRemote.removeFromQueue(song);
cursor.moveToNext();
} catch (@NonNull final SecurityException ex) {
cursor.moveToNext();
} catch (NullPointerException e) {
Log.e("MusicUtils", "Failed to find file " + name);
}
// Step 2: Remove selected tracks from the database
context.getContentResolver().delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
selection.toString(), null);
// Step 3: Remove files from card
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
final String name = cursor.getString(1);
try { // File.delete can throw a security exception
final File f = new File(name);
if (!f.delete()) {
// I'm not sure if we'd ever get here (deletion would
// have to fail, but no exception thrown)
Log.e("MusicUtils", "Failed to delete file " + name);
}
cursor.moveToNext();
} catch (@NonNull final SecurityException ex) {
cursor.moveToNext();
} catch (NullPointerException e) {
Log.e("MusicUtils", "Failed to find file " + name);
}
}
cursor.close();
}
cursor.close();
context.getContentResolver().notifyChange(Uri.parse("content://media"), null);
Toast.makeText(context, context.getString(R.string.deleted_x_songs, songs.size()), Toast.LENGTH_SHORT).show();
} catch (SecurityException ignored) {
}
context.getContentResolver().notifyChange(Uri.parse("content://media"), null);
Toast.makeText(context, context.getString(R.string.deleted_x_songs, songs.size()), Toast.LENGTH_SHORT).show();
}
public static Playlist getFavoritesPlaylist(@NonNull final Context context) {

View file

@ -3,7 +3,6 @@ package com.kabouzeid.gramophone.util;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.provider.BaseColumns;
@ -16,7 +15,6 @@ import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.model.Playlist;
import com.kabouzeid.gramophone.model.PlaylistSong;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.service.MusicService;
import java.util.ArrayList;
import java.util.List;
@ -29,28 +27,31 @@ public class PlaylistsUtil {
public static int createPlaylist(@NonNull final Context context, @Nullable final String name) {
int id = -1;
if (name != null && name.length() > 0) {
Cursor cursor = context.getContentResolver().query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Audio.Playlists._ID}, MediaStore.Audio.PlaylistsColumns.NAME + "=?", new String[]{name}, null);
if (cursor == null || cursor.getCount() < 1) {
final ContentValues values = new ContentValues(1);
values.put(MediaStore.Audio.PlaylistsColumns.NAME, name);
final Uri uri = context.getContentResolver().insert(
MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
values);
if (uri != null) {
// necessary because somehow the MediaStoreObserver is not notified when adding a playlist
context.sendBroadcast(new Intent(MusicService.MEDIA_STORE_CHANGED));
Toast.makeText(context, context.getResources().getString(
R.string.created_playlist_x, name), Toast.LENGTH_SHORT).show();
id = Integer.parseInt(uri.getLastPathSegment());
try {
Cursor cursor = context.getContentResolver().query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Audio.Playlists._ID}, MediaStore.Audio.PlaylistsColumns.NAME + "=?", new String[]{name}, null);
if (cursor == null || cursor.getCount() < 1) {
final ContentValues values = new ContentValues(1);
values.put(MediaStore.Audio.PlaylistsColumns.NAME, name);
final Uri uri = context.getContentResolver().insert(
MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
values);
if (uri != null) {
// necessary because somehow the MediaStoreObserver is not notified when adding a playlist
context.getContentResolver().notifyChange(Uri.parse("content://media"), null);
Toast.makeText(context, context.getResources().getString(
R.string.created_playlist_x, name), Toast.LENGTH_SHORT).show();
id = Integer.parseInt(uri.getLastPathSegment());
}
} else {
if (cursor.moveToFirst()) {
id = cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Playlists._ID));
}
}
} else {
if (cursor.moveToFirst()) {
id = cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Playlists._ID));
if (cursor != null) {
cursor.close();
}
}
if (cursor != null) {
cursor.close();
} catch (SecurityException ignored) {
}
}
if (id == -1) {
@ -70,7 +71,10 @@ public class PlaylistsUtil {
}
}
selection.append(")");
context.getContentResolver().delete(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, selection.toString(), null);
try {
context.getContentResolver().delete(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, selection.toString(), null);
} catch (SecurityException ignored) {
}
}
public static void addToPlaylist(@NonNull final Context context, final Song song, final int playlistId, final boolean showToastOnFinish) {
@ -90,24 +94,27 @@ public class PlaylistsUtil {
int base = 0;
try {
cursor = resolver.query(uri, projection, null, null, null);
try {
cursor = resolver.query(uri, projection, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
base = cursor.getInt(0) + 1;
if (cursor != null && cursor.moveToFirst()) {
base = cursor.getInt(0) + 1;
}
} finally {
if (cursor != null) {
cursor.close();
}
}
} finally {
if (cursor != null) {
cursor.close();
int numInserted = 0;
for (int offSet = 0; offSet < size; offSet += 1000)
numInserted += resolver.bulkInsert(uri, makeInsertItems(songs, offSet, 1000, base));
if (showToastOnFinish) {
Toast.makeText(context, context.getResources().getString(
R.string.inserted_x_songs_into_playlist, numInserted), Toast.LENGTH_SHORT).show();
}
}
int numinserted = 0;
for (int offSet = 0; offSet < size; offSet += 1000)
numinserted += resolver.bulkInsert(uri, makeInsertItems(songs, offSet, 1000, base));
if (showToastOnFinish) {
Toast.makeText(context, context.getResources().getString(
R.string.inserted_x_songs_into_playlist, numinserted), Toast.LENGTH_SHORT).show();
} catch (SecurityException ignored) {
}
}
@ -133,7 +140,10 @@ public class PlaylistsUtil {
String selection = MediaStore.Audio.Playlists.Members.AUDIO_ID + " =?";
String[] selectionArgs = new String[]{String.valueOf(song.id)};
context.getContentResolver().delete(uri, selection, selectionArgs);
try {
context.getContentResolver().delete(uri, selection, selectionArgs);
} catch (SecurityException ignored) {
}
}
public static void removeFromPlaylist(@NonNull final Context context, @NonNull final List<PlaylistSong> songs) {
@ -145,23 +155,30 @@ public class PlaylistsUtil {
selectionArgs[i] = String.valueOf(songs.get(i).idInPlayList);
}
String selection = MediaStore.Audio.Playlists.Members._ID + " in (";
//noinspection unused
for (String selectionArg : selectionArgs) selection += "?, ";
selection = selection.substring(0, selection.length() - 2) + ")";
context.getContentResolver().delete(uri, selection, selectionArgs);
try {
context.getContentResolver().delete(uri, selection, selectionArgs);
} catch (SecurityException ignored) {
}
}
public static boolean doPlaylistContains(@NonNull final Context context, final long playlistId, final int songId) {
if (playlistId != -1) {
Cursor c = context.getContentResolver().query(
MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId),
new String[]{MediaStore.Audio.Playlists.Members.AUDIO_ID}, MediaStore.Audio.Playlists.Members.AUDIO_ID + "=?", new String[]{String.valueOf(songId)}, null);
int count = 0;
if (c != null) {
count = c.getCount();
c.close();
try {
Cursor c = context.getContentResolver().query(
MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId),
new String[]{MediaStore.Audio.Playlists.Members.AUDIO_ID}, MediaStore.Audio.Playlists.Members.AUDIO_ID + "=?", new String[]{String.valueOf(songId)}, null);
int count = 0;
if (c != null) {
count = c.getCount();
c.close();
}
return count > 0;
} catch (SecurityException ignored) {
}
return count > 0;
}
return false;
}
@ -174,27 +191,33 @@ public class PlaylistsUtil {
public static void renamePlaylist(@NonNull final Context context, final long id, final String newName) {
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Audio.PlaylistsColumns.NAME, newName);
context.getContentResolver().update(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
contentValues,
MediaStore.Audio.Playlists._ID + "=?",
new String[]{String.valueOf(id)});
try {
context.getContentResolver().update(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
contentValues,
MediaStore.Audio.Playlists._ID + "=?",
new String[]{String.valueOf(id)});
} catch (SecurityException ignored) {
}
}
public static String getNameForPlaylist(@NonNull final Context context, final long id) {
Cursor cursor = context.getContentResolver().query(
MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Audio.PlaylistsColumns.NAME},
BaseColumns._ID + "=?",
new String[]{String.valueOf(id)},
null);
if (cursor != null) {
try {
if (cursor.moveToFirst()) {
return cursor.getString(0);
try {
Cursor cursor = context.getContentResolver().query(
MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Audio.PlaylistsColumns.NAME},
BaseColumns._ID + "=?",
new String[]{String.valueOf(id)},
null);
if (cursor != null) {
try {
if (cursor.moveToFirst()) {
return cursor.getString(0);
}
} finally {
cursor.close();
}
} finally {
cursor.close();
}
} catch (SecurityException ignored) {
}
return "";
}