app/src/main/java/com/andryr/musicplayer/loaders/AlbumLoader.java
public class AlbumLoader extends BaseLoader<List<Album>> {


    private static final String[] sProjection = {BaseColumns._ID,
            MediaStore.Audio.AlbumColumns.ALBUM,
            MediaStore.Audio.AlbumColumns.ARTIST,
            MediaStore.Audio.AlbumColumns.FIRST_YEAR,


            MediaStore.Audio.AlbumColumns.NUMBER_OF_SONGS};

    private String mArtist = null;

    private List<Album> mAlbumList;


    public AlbumLoader(Context context) {
        super(context);
    }

    public AlbumLoader(Context context, String artist) {
        super(context);
        mArtist = artist;
    }


    @Override
    public List<Album> loadInBackground() {


        mAlbumList = new ArrayList<>();

        Cursor cursor = getAlbumCursor();

        if (cursor != null && cursor.moveToFirst()) {
            int idCol = cursor.getColumnIndex(BaseColumns._ID);

            int albumNameCol = cursor.getColumnIndex(MediaStore.Audio.AlbumColumns.ALBUM);
            int artistCol = cursor.getColumnIndex(MediaStore.Audio.AlbumColumns.ARTIST);
            int yearCol = cursor.getColumnIndex(MediaStore.Audio.AlbumColumns.FIRST_YEAR);

            int songsNbCol = cursor
                    .getColumnIndex(MediaStore.Audio.AlbumColumns.NUMBER_OF_SONGS);

            do {

                long id = cursor.getLong(idCol);

                String name = cursor.getString(albumNameCol);
                if (name == null || name.equals(MediaStore.UNKNOWN_STRING)) {
                    name = getContext().getString(R.string.unknown_album);
                    id = -1;
                }
                String artist = cursor.getString(artistCol);
                int year = cursor.getInt(yearCol);
                int count = cursor.getInt(songsNbCol);


                mAlbumList.add(new Album(id, name, artist, year, count));

            } while (cursor.moveToNext());


        }


        if (cursor != null) {
            cursor.close();
        }
        return mAlbumList;
    }

    private Cursor getAlbumCursor() {

        Uri musicUri = MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI;

        String selection = getSelectionString();
        String[] selectionArgs = getSelectionArgs();
        if (mArtist != null) {
            selection = DatabaseUtilsCompat.concatenateWhere(selection, MediaStore.Audio.Albums.ARTIST + " = ?");
            selectionArgs = DatabaseUtilsCompat.appendSelectionArgs(selectionArgs, new String[]{mArtist});

        }

        String fieldName = MediaStore.Audio.Albums.ALBUM;
        String filter = getFilter();
        return getCursor(musicUri, sProjection, selection, selectionArgs, fieldName, filter);
    }


}
app/src/main/java/com/andryr/musicplayer/loaders/SongLoader.java
public class SongLoader extends BaseLoader<List<Song>> {

    private static final String[] sProjection = {MediaStore.Audio.Media._ID,
            MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.ARTIST,
            MediaStore.Audio.Media.ALBUM, MediaStore.Audio.Media.ALBUM_ID,
            MediaStore.Audio.Media.ARTIST_ID, MediaStore.Audio.Media.TRACK,
            MediaStore.Audio.Media.DURATION
    };

    private List<Song> mSongList = null;

    public SongLoader(Context context) {
        super(context);

    }

    @Override
    public List<Song> loadInBackground() {
        mSongList = new ArrayList<>();

        Cursor cursor = getSongCursor();
        if (cursor != null && cursor.moveToFirst()) {
            int idCol = cursor
                    .getColumnIndex(MediaStore.Audio.Playlists.Members.AUDIO_ID);
            if (idCol == -1) {
                idCol = cursor.getColumnIndex(MediaStore.Audio.Media._ID);
            }
            int titleCol = cursor
                    .getColumnIndex(MediaStore.Audio.Media.TITLE);
            int artistCol = cursor
                    .getColumnIndex(MediaStore.Audio.Media.ARTIST);
            int albumCol = cursor
                    .getColumnIndex(MediaStore.Audio.Media.ALBUM);
            int albumIdCol = cursor
                    .getColumnIndex(MediaStore.Audio.Media.ALBUM_ID);
            int trackCol = cursor
                    .getColumnIndex(MediaStore.Audio.Media.TRACK);
            int durationCol = cursor
                    .getColumnIndex(MediaStore.Audio.Media.DURATION);

            do {
                long id = cursor.getLong(idCol);
                String title = cursor.getString(titleCol);

                String artist = cursor.getString(artistCol);

                String album = cursor.getString(albumCol);

                long albumId = cursor.getLong(albumIdCol);

                int track = cursor.getInt(trackCol);

                long duration = cursor.getLong(durationCol);


                mSongList.add(new Song(id, title, artist, album, albumId, track, duration));
            } while (cursor.moveToNext());

         /*   Collections.sort(mSongList, new Comparator<Song>() {

                @Override
                public int compare(Song lhs, Song rhs) {
                    Collator c = Collator.getInstance(Locale.getDefault());
                    c.setStrength(Collator.PRIMARY);
                    return c.compare(lhs.getTitle(), rhs.getTitle());
                }
            });*/

        }

        if (cursor != null) {
            cursor.close();
        }
        Log.e("test", "  d " + mSongList.size());

        return mSongList;
    }

    protected Uri getContentUri() {
        return MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
    }

    protected Cursor getSongCursor() {

        Uri musicUri = getContentUri();

        String selection = getSelectionString();
        String[] selectionArgs = getSelectionArgs();

        selection = DatabaseUtilsCompat.concatenateWhere(selection, MediaStore.Audio.Media.IS_MUSIC + " = 1");

        String fieldName = MediaStore.Audio.Media.TITLE;
        String filter = getFilter();
        return getCursor(musicUri, sProjection, selection, selectionArgs, fieldName, filter);
    }


}
app/src/main/java/com/andryr/musicplayer/utils/ThemeHelper.java
public class ThemeHelper {

    public static boolean isDarkThemeSelected(Context context) {

        String lightStr = context.getResources().getString(R.string.light);
        String darkStr = context.getResources().getString(R.string.dark);
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        String prefKey = context.getString(R.string.pref_theme_base_key);
        return prefs.getString(prefKey, lightStr).equals(darkStr);
    }

    public static int getStyleColor(Context context, int attr) {
        int[] attrs = {attr};

        TypedArray ta = context.getTheme().obtainStyledAttributes(attrs);


        return ta.getColor(0, Color.BLACK);
    }

    public static void tintDrawable(Context context, Drawable drawable) {

        if (drawable != null) {
            drawable.mutate().setColorFilter(getStyleColor(context, android.R.attr.textColorPrimary), PorterDuff.Mode.SRC_ATOP);
        }
    }

    public static void tintImageView(Context context, ImageView imageView) {
        if (imageView != null) {
            imageView.setColorFilter(getStyleColor(context, android.R.attr.textColorPrimary), PorterDuff.Mode.SRC_ATOP);
        }
    }

    public static void tintCompoundDrawables(Context context, TextView textView) {
        for (Drawable d : textView.getCompoundDrawables()) {
            tintDrawable(context, d);
        }
    }


    public static int getResourcesColor(Context context, int id) {
        return context.getResources().getColor(id);
    }
}
app/src/main/java/com/andryr/musicplayer/model/Song.java
public class Song {
    private long id;
    private String title;
    private String artist;
    private String album;
    private int trackNumber;
    private long albumId;
    private String genre;
    private long duration;

    public Song(long id, String title, String artist, String album, long albumId, int trackNumber, long duration) {
        super();
        this.id = id;
        this.title = title == null ? MediaStore.UNKNOWN_STRING : title;
        this.artist = artist == null ? MediaStore.UNKNOWN_STRING : artist;
        this.album = album == null ? MediaStore.UNKNOWN_STRING : album;
        this.albumId = albumId;
        this.trackNumber = trackNumber;
        this.duration = duration;

    }

    public long getId() {
        return id;
    }

    public String getAlbum() {
        return album;
    }

    public String getTitle() {
        return title;
    }

    public String getArtist() {
        return artist;
    }

    public long getAlbumId() {
        return albumId;
    }

    public int getTrackNumber() {
        return trackNumber;
    }

    public String getGenre() {
        return genre;
    }

    public void setGenre(String genre) {
        this.genre = genre;
    }

    public long getDuration() {
        return duration;
    }

    public void setDuration(long duration) {
        this.duration = duration;
    }
}
app/src/main/java/com/andryr/musicplayer/fragments/dialog/AlbumEditorDialog.java
public class AlbumEditorDialog extends DialogFragment {


    private static final String ARG_ID = "id";
    private static final String ARG_NAME = "name";
    private static final String ARG_ARTIST = "artist";
    private static final String ARG_YEAR = "year";
    private static final String ARG_TRACK_COUNT = "track_count";



    private Album mAlbum;


    private EditText mTitleEditText;
    private EditText mArtistEditText;
    private EditText mYearEditText;
    private OnEditionSuccessListener mListener;


    public AlbumEditorDialog() {
        // Required empty public constructor
    }

    public static AlbumEditorDialog newInstance(Album album) {
        AlbumEditorDialog fragment = new AlbumEditorDialog();
        Bundle args = new Bundle();
        args.putLong(ARG_ID, album.getId());
        args.putString(ARG_NAME, album.getAlbumName());
        args.putString(ARG_ARTIST, album.getArtistName());
        args.putInt(ARG_YEAR, album.getYear());
        args.putInt(ARG_TRACK_COUNT, album.getTrackCount());

        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle args = getArguments();
        if (args != null) {

            long id = args.getLong(ARG_ID);
            String title = args.getString(ARG_NAME);
            String artist = args.getString(ARG_ARTIST);
            int year = args.getInt(ARG_YEAR);
            int trackCount = args.getInt(ARG_TRACK_COUNT);

            mAlbum = new Album(id,title,artist,year,trackCount);


        }
    }


    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle(R.string.edit_tags);

        View dialogView = getActivity().getLayoutInflater().inflate(R.layout.fragment_album_editor_dialog, null);
        builder.setView(dialogView);

        mTitleEditText = (EditText) dialogView.findViewById(R.id.title);
        mArtistEditText = (EditText) dialogView.findViewById(R.id.artist);
        mYearEditText = (EditText) dialogView.findViewById(R.id.year);

        mTitleEditText.setText(mAlbum.getAlbumName());
        mArtistEditText.setText(mAlbum.getArtistName());
        mYearEditText.setText(String.valueOf(mAlbum.getYear()));


        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

                final Activity activity = getActivity();
                dismiss();

                new AsyncTask<Object,Object,Boolean>(){

                    @Override
                    protected Boolean doInBackground(Object... params) {
                        return saveTags(activity);
                    }

                    @Override
                    protected void onPostExecute(Boolean b) {
                        super.onPostExecute(b);
                        if (b) {
                            if(mListener != null)
                            {
                                mListener.onEditionSuccess();
                            }
                        }
                        else
                        {
                            Toast.makeText(getActivity(), R.string.tags_edition_failed, Toast.LENGTH_SHORT).show();

                        }


                    }
                }.execute();


            }
        }).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dismiss();
            }
        });


        return builder.create();
    }

    private boolean saveTags(Context context) {

        HashMap<String,String> data = new HashMap<>();

        data.put(MusicLibraryHelper.ALBUM_NAME, mTitleEditText.getText().toString());
        data.put(MusicLibraryHelper.ARTIST_NAME, mArtistEditText.getText().toString());
        data.put(MusicLibraryHelper.YEAR, mYearEditText.getText().toString());





        return MusicLibraryHelper.editAlbumData(context, mAlbum, data);

    }


    public void setOnEditionSuccessListener(OnEditionSuccessListener listener)
    {
        mListener = listener;
    }


    public interface OnEditionSuccessListener {


        void onEditionSuccess();
    }


}
app/src/main/java/com/andryr/musicplayer/images/ArtistImageCache.java
public class ArtistImageCache extends BitmapCache<String> {

    private static final LruCache<String, Bitmap> sLargeImageCache;


    private static final LruCache<String, Bitmap> sThumbCache;
    private static final String TAG = "ArtistImageCache";
    private static ArtistImageCache sInstance = null;

    static {


        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);


        sLargeImageCache = new LruCache<String, Bitmap>(maxMemory / 16) {


            @Override
            protected int sizeOf(String key, Bitmap bitmap) {

                return BitmapCompat.getAllocationByteCount(bitmap) / 1024;
            }
        };

        sThumbCache = new LruCache<String, Bitmap>(maxMemory / 8) {


            @Override
            protected int sizeOf(String key, Bitmap bitmap) {

                return BitmapCompat.getAllocationByteCount(bitmap) / 1024;
            }
        };
    }

    private final List<String> mUnavailableList = new ArrayList<>();
    private final ArtistImageDb mDatabase;
    private Context mContext;
    private int mLargeImageSize;

    private int mThumbSize;

    private ArtistImageCache(Context context) {
        super();

        mContext = context;

        mDatabase = new ArtistImageDb(mContext);

        final Resources res = mContext.getResources();
        mLargeImageSize = res.getDimensionPixelSize(R.dimen.artist_image_req_width);

        mThumbSize = res.getDimensionPixelSize(R.dimen.art_thumbnail_size);

    }

    public static void init(Context context) {
        sInstance = new ArtistImageCache(context);
    }

    public static ArtistImageCache getInstance() {

        return sInstance;
    }


    @Override
    public synchronized Bitmap getCachedBitmap(String artistName, int reqWidth, int reqHeight) {
        Bitmap b = null;
        if (reqWidth > mThumbSize || reqHeight > mThumbSize) {
            b = sLargeImageCache.get(artistName);
        }
        if (b == null) {
            b = sThumbCache.get(artistName);// il vaut mieux retourner une petite image que rien du tout
        }
        return b;

    }

    @Override
    public Bitmap retrieveBitmap(String artistName, int reqWidth, int reqHeight) {
        if (artistName == null || artistName.length() == 0) {
            return null;
        }


        final byte[] bytes = mDatabase.getArtistImageData(artistName);
        if (bytes != null) {
            Bitmap b = BitmapHelper.decode(bytes, reqWidth, reqHeight);
            if (b != null) {
                return b;
            }
        }

        try {
            return downloadImage(mContext, artistName, reqWidth, reqHeight);
        } catch (IOException e) {
            Log.e(TAG, "getNonCachedBitmap download", e);
        }
        return null;
    }

    public Bitmap downloadImage(final Context context, final String artistName, int reqWidth, int reqHeight) throws IOException {
        if (!Connectivity.isConnected(context) || !Connectivity.isWifi(context)) {

            throw new IOException("not connected to wifi");
        }

        if (mUnavailableList.contains(artistName)) {
            return null;
        }


        retrofit2.Response<ArtistInfo> response = LastFm.getArtistInfo(artistName).execute();
        ArtistInfo body = response.body();
        if (body != null) {
            final ArtistInfo.Artist info = body.getArtist();
            if (info != null && info.getImageList() != null && info.getImageList().size() > 0) {
                String imageUrl = null;
                for (Image image : info.getImageList()) {
                    if (image.getSize().equals("mega")) {
                        imageUrl = image.getUrl();
                        break;
                    }
                }
                if (imageUrl != null && !("".equals(imageUrl.trim()))) {
                    Bitmap bitmap = ImageDownloader.getInstance().download(imageUrl, mLargeImageSize, mLargeImageSize);
                    if (bitmap != null) {
                        save(info.getMbid(), artistName, bitmap);
                        return BitmapHelper.scale(bitmap, reqWidth, reqHeight);
                    } else {
                        mUnavailableList.add(artistName);
                    }
                }
            }
        }
        return null;


    }

    private void save(String mbid, String artistName, Bitmap image) {
        Log.d(TAG, "cached "+artistName);
        mDatabase.insertOrUpdate(mbid, artistName, image);
    }

    @Override
    protected synchronized void cacheBitmap(String artistName, Bitmap bitmap) {
        if (bitmap.getWidth() < mLargeImageSize || bitmap.getHeight() < mLargeImageSize) {
            sThumbCache.put(artistName, bitmap);
        } else {
            sLargeImageCache.put(artistName, bitmap);
        }
    }

    @Override
    protected Bitmap getDefaultBitmap() {
        return null;
    }

    @Override
    protected Drawable getDefaultDrawable(Context context, int reqWidth, int reqHeight) {
        if (reqWidth <= mThumbSize && reqHeight <= mThumbSize) {
            return ArtistImageHelper.getDefaultArtistThumb(context);
        } else {
            return ArtistImageHelper.getDefaultArtistImage(context);
        }
    }


    @Override
    public void clear() {
        clearDbCache();
        clearMemoryCache();
    }

    public void clearDbCache() {
        mDatabase.recreate();
    }

    public synchronized void clearMemoryCache() {
        sThumbCache.evictAll();
        sLargeImageCache.evictAll();
    }


}
app/src/main/java/com/andryr/musicplayer/model/Artist.java
public class Artist {

    private long id;
    private String name;
    private int albumCount;
    private int trackCount;

    public Artist(long id, String name, int albumCount, int trackCount) {
        super();
        this.id = id;
        this.name = name == null ? MediaStore.UNKNOWN_STRING : name;
        this.albumCount = albumCount;
        this.trackCount = trackCount;
    }

    public long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public int getAlbumCount() {
        return albumCount;
    }

    public int getTrackCount() {
        return trackCount;
    }

}
app/src/main/java/com/andryr/musicplayer/utils/Playlists.java
public class Playlists {

    public static Uri createPlaylist(ContentResolver resolver, String playlistName) {
        Uri uri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
        ContentValues values = new ContentValues();
        values.put(MediaStore.Audio.Playlists.NAME, playlistName);
        return resolver.insert(uri, values);
    }

    private static int getSongCount(ContentResolver resolver, Uri uri) {
        String[] cols = new String[]{"count(*)"};

        Cursor cur = resolver.query(uri, cols, null, null, null);
        cur.moveToFirst();
        final int count = cur.getInt(0);
        cur.close();
        return count;
    }

    private static void insert(ContentResolver resolver, Uri uri,
                               long songId, int index) {

        ContentValues values = new ContentValues();
        values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER,
                Integer.valueOf(index));
        values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, songId);
        resolver.insert(uri, values);

    }

    public static void addSongToPlaylist(ContentResolver resolver, long playlistId,
                                         long songId) {
        Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external",
                playlistId);
        final int base = getSongCount(resolver, uri);
        insert(resolver, uri, songId, base + 1);
    }

    public static void addAlbumToPlaylist(ContentResolver resolver, long playlistId,
                                          long albumId) {
        String cols[] = {MediaStore.Audio.Media._ID};

        Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external",
                playlistId);
        int index = getSongCount(resolver, uri) + 1;

        Uri musicUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;

        Cursor cursor = resolver.query(musicUri, cols,
                MediaStore.Audio.Media.ALBUM_ID + " = " + albumId, null, null);

        if (cursor != null && cursor.moveToFirst()) {


            do {
                int songId = cursor.getInt(0);
                insert(resolver, uri, songId, index);
                index++;
            } while (cursor.moveToNext());


        }

        if (cursor != null) {
            cursor.close();
        }
    }

    public static void removeFromPlaylist(ContentResolver resolver,
                                          long playlistId, long audioId) {
        Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external",
                playlistId);

        resolver.delete(uri, MediaStore.Audio.Playlists.Members.AUDIO_ID
                + " = " + audioId, null);
    }

    public static boolean moveItem(ContentResolver res, long playlistId,
                                   int from, int to) {
        Uri uri = MediaStore.Audio.Playlists.Members
                .getContentUri("external", playlistId).buildUpon()
                .appendEncodedPath(String.valueOf(from))
                .appendQueryParameter("move", "true").build();
        ContentValues values = new ContentValues();
        values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, to);
        return res.update(uri, values, null, null) != 0;
    }

}
app/src/main/java/com/andryr/musicplayer/images/ArtworkCache.java
public class ArtworkCache extends BitmapCache<Long> {
    private static final LruCache<Long, Bitmap> sLargeImageCache;


    private static final LruCache<Long, Bitmap> sThumbCache;
    private static final String TAG = "ArtworkCache";
    private static ArtworkCache sInstance;

    static {


        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

        final int cacheSize = maxMemory / 8;

        sLargeImageCache = new LruCache<Long, Bitmap>(cacheSize) {


            @Override
            protected int sizeOf(Long key, Bitmap bitmap) {

                return BitmapCompat.getAllocationByteCount(bitmap) / 1024;
            }

            @Override
            protected void entryRemoved(boolean evicted, Long key, Bitmap oldValue, Bitmap newValue) {
                super.entryRemoved(evicted, key, oldValue, newValue);
                //TODO recycler oldValue ?
            }
        };

        sThumbCache = new LruCache<Long, Bitmap>(cacheSize) {


            @Override
            protected int sizeOf(Long key, Bitmap bitmap) {

                return BitmapCompat.getAllocationByteCount(bitmap) / 1024;
            }
        };
    }

    private final List<String> mUnavailableList = new ArrayList<>();
    private final Context mContext;
    private int mLargeArtworkSize;
    private int mThumbSize;

    public ArtworkCache(Context context) {
        super();
        mContext = context;
        mLargeArtworkSize = context.getResources().getDimensionPixelSize(R.dimen.playback_activity_art_size);
        mThumbSize = context.getResources().getDimensionPixelSize(R.dimen.art_thumbnail_size);
    }

    public static void init(Context context) {
        sInstance = new ArtworkCache(context);
    }

    public static ArtworkCache getInstance() {
        return sInstance;
    }

    @Override
    public synchronized Bitmap getCachedBitmap(Long key, int reqWidth, int reqHeight) {
        if (key == -1 || PrefUtils.getInstance().useFreeArtworks()) {
            return null;
        }
        Bitmap b = null;
        if (reqWidth > mThumbSize || reqHeight > mThumbSize) {
            b = sLargeImageCache.get(key);
        }
        if (b == null) {
            b = sThumbCache.get(key);// il vaut mieux retourner une petite image que rien du tout
        }
        return b;
    }

    @Override
    protected Bitmap retrieveBitmap(Long key, int reqWidth, int reqHeight) {
        if (key == -1) {
            return null;
        }

        if (PrefUtils.getInstance().useFreeArtworks()) {
            return getFreeArtwork(reqWidth, reqHeight);
        }

        Uri uri = ContentUris.withAppendedId(ArtworkHelper.getArtworkUri(), key);

        try {
            if (uri != null) {
                ContentResolver res = mContext.getContentResolver();
                Bitmap bitmap = BitmapHelper.decode(res.openInputStream(uri), reqWidth, reqHeight);
                return bitmap;


            }
        } catch (IOException e) {
            Log.e(TAG, "get image from contentresolver", e);
        }

        try {
            return downloadArtwork(mContext, key, reqWidth, reqHeight);
        } catch (IOException e) {
            Log.e(TAG, "download", e);
        }

        return null;
    }

    private Bitmap getFreeArtwork(int reqWidth, int reqHeight) {
        try {
            return ImageDownloader.getInstance().download("http://lorempixel.com/600/600/abstract/", reqWidth, reqHeight);
        } catch (IOException e) {
            Log.e(TAG, "failed to download free artwork at http://lorempixel.com/600/600/abstract/", e);
        }
        return null;
    }

    @Override
    protected synchronized void cacheBitmap(Long key, Bitmap bitmap) {
        if (bitmap.getWidth() < mLargeArtworkSize || bitmap.getHeight() < mLargeArtworkSize) {
            sThumbCache.put(key, bitmap);
        } else {
            sLargeImageCache.put(key, bitmap);
        }
    }

    @Override
    protected Bitmap getDefaultBitmap() {
        return null;
    }

    @Override
    protected Drawable getDefaultDrawable(Context context, int reqWidth, int reqHeight) {
        if (reqWidth <= mThumbSize && reqHeight <= mThumbSize) {
            return ArtworkHelper.getDefaultThumbDrawable(context);
        } else {
            return ArtworkHelper.getDefaultArtworkDrawable(context);
        }
    }

    @Override
    public synchronized void clear() {
        sLargeImageCache.evictAll();


    }

    public Bitmap downloadArtwork(final Context context, final long albumId, int reqWidth, int reqHeight) throws IOException {
        if (!Connectivity.isConnected(context) || !Connectivity.isWifi(context)) {

            throw new IOException("not connected to wifi");
        }

        String albumName = null;
        String artistName = null;
        Album album = Albums.getAlbum(context, albumId);
        if (album != null) {
            albumName = album.getAlbumName();
            artistName = album.getArtistName();
        }
        if (mUnavailableList.contains(albumName)) {
            return null;
        }


        retrofit2.Response<AlbumInfo> response = LastFm.getAlbumInfo(albumName, artistName).execute();
        AlbumInfo body = response.body();
        if (body != null) {
            final AlbumInfo.Album info = body.getAlbum();
            if (info != null && info.getImageList() != null && info.getImageList().size() > 0) {
                String imageUrl = null;
                for (Image image : info.getImageList()) {
                    if (image.getSize().equals("mega")) {
                        imageUrl = image.getUrl();
                        break;
                    }
                }
                if (imageUrl != null && !("".equals(imageUrl.trim()))) {
                    Bitmap bitmap = ImageDownloader.getInstance().download(imageUrl, reqWidth, reqHeight);
                    if (bitmap != null) {
                        save(albumId, albumName, bitmap);
                        return bitmap;
                    } else {
                        mUnavailableList.add(albumName);
                    }
                }
            }
        }
        return null;


    }

    private void save(long albumId, String albumName, Bitmap bitmap) {
        try {
            ArtworkHelper.insertOrUpdate(mContext, albumId, albumName, bitmap);
        } catch (IOException e) {
            Log.e(TAG, "save", e);
        }
    }
}
app/src/main/java/com/andryr/musicplayer/adapters/BaseAdapter.java
public abstract class BaseAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {

    private OnItemClickListener mOnItemClickListener;

    public void setOnItemClickListener(OnItemClickListener listener)
    {
        mOnItemClickListener = listener;
    }

    protected void triggerOnItemClickListener(int position, View view)
    {
        if(mOnItemClickListener != null)
        {
            mOnItemClickListener.onItemClick(position, view);
        }
    }

    public interface OnItemClickListener {
        void onItemClick(int position, View view);
    }
}
app/src/main/java/com/andryr/musicplayer/model/Album.java
public class Album {

    private long id;
    private String albumName;
    private String artistName;
    private int year;
    private int trackCount;

    public Album(long id, String albumName, String artistName, int year, int trackCount) {
        super();
        this.id = id;
        this.albumName = albumName == null ? MediaStore.UNKNOWN_STRING : albumName;
        this.artistName = artistName == null ? MediaStore.UNKNOWN_STRING : artistName;
        this.year = year;
        this.trackCount = trackCount;
    }

    public long getId() {
        return id;
    }

    public String getAlbumName() {
        return albumName;
    }

    public String getArtistName() {
        return artistName;
    }

    public int getYear() {
        return year;
    }

    public int getTrackCount() {
        return trackCount;
    }


}
app/src/main/java/com/andryr/musicplayer/fragments/dialog/ID3TagEditorDialog.java
public class ID3TagEditorDialog extends DialogFragment {

    private static final String ARG_ID = "id";
    private static final String ARG_TITLE = "title";
    private static final String ARG_ARTIST = "artist";
    private static final String ARG_ALBUM = "album";
    private static final String ARG_ALBUM_ID = "album_id";
    private static final String ARG_TRACK_NUMBER = "track_number";


    private Song mSong;


    private EditText mTitleEditText;
    private EditText mArtistEditText;
    private EditText mAlbumEditText;
    private EditText mTrackEditText;
    private EditText mGenreEditText;
    private OnTagsEditionSuccessListener mListener;


    public ID3TagEditorDialog() {
        // Required empty public constructor
    }

    public static ID3TagEditorDialog newInstance(Song song) {
        ID3TagEditorDialog fragment = new ID3TagEditorDialog();
        Bundle args = new Bundle();
        args.putLong(ARG_ID, song.getId());
        args.putString(ARG_TITLE, song.getTitle());
        args.putString(ARG_ARTIST, song.getArtist());
        args.putString(ARG_ALBUM, song.getAlbum());
        args.putLong(ARG_ALBUM_ID, song.getAlbumId());
        args.putInt(ARG_TRACK_NUMBER, song.getTrackNumber());
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle args = getArguments();
        if (args != null) {

            long id = args.getLong(ARG_ID);
            String title = args.getString(ARG_TITLE);
            String artist = args.getString(ARG_ARTIST);
            String album = args.getString(ARG_ALBUM);
            long albumId = args.getLong(ARG_ALBUM_ID);
            int trackNumber = args.getInt(ARG_TRACK_NUMBER);
            mSong = new Song(id, title, artist, album, albumId, trackNumber, 0);


        }
    }


    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle(R.string.edit_tags);

        mSong.setGenre(MusicLibraryHelper.getSongGenre(getActivity(), mSong.getId()));//TODO récupérer le genre de manière asynchrone ??
        View dialogView = getActivity().getLayoutInflater().inflate(R.layout.fragment_id3_tag_editor_dialog, null);
        builder.setView(dialogView);

        mTitleEditText = (EditText) dialogView.findViewById(R.id.title);
        mArtistEditText = (EditText) dialogView.findViewById(R.id.artist);
        mAlbumEditText = (EditText) dialogView.findViewById(R.id.album);
        mTrackEditText = (EditText) dialogView.findViewById(R.id.track_number);
        mGenreEditText = (EditText) dialogView.findViewById(R.id.genre);

        mTitleEditText.setText(mSong.getTitle());
        mArtistEditText.setText(mSong.getArtist());
        mAlbumEditText.setText(mSong.getAlbum());
        mTrackEditText.setText(String.valueOf(mSong.getTrackNumber()));
        mGenreEditText.setText(mSong.getGenre());


        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

                final Activity activity = getActivity();
                dismiss();

                new AsyncTask<Object,Object,Boolean>(){

                    @Override
                    protected Boolean doInBackground(Object... params) {
                        return saveTags(activity);
                    }

                    @Override
                    protected void onPostExecute(Boolean b) {
                        super.onPostExecute(b);
                        if (b) {
                            if(mListener != null)
                            {
                                mListener.onTagsEditionSuccess();
                            }
                        }
                        else
                        {
                            Toast.makeText(getContext(),R.string.tags_edition_failed,Toast.LENGTH_SHORT).show();

                        }


                    }
                }.execute();


            }
        }).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dismiss();
            }
        });


        return builder.create();
    }

    private boolean saveTags(Context context) {

        HashMap<String,String> tags = new HashMap<>();

        tags.put(MusicLibraryHelper.TITLE, mTitleEditText.getText().toString());
        tags.put(MusicLibraryHelper.ARTIST, mArtistEditText.getText().toString());
        tags.put(MusicLibraryHelper.ALBUM, mAlbumEditText.getText().toString());
        tags.put(MusicLibraryHelper.TRACK, mTrackEditText.getText().toString());
        tags.put(MusicLibraryHelper.GENRE, mGenreEditText.getText().toString());




        return MusicLibraryHelper.editSongTags(context, mSong, tags);

    }


    public void setOnTagsEditionSuccessListener(OnTagsEditionSuccessListener listener)
    {
        mListener = listener;
    }


    public interface OnTagsEditionSuccessListener {


        void onTagsEditionSuccess();
    }


}
app/src/main/java/com/andryr/musicplayer/model/Playlist.java
public class Playlist {
    private long id;
    private String name;

    public Playlist(long id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    public long getId() {
        return id;
    }

    public String getName() {
        return name;
    }


}
app/src/main/java/com/andryr/musicplayer/fragments/dialog/PlaylistPicker.java
public class PlaylistPicker extends DialogFragment {

    private static final String[] sProjection = {
            MediaStore.Audio.Playlists._ID, MediaStore.Audio.Playlists.NAME};

    private RecyclerView mRecyclerView;

    private PlaylistListAdapter mAdapter;

    private OnPlaylistPickedListener mListener;

    private LoaderCallbacks<Cursor> mLoaderCallbacks = new LoaderCallbacks<Cursor>() {

        @Override
        public void onLoaderReset(Loader<Cursor> loader) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
            List<Playlist> list = new ArrayList<>();
            if (cursor != null && cursor.moveToFirst()) {
                int idCol = cursor.getColumnIndex(MediaStore.Audio.Genres._ID);
                int nameCol = cursor
                        .getColumnIndex(MediaStore.Audio.Genres.NAME);

                do {
                    long id = cursor.getLong(idCol);
                    String name = cursor.getString(nameCol);
                    list.add(new Playlist(id, name));
                } while (cursor.moveToNext());

                Collections.sort(list, new Comparator<Playlist>() {

                    @Override
                    public int compare(Playlist lhs, Playlist rhs) {
                        Collator c = Collator.getInstance(Locale.getDefault());
                        c.setStrength(Collator.PRIMARY);
                        return c.compare(lhs.getName(), rhs.getName());
                    }
                });

            }

            mAdapter.setData(list);

        }

        @Override
        public Loader<Cursor> onCreateLoader(int id, Bundle args) {

            Uri playlistsUri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;

            CursorLoader loader = new CursorLoader(getActivity(), playlistsUri,
                    sProjection, null, null, null);

            return loader;
        }
    };
    private OnClickListener mOnClickListener = new OnClickListener() {

        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.new_playlist:
                    CreatePlaylistDialog dialog = CreatePlaylistDialog.newInstance();
                    dialog.setOnPlaylistCreatedListener(new CreatePlaylistDialog.OnPlaylistCreatedListener() {
                        @Override
                        public void onPlaylistCreated() {
                            refresh();
                        }
                    });
                    dialog.show(getChildFragmentManager(), "create_playlist");
                    break;
            }


        }
    };
    private BaseAdapter.OnItemClickListener mOnItemClickListener = new BaseAdapter.OnItemClickListener() {
        @Override
        public void onItemClick(int position, View view) {
            Playlist playlist = mAdapter.getItem(position);

            if (mListener != null) {
                mListener.onPlaylistPicked(playlist);
            }

            dismiss();
        }
    };

    public PlaylistPicker() {
        // Required empty public constructor
    }

    public static PlaylistPicker newInstance() {
        PlaylistPicker fragment = new PlaylistPicker();

        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        getLoaderManager().initLoader(0, null, mLoaderCallbacks);
    }


    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        android.support.v7.app.AlertDialog.Builder builder = new android.support.v7.app.AlertDialog.Builder(getActivity(), getTheme());
        mAdapter = new PlaylistListAdapter();
        mAdapter.setOnItemClickListener(mOnItemClickListener);

        builder.setTitle(R.string.choose_playlist);

        View rootView = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_playlist_picker, null);
        mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

        mRecyclerView.setAdapter(mAdapter);


        Button newPlaylistButton = (Button) rootView.findViewById(R.id.new_playlist);
        newPlaylistButton.setOnClickListener(mOnClickListener);
        ThemeHelper.tintCompoundDrawables(getActivity(), newPlaylistButton);

        builder.setView(rootView);
        return builder.create();
    }


    public void refresh() {
        getLoaderManager().restartLoader(0, null, mLoaderCallbacks);

    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

    }

    @Override
    public void onDetach() {
        super.onDetach();
    }

    public void setListener(OnPlaylistPickedListener listener) {
        mListener = listener;
    }

    public interface OnPlaylistPickedListener {
        void onPlaylistPicked(Playlist playlist);
    }


}
app/src/main/java/com/andryr/musicplayer/MainActivity.java
public class MainActivity extends AppCompatActivity {
    public static final String ALBUM_ID = "id";
    public static final String ALBUM_NAME = "name";
    public static final String ALBUM_ARTIST = "artist";
    public static final String ALBUM_YEAR = "year";
    public static final String ALBUM_TRACK_COUNT = "track_count";
    public static final String ARTIST_ARTIST_ID = "artist_id";
    public static final String ARTIST_ARTIST_NAME = "artist_name";
    public static final String ARTIST_ALBUM_COUNT = "album_count";
    public static final String ARTIST_TRACK_COUNT = "track_count";
    public static final String SONG_ID = "song_id";
    public static final String SONG_TITLE = "song_title";
    public static final String SONG_ARTIST = "song_artist";
    public static final String SONG_ALBUM = "song_album";
    public static final String SONG_ALBUM_ID = "song_album_id";
    public static final String SONG_TRACK_NUMBER = "song_track_number";
    private static final String SONG_DURATION = "song_duration";

    public static final String ACTION_REFRESH = "resfresh";
    public static final String ACTION_SHOW_ALBUM = "show_album";
    public static final String ACTION_SHOW_ARTIST = "show_artist";
    public static final String ACTION_PLAY_SONG = "play_song";
    public static final String ACTION_ADD_TO_QUEUE = "add_to_queue";
    public static final String ACTION_SET_AS_NEXT_TRACK = "set_as_next_track";

    private static final int SEARCH_ACTIVITY = 234;

    private static final int PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1;
    private static final int PERMISSIONS_REQUEST_READ_PHONE_STATE = 2;
    private static final int PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 3;

    private Intent mOnActivityResultIntent;
    private PlaybackService mPlaybackService;
    private Intent mServiceIntent;
    private boolean mServiceBound = false;

    private ProgressBar mProgressBar;
    private Handler mHandler = new Handler();

    private int mThumbSize;


    private PlaybackRequests mPlaybackRequests;
    private OnClickListener mOnClickListener = new OnClickListener() {

        @Override
        public void onClick(View v) {

            if (mPlaybackService == null) {
                return;
            }
            switch (v.getId()) {
                case R.id.play_pause_toggle:
                case R.id.quick_play_pause_toggle:

                    mPlaybackService.toggle();

                    break;
                case R.id.quick_prev:
                case R.id.prev:
                    mPlaybackService.playPrev(true);

                    break;
                case R.id.quick_next:
                case R.id.next:
                    mPlaybackService.playNext(true);
                    break;


                case R.id.action_equalizer:
                    NavigationUtils.showEqualizer(MainActivity.this);
                    break;
                case R.id.track_info:
                    NavigationUtils.showPlaybackActivity(MainActivity.this);
                    break;


            }

        }
    };
    private Runnable mUpdateProgressBar = new Runnable() {

        @Override
        public void run() {


            updateProgressBar();


            mHandler.postDelayed(mUpdateProgressBar, 1000);

        }
    };
    private NavigationView mNavigationView;
    private DrawerLayout mDrawerLayout;
    private ServiceConnection mServiceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

            PlaybackService.PlaybackBinder binder = (PlaybackBinder) service;
            mPlaybackService = binder.getService();
            mServiceBound = true;

            mPlaybackRequests.sendRequests();

            updateAll();
         /*   if (!mPlaybackService.isPlaying()
                    && !mPlaybackService.hasPlaylist()) {

                List<Song> playList = getDefaultPlaylist();
                Log.d("playlist", String.valueOf(playList == null));
                if (playList != null) {
                    Log.d("playlist", String.valueOf(playList.size()));

                    int pos = (int) (Math.random() * (playList.size() - 1));
                    Log.d("playlist", String.valueOf(pos));

                    mPlaybackService.setPlayList(playList, pos, false);
                }

            }*/

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mServiceBound = false;

        }
    };
    private BroadcastReceiver mServiceListener = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (mPlaybackService == null) {
                return;
            }
            String action = intent.getAction();
            Log.d("action", action);
            if (action.equals(PlaybackService.PLAYSTATE_CHANGED)) {
                setButtonDrawable();
                if (mPlaybackService.isPlaying()) {
                    mHandler.post(mUpdateProgressBar);
                } else {
                    mHandler.removeCallbacks(mUpdateProgressBar);
                }


            } else if (action.equals(PlaybackService.META_CHANGED)) {
                updateTrackInfo();
            }

        }
    };


    /**
     * Handler for the sleep timer dialog
     */
    private HmsPickerDialogFragment.HmsPickerDialogHandler mHmsPickerHandler = new HmsPickerDialogFragment.HmsPickerDialogHandler() {
        @Override
        public void onDialogHmsSet(int reference, int hours, int minutes, int seconds) {
            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
            SleepTimer.setTimer(MainActivity.this, prefs, hours * 3600 + minutes * 60 + seconds);
        }
    };


    private DialogInterface.OnClickListener mSleepTimerDialogListener = new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            switch(which) {
                case DialogInterface.BUTTON_POSITIVE: // set a new timer
                    DialogUtils.showSleepHmsPicker(MainActivity.this, mHmsPickerHandler);
                    break;
                case DialogInterface.BUTTON_NEGATIVE: // cancel the current timer
                    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
                    SleepTimer.cancelTimer(MainActivity.this, prefs);
                    break;
                case DialogInterface.BUTTON_NEUTRAL: // just go back
                    break;

            }
        }
    };

    public DrawerLayout getDrawerLayout() {
        return mDrawerLayout;
    }

  /*  private List<Song> getDefaultPlaylist() {
        ContentResolver resolver = getContentResolver();
        Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        String[] projection = {MediaStore.Audio.Media._ID,
                MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.ARTIST,
                MediaStore.Audio.Media.ALBUM, MediaStore.Audio.Media.ALBUM_ID,
                MediaStore.Audio.Media.ARTIST_ID, MediaStore.Audio.Media.TRACK};
        Cursor cursor = resolver.query(musicUri, projection, null, null,
                android.provider.MediaStore.Audio.Media.TITLE);

        List<Song> songList = new ArrayList<>();
        if (cursor != null && cursor.moveToFirst()) {
            int idCol = cursor
                    .getColumnIndex(MediaStore.Audio.Playlists.Members.AUDIO_ID);
            if (idCol == -1) {
                idCol = cursor.getColumnIndex(MediaStore.Audio.Media._ID);
            }
            int titleCol = cursor
                    .getColumnIndex(MediaStore.Audio.Media.TITLE);
            int artistCol = cursor
                    .getColumnIndex(MediaStore.Audio.Media.ARTIST);
            int albumCol = cursor
                    .getColumnIndex(MediaStore.Audio.Media.ALBUM);
            int albumIdCol = cursor
                    .getColumnIndex(MediaStore.Audio.Media.ALBUM_ID);
            int trackCol = cursor
                    .getColumnIndex(MediaStore.Audio.Media.TRACK);

            do {
                long id = cursor.getLong(idCol);
                String title = cursor.getString(titleCol);

                String artist = cursor.getString(artistCol);

                String album = cursor.getString(albumCol);

                long albumId = cursor.getLong(albumIdCol);

                int track = cursor.getInt(trackCol);


                songList.add(new Song(id, title, artist, album, albumId, track));
            } while (cursor.moveToNext());
        }
        if (cursor != null) {
            cursor.close();
        }
        return songList;

    }*/

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setTheme();

        super.onCreate(savedInstanceState);

        setVolumeControlStream(AudioManager.STREAM_MUSIC);

        setContentView(R.layout.activity_main);


        mThumbSize = getResources().getDimensionPixelSize(R.dimen.art_thumbnail_size);


        mPlaybackRequests = new PlaybackRequests();

        if (savedInstanceState == null) {
            showLibrary();
        }


        findViewById(R.id.quick_play_pause_toggle).setOnClickListener(
                mOnClickListener);

        findViewById(R.id.track_info).setOnClickListener(mOnClickListener);

        findViewById(R.id.quick_prev).setOnClickListener(mOnClickListener);
        findViewById(R.id.quick_next).setOnClickListener(mOnClickListener);


        mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);

        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mNavigationView = (NavigationView) findViewById(R.id.navigation_view);
        mNavigationView.inflateHeaderView(R.layout.navigation_header);
        mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(MenuItem menuItem) {
                mDrawerLayout.closeDrawers();
                switch (menuItem.getItemId()) {
                   /* case R.id.action_home:
                        showHome();
                        break;*/
                    case R.id.action_library:
                        showLibrary();
                        break;
                    case R.id.action_favorites:
                        showFavorites();
                        break;
                    case R.id.action_equalizer:
                        NavigationUtils.showEqualizer(MainActivity.this);
                        break;
                    case R.id.action_settings:
                        NavigationUtils.showPreferencesActivity(MainActivity.this);
                        break;
                }
                return true;
            }
        });
        checkPermissions();

    }

    private void setTheme() {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);

        boolean dark = ThemeHelper.isDarkThemeSelected(this);
        String prefKey = getString(R.string.pref_theme_key);
        int theme = prefs.getInt(prefKey, ThemePreference.DEFAULT_THEME);

        switch (theme) {
            case ThemePreference.DARK_BLUE_GREY_THEME:
                if (dark) {
                    setTheme(R.style.MainActivityDarkBlueGreyDark);
                } else {
                    setTheme(R.style.MainActivityDarkBlueGreyLight);
                }
                break;
            case ThemePreference.BLUE_GREY_THEME:
                if (dark) {
                    setTheme(R.style.MainActivityBlueGreyDark);
                } else {
                    setTheme(R.style.MainActivityBlueGreyLight);
                }
                break;
            case ThemePreference.BLUE_THEME:
                if (dark) {
                    setTheme(R.style.MainActivityBlueDark);
                } else {
                    setTheme(R.style.MainActivityBlueLight);
                }
                break;
        }
    }

    /**
     * Affiche bibliothèque sans backstack
     */
    public void showLibrary() {
        mNavigationView = (NavigationView) findViewById(R.id.navigation_view);

        mNavigationView.getMenu().findItem(R.id.action_library).setChecked(true);
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, LibraryFragment.newInstance()).commit();
    }

    /**
     * Afficher favoris sans backstack
     */
    public void showFavorites() {
        mNavigationView = (NavigationView) findViewById(R.id.navigation_view);

        mNavigationView.getMenu().findItem(R.id.action_favorites).setChecked(true);
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, PlaylistFragment.newFavoritesFragment()).commit();
    }

    private void checkPermissions() {
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.READ_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {

            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.READ_EXTERNAL_STORAGE)) {

                DialogUtils.showPermissionDialog(this, getString(R.string.permission_read_external_storage), new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ActivityCompat.requestPermissions(MainActivity.this,
                                new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                                PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
                    }
                });

            } else {


                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                        PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);


            }
        }

        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {

            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

                DialogUtils.showPermissionDialog(this, getString(R.string.permission_write_external_storage), new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ActivityCompat.requestPermissions(MainActivity.this,
                                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                                PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);
                    }
                });

            } else {


                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                        PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);


            }
        }

        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.READ_PHONE_STATE)
                != PackageManager.PERMISSION_GRANTED) {

            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.READ_PHONE_STATE)) {

                DialogUtils.showPermissionDialog(this, getString(R.string.permission_read_phone_state), new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ActivityCompat.requestPermissions(MainActivity.this,
                                new String[]{Manifest.permission.READ_PHONE_STATE},
                                PERMISSIONS_REQUEST_READ_PHONE_STATE);
                    }
                });

            } else {


                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.READ_PHONE_STATE},
                        PERMISSIONS_REQUEST_READ_PHONE_STATE);


            }
        }
    }

    @Override

    protected void onStop() {


        super.onStop();
    }

   /* private void showHome() {
        mNavigationView = (NavigationView) findViewById(R.id.navigation_view);

        mNavigationView.getMenu().findItem(R.id.action_home).setChecked(true);
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, HomeFragment.newInstance()).commit();
    }*/

    @Override
    protected void onPostResume() {
        super.onPostResume();
        if (mOnActivityResultIntent != null) {
            Bundle bundle = mOnActivityResultIntent.getExtras();
            if (mOnActivityResultIntent.getAction().equals(ACTION_REFRESH)) {
                refresh();
            } else if (mOnActivityResultIntent.getAction().equals(ACTION_SHOW_ALBUM)) {
                Album album = getAlbumFromBundle(bundle);
                AlbumFragment fragment = AlbumFragment.newInstance(album);
                setFragment(fragment);
            } else if (mOnActivityResultIntent.getAction().equals(ACTION_SHOW_ARTIST)) {
                Artist artist = getArtistFromBundle(bundle);
                ArtistFragment fragment = ArtistFragment.newInstance(artist);
                setFragment(fragment);
            } else {


                Song song = getSongFromBundle(bundle);

                if (mOnActivityResultIntent.getAction().equals(ACTION_PLAY_SONG)) {
                    ArrayList<Song> songList = new ArrayList<>();
                    songList.add(song);
                    mPlaybackRequests.requestPlayList(songList, 0, true);
                } else if (mOnActivityResultIntent.getAction().equals(ACTION_ADD_TO_QUEUE)) {
                    mPlaybackRequests.requestAddToQueue(song);
                } else if (mOnActivityResultIntent.getAction().equals(ACTION_SET_AS_NEXT_TRACK)) {
                    mPlaybackRequests.requestAsNextTrack(song);
                }


            }
            mOnActivityResultIntent = null;
        }
    }

    public void refresh() {
        for (Fragment f : getSupportFragmentManager().getFragments()) {
            if (f != null) {
                Log.d("frag", f.getClass().getCanonicalName());
                ((BaseFragment) f).load();
            }
        }
    }

    private Album getAlbumFromBundle(Bundle bundle) {
        long id = bundle.getLong(ALBUM_ID);
        String title = bundle.getString(ALBUM_NAME);
        String artist = bundle.getString(ALBUM_ARTIST);
        int year = bundle.getInt(ALBUM_YEAR);
        int trackCount = bundle.getInt(ALBUM_TRACK_COUNT);

        return new Album(id, title, artist, year, trackCount);
    }

    public void setFragment(Fragment f) {
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, f).addToBackStack(null).commit();
    }

    private Artist getArtistFromBundle(Bundle bundle) {
        long id = bundle.getLong(ARTIST_ARTIST_ID);
        String name = bundle.getString(ARTIST_ARTIST_NAME);
        int albumCount = bundle.getInt(ARTIST_ALBUM_COUNT);
        int trackCount = bundle.getInt(ARTIST_TRACK_COUNT);
        return new Artist(id, name, albumCount, trackCount);
    }

    private Song getSongFromBundle(Bundle bundle) {
        long id = bundle.getLong(SONG_ID);
        String title = bundle.getString(SONG_TITLE);
        String artist = bundle.getString(SONG_ARTIST);
        String album = bundle.getString(SONG_ALBUM);
        long albumId = bundle.getLong(SONG_ALBUM_ID);
        int trackNumber = bundle.getInt(SONG_TRACK_NUMBER);
        long duration = bundle.getLong(SONG_DURATION);


        return new Song(id, title, artist, album, albumId, trackNumber, duration);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // unbindService(mServiceConnection);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        switch (id) {
            case android.R.id.home:
                FragmentManager fm = getSupportFragmentManager();
                if (fm.getBackStackEntryCount() > 0) {
                    fm.popBackStack();
                } else {
                    showLibrary();
                }
                return true;
            case R.id.action_search:
                NavigationUtils.showSearchActivity(this, SEARCH_ACTIVITY);
                return true;
            case R.id.action_equalizer:
                NavigationUtils.showEqualizer(this);
                return true;
            case R.id.action_preferences:
                NavigationUtils.showPreferencesActivity(this);
                break;
            case R.id.action_sleep_timer:
                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
                if (SleepTimer.isTimerSet(prefs)) {
                    DialogUtils.showSleepTimerDialog(this, mSleepTimerDialogListener);
                } else {
                    DialogUtils.showSleepHmsPicker(this, mHmsPickerHandler);
                }
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    public void onSongSelected(List<Song> songList, int position) {
        if (mPlaybackService == null) {
            return;
        }
        mPlaybackService.setPlayList(songList, position, true);
        // mPlaybackService.play();

    }

    public void onShuffleRequested(List<Song> songList, boolean play) {
        if (mPlaybackService == null) {
            return;
        }
        mPlaybackService.setPlayListAndShuffle(songList, play);


    }

    public void addToQueue(Song song) {
        if (mPlaybackService != null) {
            mPlaybackService.addToQueue(song);
        }

    }

    public void setAsNextTrack(Song song) {
        if (mPlaybackService != null) {
            mPlaybackService.setAsNextTrack(song);
        }

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == SEARCH_ACTIVITY && resultCode == RESULT_OK) {
            mOnActivityResultIntent = data;

        }
    }

    @Override
    protected void onPause() {
        super.onPause();

        if (mServiceBound) {
            mPlaybackService = null;

            unregisterReceiver(mServiceListener);

            unbindService(mServiceConnection);
            mServiceBound = false;
        }
        mHandler.removeCallbacks(mUpdateProgressBar);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (!mServiceBound) {
            mServiceIntent = new Intent(this, PlaybackService.class);
            bindService(mServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
            startService(mServiceIntent);
            IntentFilter filter = new IntentFilter();
            filter.addAction(PlaybackService.META_CHANGED);
            filter.addAction(PlaybackService.PLAYSTATE_CHANGED);
            filter.addAction(PlaybackService.POSITION_CHANGED);
            filter.addAction(PlaybackService.ITEM_ADDED);
            filter.addAction(PlaybackService.ORDER_CHANGED);
            registerReceiver(mServiceListener, filter);
        } else {
            updateAll();
        }
    }

    @Override
    protected void onStart() {
        super.onStart();


        // if (!mServiceBound) {
        // mServiceIntent = new Intent(this, PlaybackService.class);
        // bindService(mServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
        // startService(mServiceIntent);
        // }

    }

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        switch (requestCode) {
            case PERMISSIONS_REQUEST_READ_PHONE_STATE:
                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
                SharedPreferences.Editor editor = prefs.edit();
                editor.putBoolean(PlaybackService.PREF_AUTO_PAUSE, true);
                if (mPlaybackService != null) {
                    mPlaybackService.setAutoPauseEnabled(true);
                }
                editor.commit();
                break;

        }
    }

    private void updateAll() {
        if (mPlaybackService != null) {
            Log.d("playlist", "hasplaylist " + mPlaybackService.hasPlaylist());
            updateTrackInfo();
            setButtonDrawable();
            if (mPlaybackService.isPlaying()) {
                mHandler.post(mUpdateProgressBar);
            }


        }
    }

    private void updateTrackInfo() {
        View trackInfoLayout = findViewById(R.id.track_info);

        if (mPlaybackService != null && mPlaybackService.hasPlaylist()) {

            if (trackInfoLayout.getVisibility() != View.VISIBLE) {
                trackInfoLayout.setVisibility(View.VISIBLE);
                trackInfoLayout.startAnimation(AnimationUtils.loadAnimation(this, R.anim.abc_grow_fade_in_from_bottom));
            }
            String title = mPlaybackService.getSongTitle();
            String artist = mPlaybackService.getArtistName();
            if (title != null) {
                ((TextView) findViewById(R.id.song_title)).setText(title);

            }
            if (artist != null) {
                ((TextView) findViewById(R.id.song_artist)).setText(artist);
            }

            long albumId = mPlaybackService.getAlbumId();
            final ImageView minArtworkView = (ImageView) findViewById(R.id.artwork_min);
            ArtworkCache.getInstance().loadBitmap(albumId, minArtworkView, mThumbSize, mThumbSize);


            int duration = mPlaybackService.getTrackDuration();
            if (duration != -1) {
                mProgressBar.setMax(duration);

                updateProgressBar();
            }


        } else {
            trackInfoLayout.setVisibility(View.GONE);
        }
    }

    private void setButtonDrawable() {
        if (mPlaybackService != null) {
            ImageButton quickButton = (ImageButton) findViewById(R.id.quick_play_pause_toggle);
            if (mPlaybackService.isPlaying()) {
                quickButton.setImageResource(R.drawable.ic_pause);
            } else {
                quickButton.setImageResource(R.drawable.ic_play_small);
            }
        }

    }


    private void updateProgressBar() {
        if (mPlaybackService != null) {
            int position = mPlaybackService.getPlayerPosition();
            mProgressBar.setProgress(position);


        }
    }

    private class PlaybackRequests {

        private List<Song> mPlayList;
        private int mIndex;
        private boolean mAutoPlay;

        private Song mNextTrack;

        private Song mAddToQueue;

        private void requestPlayList(List<Song> playList, int index, boolean autoPlay) {
            if (mPlaybackService != null) {
                mPlaybackService.setPlayList(playList, 0, true);
            } else {
                mPlayList = playList;
                mIndex = index;
                mAutoPlay = autoPlay;
            }
        }


        public void requestAddToQueue(Song song) {
            if (mPlaybackService != null) {
                mPlaybackService.addToQueue(song);
            } else {
                mAddToQueue = song;
            }
        }

        public void requestAsNextTrack(Song song) {
            if (mPlaybackService != null) {
                mPlaybackService.setAsNextTrack(song);
            } else {
                mNextTrack = song;
            }
        }

        public void sendRequests() {
            if (mPlaybackService == null) {
                return;
            }

            if (mPlayList != null) {
                mPlaybackService.setPlayList(mPlayList, mIndex, mAutoPlay);
                mPlayList = null;
            }

            if (mAddToQueue != null) {
                mPlaybackService.addToQueue(mAddToQueue);
                mAddToQueue = null;
            }

            if (mNextTrack != null) {
                mPlaybackService.setAsNextTrack(mNextTrack);
                mNextTrack = null;
            }
        }
    }

}
app/src/main/java/com/andryr/musicplayer/adapters/AlbumListAdapter.java
public class AlbumListAdapter extends BaseAdapter<AlbumListAdapter.AlbumViewHolder>
        implements FastScroller.SectionIndexer {

    private final int mArtworkWidth;
    private final int mArtworkHeight;
    private final Context mContext;
    private int mLayoutId = R.layout.album_grid_item;
    private List<Album> mAlbumList = Collections.emptyList();


    public AlbumListAdapter(Context context, int artworkWidth, int artworkHeight) {
        mArtworkWidth = artworkWidth;
        mArtworkHeight = artworkHeight;
        mContext = context;
    }

    public void setData(List<Album> data) {
        mAlbumList = data;
        notifyDataSetChanged();
    }

    public void setLayoutId(int layoutId) {
        mLayoutId = layoutId;
    }

    @Override
    public AlbumViewHolder onCreateViewHolder(ViewGroup parent, int type) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(
                mLayoutId, parent, false);


        return new AlbumViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(AlbumViewHolder viewHolder, int position) {
        Album album = mAlbumList.get(position);
        viewHolder.vName.setText(album.getAlbumName());
        if (mLayoutId != R.layout.small_album_grid_item) {
            viewHolder.vArtist.setText(album.getArtistName());
        }

        //évite de charger des images dans les mauvaises vues si elles sont recyclées
        viewHolder.vArtwork.setTag(position);

        ArtworkCache.getInstance().loadBitmap(album.getId(), viewHolder.vArtwork, mArtworkWidth, mArtworkHeight, ArtworkHelper.getDefaultArtworkDrawable(mContext));


    }

    @Override
    public int getItemCount() {
        return mAlbumList.size();
    }

    @Override
    public String getSectionForPosition(int position) {
        String name = getItem(position).getAlbumName();
        if (name.length() > 0) {
            return name.substring(0, 1);
        }

        return "";
    }

    public Album getItem(int position) {
        return mAlbumList.get(position);
    }

    class AlbumViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        ImageView vArtwork;
        TextView vName;
        TextView vArtist;

        public AlbumViewHolder(View itemView) {
            super(itemView);
            vArtwork = (ImageView) itemView.findViewById(R.id.album_artwork);
            vName = (TextView) itemView.findViewById(R.id.album_name);
            vArtwork.setOnClickListener(this);
            if (mLayoutId != R.layout.small_album_grid_item) {
                vArtist = (TextView) itemView.findViewById(R.id.artist_name);
                itemView.findViewById(R.id.album_info).setOnClickListener(this);
            } else {
                vName.setOnClickListener(this);
            }
            ImageButton menuButton = (ImageButton) itemView.findViewById(R.id.menu_button);
            menuButton.setOnClickListener(this);

            Drawable drawable = menuButton.getDrawable();

            drawable.mutate();
            ThemeHelper.tintDrawable(itemView.getContext(), drawable);

        }

        @Override
        public void onClick(View v) {
            int position = getAdapterPosition();

            triggerOnItemClickListener(position, v);
        }
    }
}


Question: import android.app.Activity;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import com.andryr.musicplayer.MainActivity;
import com.andryr.musicplayer.R;
import com.andryr.musicplayer.adapters.AlbumListAdapter;
import com.andryr.musicplayer.adapters.BaseAdapter;
import com.andryr.musicplayer.fragments.dialog.AlbumEditorDialog;
import com.andryr.musicplayer.fragments.dialog.ID3TagEditorDialog;
import com.andryr.musicplayer.fragments.dialog.PlaylistPicker;
import com.andryr.musicplayer.images.ArtistImageCache;
import com.andryr.musicplayer.images.ArtworkCache;
import com.andryr.musicplayer.loaders.AlbumLoader;
import com.andryr.musicplayer.loaders.SongLoader;
import com.andryr.musicplayer.model.Album;
import com.andryr.musicplayer.model.Artist;
import com.andryr.musicplayer.model.Playlist;
import com.andryr.musicplayer.model.Song;
import com.andryr.musicplayer.utils.Playlists;
import com.andryr.musicplayer.utils.ThemeHelper;
import java.util.List;
/*
 * Copyright 2016 andryr
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.andryr.musicplayer.fragments;




public class ArtistFragment extends BaseFragment {

    private static final String PARAM_ARTIST_ID = "artist_id";
    private static final String PARAM_ARTIST_NAME = "artist_name";
    private static final String PARAM_ALBUM_COUNT = "album_count";
    private static final String PARAM_TRACK_COUNT = "track_count";


    private Artist mArtist;

    private SongListAdapter mSongListAdapter;

    private RecyclerView mSongListView;


    private LoaderManager.LoaderCallbacks<List<Song>> mSongLoaderCallbacks = new LoaderManager.LoaderCallbacks<List<Song>>() {

        @Override
        public Loader<List<Song>> onCreateLoader(int id, Bundle args) {
            SongLoader loader = new SongLoader(getActivity());

            loader.setSelection(MediaStore.Audio.Media.ARTIST_ID + " = ?", new String[]{String.valueOf(mArtist.getId())});

            loader.setSortOrder(MediaStore.Audio.Media.TRACK);
            return loader;
        }

        @Override
        public void onLoaderReset(Loader<List<Song>> loader) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onLoadFinished(Loader<List<Song>> loader, List<Song> songList) {
            mSongListAdapter.setData(songList);
            Log.e("test", "" + mSongListAdapter.getItemCount());
        }


    };

    private AlbumListAdapter mAlbumListAdapter;
    private boolean mAlbumListLoaded = false;
    private LoaderManager.LoaderCallbacks<List<Album>> mAlbumLoaderCallbacks = new LoaderManager.LoaderCallbacks<List<Album>>() {

        @Override
        public void onLoaderReset(Loader<List<Album>> loader) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onLoadFinished(Loader<List<Album>> loader, List<Album> data) {
            mAlbumListAdapter.setData(data);
            mAlbumListLoaded = true;
        }

        @Override
        public Loader<List<Album>> onCreateLoader(int id, Bundle args) {


            return new AlbumLoader(getActivity(), mArtist.getName());
        }
    };
    private ID3TagEditorDialog.OnTagsEditionSuccessListener mOnTagsEditionSuccessListener = new ID3TagEditorDialog.OnTagsEditionSuccessListener() {
        @Override
        public void onTagsEditionSuccess() {
Answer:             ((MainActivity) getActivity()).refresh();