org.opensilk.music.library.mediastore.provider.MediaStoreLibraryProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.opensilk.music.library.mediastore.provider.MediaStoreLibraryProvider.java

Source

/*
 * Copyright (c) 2015 OpenSilk Productions LLC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.opensilk.music.library.mediastore.provider;

import android.content.ComponentName;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.text.TextUtils;

import org.apache.commons.lang3.StringUtils;
import org.opensilk.common.core.dagger2.AppContextComponent;
import org.opensilk.common.core.mortar.DaggerService;
import org.opensilk.music.library.LibraryConfig;
import org.opensilk.music.library.mediastore.MediaStoreLibraryComponent;
import org.opensilk.music.library.mediastore.R;
import org.opensilk.music.library.mediastore.loader.AlbumsLoader;
import org.opensilk.music.library.mediastore.loader.ArtistsLoader;
import org.opensilk.music.library.mediastore.loader.GenresLoader;
import org.opensilk.music.library.mediastore.loader.PlaylistsLoader;
import org.opensilk.music.library.mediastore.loader.TracksLoader;
import org.opensilk.music.library.mediastore.ui.StoragePickerActivity;
import org.opensilk.music.library.mediastore.util.FilesUtil;
import org.opensilk.music.library.mediastore.util.Projections;
import org.opensilk.music.library.mediastore.util.SelectionArgs;
import org.opensilk.music.library.mediastore.util.Selections;
import org.opensilk.music.library.mediastore.util.StorageLookup;
import org.opensilk.music.library.mediastore.util.Uris;
import org.opensilk.music.library.provider.LibraryProvider;
import org.opensilk.music.model.Album;
import org.opensilk.music.model.Artist;
import org.opensilk.music.model.Genre;
import org.opensilk.music.model.Playlist;
import org.opensilk.music.model.Track;
import org.opensilk.music.model.spi.Bundleable;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;

import rx.Observable;
import rx.Subscriber;
import rx.functions.Action1;
import rx.functions.Func1;
import timber.log.Timber;

import static org.opensilk.music.library.LibraryCapability.ALBUMS;
import static org.opensilk.music.library.LibraryCapability.ARTISTS;
import static org.opensilk.music.library.LibraryCapability.FOLDERSTRACKS;
import static org.opensilk.music.library.LibraryCapability.GENRES;
import static org.opensilk.music.library.LibraryCapability.PLAYLISTS;
import static org.opensilk.music.library.LibraryCapability.TRACKS;
import static org.opensilk.music.library.mediastore.util.CursorHelpers.appendId;
import static org.opensilk.music.library.provider.LibraryMethods.Extras.URI;
import static org.opensilk.music.library.provider.LibraryUris.Q.FOLDERS_ONLY;
import static org.opensilk.music.library.provider.LibraryUris.Q.Q;
import static org.opensilk.music.library.provider.LibraryUris.Q.TRACKS_ONLY;

/**
 * Created by drew on 4/26/15.
 */
public class MediaStoreLibraryProvider extends LibraryProvider {
    private static final boolean TESTING = false; //for when the tester app doesnt use mortar

    @Inject
    @Named("mediaStoreLibraryBaseAuthority")
    String mBaseAuthority;
    @Inject
    Provider<AlbumsLoader> mAlbumsLoaderProvider;
    @Inject
    Provider<ArtistsLoader> mArtistsLoaderProvider;
    @Inject
    Provider<TracksLoader> mTracksLoaderProvider;
    @Inject
    Provider<GenresLoader> mGenresLoaderProvider;
    @Inject
    Provider<PlaylistsLoader> mPlaylistsLoaderProvider;
    @Inject
    StorageLookup mStorageLookup;

    @Override
    public boolean onCreate() {
        final AppContextComponent acc;
        if (TESTING) {
            Timber.plant(new Timber.DebugTree());
            acc = AppContextComponent.FACTORY.call(getContext());
        } else {
            acc = DaggerService.getDaggerComponent(getContext());
        }
        MediaStoreLibraryComponent.FACTORY.call(acc).inject(this);
        return super.onCreate();
    }

    @Override
    protected LibraryConfig getLibraryConfig() {
        return LibraryConfig.builder()
                .setCapabilities(FOLDERSTRACKS | ALBUMS | ARTISTS | GENRES | PLAYLISTS | TRACKS)
                .setPickerComponent(new ComponentName(getContext(), StoragePickerActivity.class),
                        getContext().getString(R.string.folders_picker_title))
                .setAuthority(mAuthority).build();
    }

    @Override
    protected String getBaseAuthority() {
        return mBaseAuthority;
    }

    @Override
    protected void browseFolders(String library, String identity, Subscriber<? super Bundleable> subscriber,
            Bundle args) {
        final File base = mStorageLookup.getStorageFile(library);
        final File rootDir = TextUtils.isEmpty(identity) ? base : new File(base, identity);
        if (!rootDir.exists() || !rootDir.isDirectory() || !rootDir.canRead()) {
            Timber.e("Can't access path %s", rootDir.getPath());
            subscriber.onError(new IllegalArgumentException("Can't access path " + rootDir.getPath()));
            return;
        }

        final String q = args.<Uri>getParcelable(URI).getQueryParameter(Q);
        final boolean dirsOnly = StringUtils.equals(q, FOLDERS_ONLY);
        final boolean tracksOnly = StringUtils.equals(q, TRACKS_ONLY);

        File[] dirList = rootDir.listFiles();
        List<File> files = new ArrayList<>(dirList.length);
        for (File f : dirList) {
            if (!f.canRead()) {
                continue;
            }
            if (f.getName().startsWith(".")) {
                continue;
            }
            if (f.isDirectory() && !tracksOnly) {
                subscriber.onNext(FilesUtil.makeFolder(base, f));
            } else if (f.isFile()) {
                files.add(f);
            }
        }
        //Save ourselves the trouble
        if (dirsOnly) {
            subscriber.onCompleted();
            return;
        } else if (subscriber.isUnsubscribed()) {
            return;
        }
        // convert raw file list into something useful
        List<File> audioFiles = FilesUtil.filterAudioFiles(getContext(), files);
        List<Track> tracks = FilesUtil.convertAudioFilesToTracks(getContext(), base, audioFiles);
        if (subscriber.isUnsubscribed()) {
            return;
        }
        for (Track track : tracks) {
            subscriber.onNext(track);
        }
        subscriber.onCompleted();
    }

    @Override
    protected void queryAlbums(String library, Subscriber<? super Album> subscriber, Bundle args) {
        AlbumsLoader l = mAlbumsLoaderProvider.get();
        l.createObservable().subscribe(subscriber);
    }

    @Override
    protected void getAlbum(String library, String identity, Subscriber<? super Album> subscriber, Bundle args) {
        AlbumsLoader l = mAlbumsLoaderProvider.get();
        l.setUri(appendId(Uris.EXTERNAL_MEDIASTORE_ALBUMS, identity));
        l.createObservable().subscribe(subscriber);
    }

    @Override
    protected void getAlbumTracks(String library, String identity, Subscriber<? super Track> subscriber,
            Bundle args) {
        TracksLoader l = mTracksLoaderProvider.get();
        l.setSelection(Selections.LOCAL_ALBUM_SONGS);
        l.setSelectionArgs(SelectionArgs.LOCAL_ALBUM_SONGS(identity));
        l.createObservable().doOnNext(new Action1<Track>() {
            @Override
            public void call(Track track) {
                Timber.v("Track name=%s artist=%s albumArtist=%s", track.name, track.artistName,
                        track.albumArtistName);
            }
        }).subscribe(subscriber);
    }

    @Override
    protected void queryArtists(String library, Subscriber<? super Artist> subscriber, Bundle args) {
        ArtistsLoader l = mArtistsLoaderProvider.get();
        l.createObservable().subscribe(subscriber);
    }

    @Override
    protected void getArtist(String library, String identity, Subscriber<? super Artist> subscriber, Bundle args) {
        ArtistsLoader l = mArtistsLoaderProvider.get();
        l.setUri(appendId(Uris.EXTERNAL_MEDIASTORE_ARTISTS, identity));
        l.createObservable().subscribe(subscriber);
    }

    @Override
    protected void getArtistAlbums(String library, String identity, Subscriber<? super Album> subscriber,
            Bundle args) {
        AlbumsLoader l = mAlbumsLoaderProvider.get();
        l.setUri(Uris.EXTERNAL_MEDIASTORE_ARTISTS_ALBUMS(identity));
        l.createObservable().subscribe(subscriber);
    }

    @Override
    protected void getArtistTracks(String library, String identity, Subscriber<? super Track> subscriber,
            Bundle args) {
        TracksLoader l = mTracksLoaderProvider.get();
        l.setSelection(Selections.LOCAL_ARTIST_SONGS);
        l.setSelectionArgs(SelectionArgs.LOCAL_ARTIST_SONGS(identity));
        l.createObservable().doOnNext(new Action1<Track>() {
            @Override
            public void call(Track track) {
                Timber.v("Track name=%s artist=%s albumArtist=%s", track.name, track.artistName,
                        track.albumArtistName);
            }
        }).subscribe(subscriber);
    }

    @Override
    protected void queryGenres(String library, Subscriber<? super Genre> subscriber, Bundle args) {
        GenresLoader l = mGenresLoaderProvider.get();
        l.createObservable().subscribe(subscriber);
    }

    @Override
    protected void getGenre(String library, String identity, Subscriber<? super Genre> subscriber, Bundle args) {
        GenresLoader l = mGenresLoaderProvider.get();
        l.setUri(appendId(Uris.EXTERNAL_MEDIASTORE_GENRES, identity));
        l.createObservable().subscribe(subscriber);
    }

    @Override
    protected void getGenreAlbums(String library, String identity, Subscriber<? super Album> subscriber,
            Bundle args) {
        GenresLoader l = mGenresLoaderProvider.get();
        l.setUri(appendId(Uris.EXTERNAL_MEDIASTORE_GENRES, identity));
        l.createObservable().flatMap(new Func1<Genre, Observable<Album>>() {
            @Override
            public Observable<Album> call(Genre genre) {
                //Extract the albumuris and load them
                AlbumsLoader l = mAlbumsLoaderProvider.get();
                String[] ids = new String[genre.albumUris.size()];
                for (int ii = 0; ii < genre.albumUris.size(); ii++) {
                    ids[ii] = genre.albumUris.get(ii).getLastPathSegment();
                }
                l.setSelection(Selections.LOCAL_ALBUMS(ids));
                return l.createObservable();
            }
        }).subscribe(subscriber);
    }

    @Override
    protected void getGenreTracks(String library, String identity, Subscriber<? super Track> subscriber,
            Bundle args) {
        TracksLoader l = mTracksLoaderProvider.get();
        l.setUri(Uris.GENRE_MEMBERS(identity));
        l.setProjection(Projections.GENRE_SONGS);
        l.setSelection(Selections.GENRE_SONGS);
        l.setSelectionArgs(SelectionArgs.GENRE_SONGS);
        l.createObservable().doOnNext(new Action1<Track>() {
            @Override
            public void call(Track track) {
                Timber.v("Track name=%s artist=%s albumArtist=%s", track.name, track.artistName,
                        track.albumArtistName);
            }
        }).subscribe(subscriber);
    }

    @Override
    protected void queryPlaylists(String library, Subscriber<? super Playlist> subscriber, Bundle args) {
        PlaylistsLoader l = mPlaylistsLoaderProvider.get();
        l.createObservable().subscribe(subscriber);
    }

    @Override
    protected void getPlaylist(String library, String identity, Subscriber<? super Playlist> subscriber,
            Bundle args) {
        PlaylistsLoader l = mPlaylistsLoaderProvider.get();
        l.setUri(appendId(Uris.EXTERNAL_MEDIASTORE_PLAYLISTS, identity));
        l.createObservable().subscribe(subscriber);
    }

    @Override
    protected void getPlaylistTracks(String library, String identity, Subscriber<? super Track> subscriber,
            Bundle args) {
        TracksLoader l = mTracksLoaderProvider.get();
        l.setUri(Uris.PLAYLIST_MEMBERS(identity));
        l.setProjection(Projections.PLAYLIST_SONGS);
        l.setSelection(Selections.PLAYLIST_SONGS);
        l.setSelectionArgs(SelectionArgs.PLAYLIST_SONGS);
        l.setSortOrder(MediaStore.Audio.Playlists.Members.PLAY_ORDER);
        l.createObservable().doOnNext(new Action1<Track>() {
            @Override
            public void call(Track track) {
                Timber.v("Track name=%s artist=%s albumArtist=%s", track.name, track.artistName,
                        track.albumArtistName);
            }
        }).subscribe(subscriber);
    }

    @Override
    protected void queryTracks(String library, Subscriber<? super Track> subscriber, Bundle args) {
        final File rootDir = mStorageLookup.getStorageFile(library);
        if (!rootDir.exists() || !rootDir.isDirectory() || !rootDir.canRead()) {
            Timber.e("Can't access path %s", rootDir.getPath());
            subscriber.onError(new IllegalArgumentException("Can't access path " + rootDir.getPath()));
            return;
        }
        TracksLoader l = mTracksLoaderProvider.get();
        l.setSelection(Selections.LOCAL_SONG_PATH);
        l.setSelectionArgs(SelectionArgs.LOCAL_SONG_PATH(rootDir.getAbsolutePath()));
        l.createObservable().subscribe(subscriber);
    }

    @Override
    protected void getTrack(String library, String identity, Subscriber<? super Track> subscriber, Bundle args) {
        if (StringUtils.isNumeric(identity)) {
            TracksLoader l = mTracksLoaderProvider.get();
            l.setUri(appendId(Uris.EXTERNAL_MEDIASTORE_MEDIA, identity));
            l.createObservable().doOnNext(new Action1<Track>() {
                @Override
                public void call(Track track) {
                    Timber.v("Track name=%s artist=%s albumArtist=%s", track.name, track.artistName,
                            track.albumArtistName);
                }
            }).subscribe(subscriber);
        } else {
            final File base = mStorageLookup.getStorageFile(library);
            final File f = new File(base, identity);
            if (!f.exists() || !f.isFile() || !f.canRead()) {
                Timber.e("Can't access path %s", f.getPath());
                subscriber.onError(new IllegalArgumentException("Can't access path " + f.getPath()));
            } else {
                try {
                    subscriber.onNext(FilesUtil.makeTrackFromFile(base, f));
                    subscriber.onCompleted();
                } catch (Exception e) {
                    subscriber.onError(e);
                }
            }
        }
    }

}