/* * Copyright 2008-2013, ETH Zürich, Samuel Welten, Michael Kuhn, Tobias Langner, * Sandro Affentranger, Lukas Bossard, Michael Grob, Rahul Jain, * Dominic Langenegger, Sonia Mayor Alonso, Roger Odermatt, Tobias Schlueter, * Yannick Stucki, Sebastian Wendland, Samuel Zehnder, Samuel Zihlmann, * Samuel Zweifel * * This file is part of Jukefox. * * Jukefox 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 any later version. Jukefox 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 * Jukefox. If not, see <http://www.gnu.org/licenses/>. */ package ch.ethz.dcg.jukefox.manager.libraryimport; import java.util.HashMap; import java.util.HashSet; import java.util.Map.Entry; import android.content.ContentResolver; import android.database.Cursor; import android.net.Uri; import android.provider.MediaStore; import ch.ethz.dcg.jukefox.commons.DataUnavailableException; import ch.ethz.dcg.jukefox.commons.DataWriteException; import ch.ethz.dcg.jukefox.commons.utils.Log; import ch.ethz.dcg.jukefox.model.AbstractCollectionModelManager; import ch.ethz.dcg.jukefox.model.libraryimport.ContentProviderId; import ch.ethz.dcg.jukefox.model.libraryimport.GenreSongMap; import ch.ethz.dcg.jukefox.model.libraryimport.ImportState; import ch.ethz.dcg.jukefox.model.libraryimport.ContentProviderId.Type; public class AndroidGenreManager extends AbstractGenreManager { private final static String TAG = AndroidGenreManager.class.getSimpleName(); private ContentResolver contentResolver; public AndroidGenreManager(AbstractCollectionModelManager collectionModelManager, ImportState importState, ContentResolver contentResolver) { super(collectionModelManager, importState); this.contentResolver = contentResolver; } @Override public void updateGenres(LibraryChanges changes) { HashMap<ContentProviderId, Integer> extGenreIdMap; try { extGenreIdMap = insertGenres(Type.EXTERNAL); GenreSongMap cpMap = readGenreSongMapFromCp(extGenreIdMap, changes.getContentProviderIdToJukefoxIdMap()); GenreSongMap dbMap = otherDataProvider.getGenreSongMappings(); // removes all inserted mappings from dbMap, such that only those // that need to be removed remain. insertGenreSongMappings(cpMap, dbMap); removeObsoleteGenreSongMappings(dbMap); modifyProvider.removeObsoleteGenres(); } catch (DataWriteException e) { // TODO Log.w(TAG, e); } catch (DataUnavailableException e) { // TODO Log.w(TAG, e); } } private GenreSongMap readGenreSongMapFromCp(HashMap<ContentProviderId, Integer> genreIdMap, HashMap<ContentProviderId, Integer> songIdMap) { GenreSongMap genreSongMap = new GenreSongMap(); for (Entry<ContentProviderId, Integer> e : genreIdMap.entrySet()) { ContentProviderId cpGenreId = e.getKey(); HashSet<Integer> songs = getSongsForGenre(cpGenreId, songIdMap); Integer genreId = e.getValue(); genreSongMap.putSongs(genreId, songs); } return genreSongMap; } private HashSet<Integer> getSongsForGenre(ContentProviderId genreId, HashMap<ContentProviderId, Integer> songIdMap) { Cursor cur = null; try { HashSet<Integer> songs = new HashSet<Integer>(); String[] projection = new String[] { MediaStore.Audio.Genres.Members._ID }; Uri uri; if (genreId.getType() == Type.EXTERNAL) { uri = MediaStore.Audio.Genres.Members.getContentUri("external", genreId.getId()); } else { // return songs; // TODO: how to handle internal songs // correctly? uri = MediaStore.Audio.Genres.Members.getContentUri("internal", genreId.getId()); } cur = contentResolver.query(uri, projection, null, null, null); while (cur.moveToNext()) { ContentProviderId cpId = new ContentProviderId(cur.getInt(0), genreId.getType()); Integer songId = songIdMap.get(cpId); if (songId == null) { // hmm... but can happen if the content provider content has // changed since we have set up the songId map. // Log.v(TAG, "No jukefoxId found for content provider " // + "songId. Maybe the content has changed during " // + "the import process?"); continue; } songs.add(songId); } return songs; } finally { if (cur != null) { cur.close(); } } } private HashMap<ContentProviderId, Integer> insertGenres(Type type) throws DataWriteException { HashMap<ContentProviderId, Integer> idMap = new HashMap<ContentProviderId, Integer>(); String[] projection = new String[] { MediaStore.Audio.Genres._ID, MediaStore.Audio.Genres.NAME }; Uri uri; if (type == Type.EXTERNAL) { uri = MediaStore.Audio.Genres.EXTERNAL_CONTENT_URI; } else { uri = MediaStore.Audio.Genres.INTERNAL_CONTENT_URI; } Log.v(TAG, "uri: " + uri); Cursor cur = null; try { cur = contentResolver.query(uri, projection, null, null, null); Log.v(TAG, "Number of genres from content provider: " + cur.getCount()); while (cur.moveToNext()) { ContentProviderId cpId = new ContentProviderId(cur.getInt(0), type); String name = cur.getString(1); int jukefoxId = modifyProvider.insertGenre(name); idMap.put(cpId, jukefoxId); } } finally { if (cur != null) { cur.close(); } } return idMap; } }