Fix Android issues
This commit is contained in:
parent
1096cea0b4
commit
f6ff0f6565
10 changed files with 1051 additions and 952 deletions
|
@ -371,6 +371,7 @@ object MusicPlayerRemote {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
fun removeFromQueue(song: Song): Boolean {
|
fun removeFromQueue(song: Song): Boolean {
|
||||||
if (musicService != null) {
|
if (musicService != null) {
|
||||||
musicService!!.removeSong(song)
|
musicService!!.removeSong(song)
|
||||||
|
|
|
@ -74,6 +74,7 @@ object SongLoader {
|
||||||
return song
|
return song
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
fun getSong(context: Context, queryId: Int): Song {
|
fun getSong(context: Context, queryId: Int): Song {
|
||||||
val cursor = makeSongCursor(context, AudioColumns._ID + "=?", arrayOf(queryId.toString()))
|
val cursor = makeSongCursor(context, AudioColumns._ID + "=?", arrayOf(queryId.toString()))
|
||||||
return getSong(cursor)
|
return getSong(cursor)
|
||||||
|
|
|
@ -38,6 +38,6 @@ class MediaStoreObserver(
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// milliseconds to delay before calling refresh to aggregate events
|
// milliseconds to delay before calling refresh to aggregate events
|
||||||
private val REFRESH_DELAY: Long = 500
|
private const val REFRESH_DELAY: Long = 500
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -14,17 +14,6 @@
|
||||||
|
|
||||||
package code.name.monkey.retromusic.service;
|
package code.name.monkey.retromusic.service;
|
||||||
|
|
||||||
import android.media.AudioManager;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.os.Message;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
|
||||||
|
|
||||||
import static code.name.monkey.retromusic.service.MusicService.DUCK;
|
import static code.name.monkey.retromusic.service.MusicService.DUCK;
|
||||||
import static code.name.monkey.retromusic.service.MusicService.META_CHANGED;
|
import static code.name.monkey.retromusic.service.MusicService.META_CHANGED;
|
||||||
import static code.name.monkey.retromusic.service.MusicService.PLAY_STATE_CHANGED;
|
import static code.name.monkey.retromusic.service.MusicService.PLAY_STATE_CHANGED;
|
||||||
|
@ -32,10 +21,20 @@ import static code.name.monkey.retromusic.service.MusicService.REPEAT_MODE_NONE;
|
||||||
import static code.name.monkey.retromusic.service.MusicService.TRACK_ENDED;
|
import static code.name.monkey.retromusic.service.MusicService.TRACK_ENDED;
|
||||||
import static code.name.monkey.retromusic.service.MusicService.TRACK_WENT_TO_NEXT;
|
import static code.name.monkey.retromusic.service.MusicService.TRACK_WENT_TO_NEXT;
|
||||||
|
|
||||||
|
import android.media.AudioManager;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.Message;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import code.name.monkey.retromusic.util.PreferenceUtil;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
class PlaybackHandler extends Handler {
|
class PlaybackHandler extends Handler {
|
||||||
|
|
||||||
|
private float currentDuckVolume = 1.0f;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final WeakReference<MusicService> mService;
|
private final WeakReference<MusicService> mService;
|
||||||
private float currentDuckVolume = 1.0f;
|
|
||||||
|
|
||||||
PlaybackHandler(final MusicService service, @NonNull final Looper looper) {
|
PlaybackHandler(final MusicService service, @NonNull final Looper looper) {
|
||||||
super(looper);
|
super(looper);
|
||||||
|
@ -79,9 +78,14 @@ class PlaybackHandler extends Handler {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TRACK_WENT_TO_NEXT:
|
case TRACK_WENT_TO_NEXT:
|
||||||
if (service.getRepeatMode() == REPEAT_MODE_NONE && service.isLastTrack()) {
|
if (service.pendingQuit || service.getRepeatMode() == REPEAT_MODE_NONE && service.isLastTrack()) {
|
||||||
service.pause();
|
service.pause();
|
||||||
service.seek(0);
|
service.seek(0);
|
||||||
|
if (service.pendingQuit) {
|
||||||
|
service.pendingQuit = false;
|
||||||
|
service.quit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
service.position = service.nextPosition;
|
service.position = service.nextPosition;
|
||||||
service.prepareNextImpl();
|
service.prepareNextImpl();
|
||||||
|
|
|
@ -21,6 +21,7 @@ import android.graphics.Bitmap
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.AsyncTask
|
import android.os.AsyncTask
|
||||||
|
import android.provider.MediaStore
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import code.name.monkey.retromusic.App
|
import code.name.monkey.retromusic.App
|
||||||
import code.name.monkey.retromusic.model.Artist
|
import code.name.monkey.retromusic.model.Artist
|
||||||
|
@ -32,7 +33,7 @@ import java.io.BufferedOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.*
|
import java.util.Locale
|
||||||
|
|
||||||
|
|
||||||
class CustomArtistImageUtil private constructor(context: Context) {
|
class CustomArtistImageUtil private constructor(context: Context) {
|
||||||
|
@ -80,7 +81,7 @@ class CustomArtistImageUtil private constructor(context: Context) {
|
||||||
if (succesful) {
|
if (succesful) {
|
||||||
mPreferences.edit().putBoolean(getFileName(artist), true).commit()
|
mPreferences.edit().putBoolean(getFileName(artist), true).commit()
|
||||||
ArtistSignatureUtil.getInstance(App.getContext()).updateArtistSignature(artist.name)
|
ArtistSignatureUtil.getInstance(App.getContext()).updateArtistSignature(artist.name)
|
||||||
App.getContext().contentResolver.notifyChange(Uri.parse("content://media"), null) // trigger media store changed to force artist image reload
|
App.getContext().contentResolver.notifyChange(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, null) // trigger media store changed to force artist image reload
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -95,7 +96,7 @@ class CustomArtistImageUtil private constructor(context: Context) {
|
||||||
override fun doInBackground(vararg params: Void): Void? {
|
override fun doInBackground(vararg params: Void): Void? {
|
||||||
mPreferences.edit().putBoolean(getFileName(artist), false).commit()
|
mPreferences.edit().putBoolean(getFileName(artist), false).commit()
|
||||||
ArtistSignatureUtil.getInstance(App.getContext()).updateArtistSignature(artist.name)
|
ArtistSignatureUtil.getInstance(App.getContext()).updateArtistSignature(artist.name)
|
||||||
App.getContext().contentResolver.notifyChange(Uri.parse("content://media"), null) // trigger media store changed to force artist image reload
|
App.getContext().contentResolver.notifyChange(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, null) // trigger media store changed to force artist image reload
|
||||||
|
|
||||||
val file = getFile(artist)
|
val file = getFile(artist)
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
|
|
|
@ -103,6 +103,7 @@ public class MusicUtil {
|
||||||
ContentResolver contentResolver = context.getContentResolver();
|
ContentResolver contentResolver = context.getContentResolver();
|
||||||
Uri localUri = Uri.parse("content://media/external/audio/albumart");
|
Uri localUri = Uri.parse("content://media/external/audio/albumart");
|
||||||
contentResolver.delete(ContentUris.withAppendedId(localUri, albumId), null, null);
|
contentResolver.delete(ContentUris.withAppendedId(localUri, albumId), null, null);
|
||||||
|
contentResolver.notifyChange(localUri, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void deleteTracks(
|
public static void deleteTracks(
|
||||||
|
@ -149,8 +150,8 @@ public class MusicUtil {
|
||||||
cursor.moveToFirst();
|
cursor.moveToFirst();
|
||||||
while (!cursor.isAfterLast()) {
|
while (!cursor.isAfterLast()) {
|
||||||
final int id = cursor.getInt(0);
|
final int id = cursor.getInt(0);
|
||||||
final Song song = SongLoader.INSTANCE.getSong(activity, id);
|
final Song song = SongLoader.getSong(activity, id);
|
||||||
MusicPlayerRemote.INSTANCE.removeFromQueue(song);
|
MusicPlayerRemote.removeFromQueue(song);
|
||||||
cursor.moveToNext();
|
cursor.moveToNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,14 +326,6 @@ public class MusicUtil {
|
||||||
return ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, songId);
|
return ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, songId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static String getSongInfoString(@NonNull Song song) {
|
|
||||||
return MusicUtil.buildInfoString(
|
|
||||||
song.getArtistName(),
|
|
||||||
song.getAlbumName()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long getTotalDuration(@NonNull List<Song> songs) {
|
public static long getTotalDuration(@NonNull List<Song> songs) {
|
||||||
long duration = 0;
|
long duration = 0;
|
||||||
for (int i = 0; i < songs.size(); i++) {
|
for (int i = 0; i < songs.size(); i++) {
|
||||||
|
@ -366,6 +359,7 @@ public class MusicUtil {
|
||||||
values.put("_data", path);
|
values.put("_data", path);
|
||||||
|
|
||||||
contentResolver.insert(artworkUri, values);
|
contentResolver.insert(artworkUri, values);
|
||||||
|
contentResolver.notifyChange(artworkUri, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isArtistNameUnknown(@Nullable String artistName) {
|
public static boolean isArtistNameUnknown(@Nullable String artistName) {
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
|
|
||||||
package code.name.monkey.retromusic.util;
|
package code.name.monkey.retromusic.util;
|
||||||
|
|
||||||
|
import static android.provider.MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -23,54 +25,72 @@ import android.os.Environment;
|
||||||
import android.provider.BaseColumns;
|
import android.provider.BaseColumns;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.R;
|
import code.name.monkey.retromusic.R;
|
||||||
import code.name.monkey.retromusic.helper.M3UWriter;
|
import code.name.monkey.retromusic.helper.M3UWriter;
|
||||||
import code.name.monkey.retromusic.model.Playlist;
|
import code.name.monkey.retromusic.model.Playlist;
|
||||||
import code.name.monkey.retromusic.model.PlaylistSong;
|
import code.name.monkey.retromusic.model.PlaylistSong;
|
||||||
import code.name.monkey.retromusic.model.Song;
|
import code.name.monkey.retromusic.model.Song;
|
||||||
|
import java.io.File;
|
||||||
import static android.provider.MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class PlaylistsUtil {
|
public class PlaylistsUtil {
|
||||||
public static boolean doesPlaylistExist(@NonNull final Context context, final int playlistId) {
|
|
||||||
return playlistId != -1 && doesPlaylistExist(context,
|
public static void addToPlaylist(@NonNull Context context,
|
||||||
MediaStore.Audio.Playlists._ID + "=?",
|
@NonNull List<Song> songs,
|
||||||
new String[]{String.valueOf(playlistId)});
|
int playlistId,
|
||||||
|
boolean showToastOnFinish) {
|
||||||
|
|
||||||
|
ArrayList<Song> noSongs = new ArrayList<Song>();
|
||||||
|
for (Song song : songs) {
|
||||||
|
if (!doPlaylistContains(context, playlistId, song.getId())) {
|
||||||
|
noSongs.add(song);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean doesPlaylistExist(@NonNull final Context context, final String name) {
|
final int size = noSongs.size();
|
||||||
return doesPlaylistExist(context,
|
final ContentResolver resolver = context.getContentResolver();
|
||||||
MediaStore.Audio.PlaylistsColumns.NAME + "=?",
|
final String[] projection = new String[]{"max(" + MediaStore.Audio.Playlists.Members.PLAY_ORDER + ")",};
|
||||||
new String[]{name});
|
final Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId);
|
||||||
|
|
||||||
|
int base = 0;
|
||||||
|
try (Cursor cursor = resolver.query(uri, projection, null, null, null)) {
|
||||||
|
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
base = cursor.getInt(0) + 1;
|
||||||
|
}
|
||||||
|
} catch (SecurityException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
int numInserted = 0;
|
||||||
|
for (int offSet = 0; offSet < size; offSet += 1000) {
|
||||||
|
numInserted += resolver.bulkInsert(uri, makeInsertItems(noSongs, offSet, 1000, base));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showToastOnFinish) {
|
||||||
|
Toast.makeText(context, context.getResources().getString(
|
||||||
|
R.string.inserted_x_songs_into_playlist_x, numInserted, getNameForPlaylist(context, playlistId)),
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int createPlaylist(@NonNull final Context context, @Nullable final String name) {
|
public static int createPlaylist(@NonNull final Context context, @Nullable final String name) {
|
||||||
int id = -1;
|
int id = -1;
|
||||||
if (name != null && name.length() > 0) {
|
if (name != null && name.length() > 0) {
|
||||||
try {
|
try {
|
||||||
Cursor cursor = context.getContentResolver().query(EXTERNAL_CONTENT_URI,
|
Cursor cursor = context.getContentResolver()
|
||||||
new String[]{MediaStore.Audio.Playlists._ID},
|
.query(EXTERNAL_CONTENT_URI, new String[]{MediaStore.Audio.Playlists._ID},
|
||||||
MediaStore.Audio.PlaylistsColumns.NAME + "=?", new String[]{name},
|
MediaStore.Audio.PlaylistsColumns.NAME + "=?", new String[]{name}, null);
|
||||||
null);
|
|
||||||
if (cursor == null || cursor.getCount() < 1) {
|
if (cursor == null || cursor.getCount() < 1) {
|
||||||
final ContentValues values = new ContentValues(1);
|
final ContentValues values = new ContentValues(1);
|
||||||
values.put(MediaStore.Audio.PlaylistsColumns.NAME, name);
|
values.put(MediaStore.Audio.PlaylistsColumns.NAME, name);
|
||||||
final Uri uri = context.getContentResolver().insert(
|
final Uri uri = context.getContentResolver().insert(EXTERNAL_CONTENT_URI, values);
|
||||||
EXTERNAL_CONTENT_URI,
|
|
||||||
values);
|
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
// Necessary because somehow the MediaStoreObserver is not notified when adding a playlist
|
Toast.makeText(context, context.getResources().getString(R.string.created_playlist_x, name),
|
||||||
context.getContentResolver().notifyChange(Uri.parse("content://media"), null);
|
Toast.LENGTH_SHORT).show();
|
||||||
Toast.makeText(context, context.getResources().getString(R.string.created_playlist_x, name), Toast.LENGTH_SHORT).show();
|
|
||||||
id = Integer.parseInt(uri.getLastPathSegment());
|
id = Integer.parseInt(uri.getLastPathSegment());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -109,55 +129,63 @@ public class PlaylistsUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addToPlaylist(@NonNull Context context,
|
public static boolean doPlaylistContains(@NonNull final Context context, final long playlistId,
|
||||||
@NonNull Song song,
|
final int songId) {
|
||||||
int playlistId,
|
if (playlistId != -1) {
|
||||||
boolean showToastOnFinish) {
|
try {
|
||||||
List<Song> helperList = new ArrayList<>();
|
Cursor c = context.getContentResolver().query(
|
||||||
helperList.add(song);
|
MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId),
|
||||||
addToPlaylist(context, helperList, playlistId, showToastOnFinish);
|
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;
|
||||||
public static void addToPlaylist(@NonNull Context context,
|
} catch (SecurityException ignored) {
|
||||||
@NonNull List<Song> songs,
|
|
||||||
int playlistId,
|
|
||||||
boolean showToastOnFinish) {
|
|
||||||
|
|
||||||
ArrayList<Song> noSongs = new ArrayList<Song>();
|
|
||||||
for (Song song : songs) {
|
|
||||||
if (!doPlaylistContains(context, playlistId, song.getId())) {
|
|
||||||
noSongs.add(song);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean doesPlaylistExist(@NonNull final Context context, final int playlistId) {
|
||||||
|
return playlistId != -1 && doesPlaylistExist(context,
|
||||||
|
MediaStore.Audio.Playlists._ID + "=?",
|
||||||
|
new String[]{String.valueOf(playlistId)});
|
||||||
|
}
|
||||||
|
|
||||||
final int size = noSongs.size();
|
public static boolean doesPlaylistExist(@NonNull final Context context, final String name) {
|
||||||
final ContentResolver resolver = context.getContentResolver();
|
return doesPlaylistExist(context,
|
||||||
final String[] projection = new String[]{"max(" + MediaStore.Audio.Playlists.Members.PLAY_ORDER + ")",};
|
MediaStore.Audio.PlaylistsColumns.NAME + "=?",
|
||||||
final Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId);
|
new String[]{name});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getNameForPlaylist(@NonNull final Context context, final long id) {
|
||||||
int base = 0;
|
try {
|
||||||
try (Cursor cursor = resolver.query(uri, projection, null, null, null)) {
|
Cursor cursor = context.getContentResolver().query(EXTERNAL_CONTENT_URI,
|
||||||
|
new String[]{MediaStore.Audio.PlaylistsColumns.NAME},
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
BaseColumns._ID + "=?",
|
||||||
base = cursor.getInt(0) + 1;
|
new String[]{String.valueOf(id)},
|
||||||
|
null);
|
||||||
|
if (cursor != null) {
|
||||||
|
try {
|
||||||
|
if (cursor.moveToFirst()) {
|
||||||
|
return cursor.getString(0);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (SecurityException ignored) {
|
} catch (SecurityException ignored) {
|
||||||
}
|
}
|
||||||
|
return "";
|
||||||
int numInserted = 0;
|
|
||||||
for (int offSet = 0; offSet < size; offSet += 1000)
|
|
||||||
numInserted += resolver.bulkInsert(uri, makeInsertItems(noSongs, offSet, 1000, base));
|
|
||||||
|
|
||||||
if (showToastOnFinish) {
|
|
||||||
Toast.makeText(context, context.getResources().getString(
|
|
||||||
R.string.inserted_x_songs_into_playlist_x, numInserted, getNameForPlaylist(context, playlistId)), Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static ContentValues[] makeInsertItems(@NonNull final List<Song> songs, final int offset, int len, final int base) {
|
public static ContentValues[] makeInsertItems(@NonNull final List<Song> songs, final int offset, int len,
|
||||||
|
final int base) {
|
||||||
if (offset + len > songs.size()) {
|
if (offset + len > songs.size()) {
|
||||||
len = songs.size() - offset;
|
len = songs.size() - offset;
|
||||||
}
|
}
|
||||||
|
@ -172,6 +200,11 @@ public class PlaylistsUtil {
|
||||||
return contentValues;
|
return contentValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean moveItem(@NonNull final Context context, int playlistId, int from, int to) {
|
||||||
|
return MediaStore.Audio.Playlists.Members.moveItem(context.getContentResolver(),
|
||||||
|
playlistId, from, to);
|
||||||
|
}
|
||||||
|
|
||||||
public static void removeFromPlaylist(@NonNull final Context context, @NonNull final Song song, int playlistId) {
|
public static void removeFromPlaylist(@NonNull final Context context, @NonNull final Song song, int playlistId) {
|
||||||
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri(
|
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri(
|
||||||
"external", playlistId);
|
"external", playlistId);
|
||||||
|
@ -194,7 +227,9 @@ public class PlaylistsUtil {
|
||||||
}
|
}
|
||||||
String selection = MediaStore.Audio.Playlists.Members._ID + " in (";
|
String selection = MediaStore.Audio.Playlists.Members._ID + " in (";
|
||||||
//noinspection unused
|
//noinspection unused
|
||||||
for (String selectionArg : selectionArgs) selection += "?, ";
|
for (String selectionArg : selectionArgs) {
|
||||||
|
selection += "?, ";
|
||||||
|
}
|
||||||
selection = selection.substring(0, selection.length() - 2) + ")";
|
selection = selection.substring(0, selection.length() - 2) + ")";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -203,29 +238,6 @@ public class PlaylistsUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean doPlaylistContains(@NonNull final Context context, final long playlistId, final int songId) {
|
|
||||||
if (playlistId != -1) {
|
|
||||||
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 false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean moveItem(@NonNull final Context context, int playlistId, int from, int to) {
|
|
||||||
return MediaStore.Audio.Playlists.Members.moveItem(context.getContentResolver(),
|
|
||||||
playlistId, from, to);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void renamePlaylist(@NonNull final Context context, final long id, final String newName) {
|
public static void renamePlaylist(@NonNull final Context context, final long id, final String newName) {
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(MediaStore.Audio.PlaylistsColumns.NAME, newName);
|
contentValues.put(MediaStore.Audio.PlaylistsColumns.NAME, newName);
|
||||||
|
@ -234,39 +246,27 @@ public class PlaylistsUtil {
|
||||||
contentValues,
|
contentValues,
|
||||||
MediaStore.Audio.Playlists._ID + "=?",
|
MediaStore.Audio.Playlists._ID + "=?",
|
||||||
new String[]{String.valueOf(id)});
|
new String[]{String.valueOf(id)});
|
||||||
context.getContentResolver().notifyChange(Uri.parse("content://media"), null);
|
|
||||||
} catch (SecurityException ignored) {
|
} catch (SecurityException ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getNameForPlaylist(@NonNull final Context context, final long id) {
|
|
||||||
try {
|
|
||||||
Cursor cursor = context.getContentResolver().query(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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SecurityException ignored) {
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static File savePlaylist(@NonNull Context context,
|
public static File savePlaylist(@NonNull Context context,
|
||||||
@NonNull Playlist playlist) throws IOException {
|
@NonNull Playlist playlist) throws IOException {
|
||||||
return M3UWriter.write(context, new File(Environment.getExternalStorageDirectory(), "Playlists"), playlist);
|
return M3UWriter.write(context, new File(Environment.getExternalStorageDirectory(), "Playlists"), playlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean doesPlaylistExist(@NonNull Context context, @NonNull final String selection, @NonNull final String[] values) {
|
static void addToPlaylist(@NonNull Context context,
|
||||||
|
@NonNull Song song,
|
||||||
|
int playlistId,
|
||||||
|
boolean showToastOnFinish) {
|
||||||
|
List<Song> helperList = new ArrayList<>();
|
||||||
|
helperList.add(song);
|
||||||
|
addToPlaylist(context, helperList, playlistId, showToastOnFinish);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean doesPlaylistExist(@NonNull Context context, @NonNull final String selection,
|
||||||
|
@NonNull final String[] values) {
|
||||||
Cursor cursor = context.getContentResolver().query(EXTERNAL_CONTENT_URI,
|
Cursor cursor = context.getContentResolver().query(EXTERNAL_CONTENT_URI,
|
||||||
new String[]{}, selection, values, null);
|
new String[]{}, selection, values, null);
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
android:id="@+id/songCurrentProgress"
|
android:id="@+id/songCurrentProgress"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
android:gravity="center_vertical|left|end"
|
android:gravity="center_vertical|left|end"
|
||||||
android:paddingStart="8dp"
|
android:paddingStart="8dp"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
|
|
|
@ -10,7 +10,7 @@ buildscript {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.5.2'
|
classpath 'com.android.tools.build:gradle:3.5.3'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
classpath 'com.android.tools.build:bundletool:0.9.0'
|
classpath 'com.android.tools.build:bundletool:0.9.0'
|
||||||
classpath "gradle.plugin.ru.cleverpumpkin.proguard-dictionaries-generator:plugin:1.0.7"
|
classpath "gradle.plugin.ru.cleverpumpkin.proguard-dictionaries-generator:plugin:1.0.7"
|
||||||
|
|
Loading…
Reference in a new issue