1f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He/* 2f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * Copyright (C) 2017 The Android Open Source Project 3f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * 4f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * Licensed under the Apache License, Version 2.0 (the "License"); 5f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * you may not use this file except in compliance with the License. 6f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * You may obtain a copy of the License at 7f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * 8f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * http://www.apache.org/licenses/LICENSE-2.0 9f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * 10f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * Unless required by applicable law or agreed to in writing, software 11f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * distributed under the License is distributed on an "AS IS" BASIS, 12f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * See the License for the specific language governing permissions and 14f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * limitations under the License. 15f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He */ 16f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 17f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Hepackage com.android.music.utils; 18f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 1996716cec6a26e31c41d514d81afe669e8824bd5cAjay Panickerimport static android.Manifest.permission.READ_EXTERNAL_STORAGE; 2096716cec6a26e31c41d514d81afe669e8824bd5cAjay Panicker 21f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport android.content.ContentResolver; 22f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport android.content.ContentUris; 23f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport android.content.ContentValues; 24f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport android.content.Context; 2596716cec6a26e31c41d514d81afe669e8824bd5cAjay Panickerimport android.content.pm.PackageManager; 26f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport android.database.Cursor; 27f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport android.graphics.Bitmap; 28f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport android.graphics.BitmapFactory; 29f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport android.graphics.drawable.BitmapDrawable; 30f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport android.media.MediaActionSound; 31f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport android.media.MediaMetadata; 32f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport android.media.MediaMetadataRetriever; 33f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport android.net.Uri; 34f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport android.os.AsyncTask; 35f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport android.provider.MediaStore; 36f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport android.util.Log; 37f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport com.android.music.MediaPlaybackService; 38f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport com.android.music.MusicUtils; 39f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport com.android.music.R; 40f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 41f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport java.io.File; 42f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport java.util.*; 43f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport java.util.concurrent.ConcurrentHashMap; 44f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Heimport java.util.concurrent.ConcurrentMap; 45f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 46f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He/* 47f02d3c605f5d1d091ca7e27170010ad23cd22134Jack HeA provider of music contents to the music application, it reads external storage for any music 48f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Hefiles, parse them and 49f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Hestore them in this class for future use. 50f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He */ 51f02d3c605f5d1d091ca7e27170010ad23cd22134Jack Hepublic class MusicProvider { 52f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He private static final String TAG = "MusicProvider"; 53f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 54f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He // Public constants 55f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public static final String UNKOWN = "UNKNOWN"; 56f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He // Uri source of this track 57f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public static final String CUSTOM_METADATA_TRACK_SOURCE = "__SOURCE__"; 58f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He // Sort key for this tack 59f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public static final String CUSTOM_METADATA_SORT_KEY = "__SORT_KEY__"; 60f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 61f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He // Content select criteria 62f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He private static final String MUSIC_SELECT_FILTER = MediaStore.Audio.Media.IS_MUSIC + " != 0"; 63f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He private static final String MUSIC_SORT_ORDER = MediaStore.Audio.Media.TITLE + " ASC"; 64f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 65f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He // Categorized caches for music track data: 66f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He private Context mContext; 67f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He // Album Name --> list of Metadata 68f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He private ConcurrentMap<String, List<MediaMetadata>> mMusicListByAlbum; 69f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He // Playlist Name --> list of Metadata 70f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He private ConcurrentMap<String, List<MediaMetadata>> mMusicListByPlaylist; 71f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He // Artist Name --> Map of (album name --> album metadata) 72f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He private ConcurrentMap<String, Map<String, MediaMetadata>> mArtistAlbumDb; 73f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He private List<MediaMetadata> mMusicList; 74f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He private final ConcurrentMap<Long, Song> mMusicListById; 75f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He private final ConcurrentMap<String, Song> mMusicListByMediaId; 76f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 77f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He enum State { NON_INITIALIZED, INITIALIZING, INITIALIZED } 78f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 79f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He private volatile State mCurrentState = State.NON_INITIALIZED; 80f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 81f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public MusicProvider(Context context) { 82f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mContext = context; 83f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mArtistAlbumDb = new ConcurrentHashMap<>(); 84f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mMusicListByAlbum = new ConcurrentHashMap<>(); 85f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mMusicListByPlaylist = new ConcurrentHashMap<>(); 86f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mMusicListById = new ConcurrentHashMap<>(); 87f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mMusicList = new ArrayList<>(); 88f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mMusicListByMediaId = new ConcurrentHashMap<>(); 89f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mMusicListByPlaylist.put(MediaIDHelper.MEDIA_ID_NOW_PLAYING, new ArrayList<>()); 90f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 91f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 92f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public boolean isInitialized() { 93f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return mCurrentState == State.INITIALIZED; 94f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 95f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 96f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He /** 97f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * Get an iterator over the list of artists 98f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * 99f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * @return list of artists 100f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He */ 101f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public Iterable<String> getArtists() { 102f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (mCurrentState != State.INITIALIZED) { 103f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return Collections.emptyList(); 104f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 105f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return mArtistAlbumDb.keySet(); 106f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 107f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 108f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He /** 109f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * Get an iterator over the list of albums 110f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * 111f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * @return list of albums 112f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He */ 113f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public Iterable<MediaMetadata> getAlbums() { 114f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (mCurrentState != State.INITIALIZED) { 115f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return Collections.emptyList(); 116f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 117f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He ArrayList<MediaMetadata> albumList = new ArrayList<>(); 118f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He for (Map<String, MediaMetadata> artist_albums : mArtistAlbumDb.values()) { 119f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He albumList.addAll(artist_albums.values()); 120f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 121f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return albumList; 122f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 123f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 124f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He /** 125f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * Get an iterator over the list of playlists 126f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * 127f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * @return list of playlists 128f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He */ 129f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public Iterable<String> getPlaylists() { 130f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (mCurrentState != State.INITIALIZED) { 131f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return Collections.emptyList(); 132f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 133f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return mMusicListByPlaylist.keySet(); 134f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 135f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 136f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public Iterable<MediaMetadata> getMusicList() { 137f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return mMusicList; 138f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 139f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 140f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He /** 141f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * Get albums of a certain artist 142f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * 143f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He */ 144f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public Iterable<MediaMetadata> getAlbumByArtist(String artist) { 145f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (mCurrentState != State.INITIALIZED || !mArtistAlbumDb.containsKey(artist)) { 146f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return Collections.emptyList(); 147f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 148f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return mArtistAlbumDb.get(artist).values(); 149f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 150f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 151f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He /** 152f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * Get music tracks of the given album 153f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * 154f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He */ 155f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public Iterable<MediaMetadata> getMusicsByAlbum(String album) { 156f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (mCurrentState != State.INITIALIZED || !mMusicListByAlbum.containsKey(album)) { 157f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return Collections.emptyList(); 158f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 159f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return mMusicListByAlbum.get(album); 160f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 161f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 162f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He /** 163f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * Get music tracks of the given playlist 164f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * 165f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He */ 166f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public Iterable<MediaMetadata> getMusicsByPlaylist(String playlist) { 167f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (mCurrentState != State.INITIALIZED || !mMusicListByPlaylist.containsKey(playlist)) { 168f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return Collections.emptyList(); 169f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 170f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return mMusicListByPlaylist.get(playlist); 171f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 172f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 173f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He /** 174f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * Return the MediaMetadata for the given musicID. 175f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * 176f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * @param musicId The unique, non-hierarchical music ID. 177f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He */ 178f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public Song getMusicById(long musicId) { 179f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return mMusicListById.containsKey(musicId) ? mMusicListById.get(musicId) : null; 180f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 181f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 182f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He /** 183f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * Return the MediaMetadata for the given musicID. 184f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * 185f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * @param musicId The unique, non-hierarchical music ID. 186f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He */ 187f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public Song getMusicByMediaId(String musicId) { 188f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return mMusicListByMediaId.containsKey(musicId) ? mMusicListByMediaId.get(musicId) : null; 189f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 190f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 191f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He /** 192f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * Very basic implementation of a search that filter music tracks which title containing 193f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * the given query. 194f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * 195f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He */ 196f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public Iterable<MediaMetadata> searchMusic(String titleQuery) { 197f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (mCurrentState != State.INITIALIZED) { 198f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return Collections.emptyList(); 199f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 200f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He ArrayList<MediaMetadata> result = new ArrayList<>(); 201f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He titleQuery = titleQuery.toLowerCase(); 202f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He for (Song song : mMusicListByMediaId.values()) { 203f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (song.getMetadata() 204f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He .getString(MediaMetadata.METADATA_KEY_TITLE) 205f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He .toLowerCase() 206f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He .contains(titleQuery)) { 207f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He result.add(song.getMetadata()); 208f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 209f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 210f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return result; 211f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 212f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 213f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public interface MusicProviderCallback { void onMusicCatalogReady(boolean success); } 214f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 215f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He /** 216f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * Get the list of music tracks from disk and caches the track information 217f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He * for future reference, keying tracks by musicId and grouping by genre. 218f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He */ 219f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public void retrieveMediaAsync(final MusicProviderCallback callback) { 220f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Log.d(TAG, "retrieveMediaAsync called"); 221f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (mCurrentState == State.INITIALIZED) { 222f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He // Nothing to do, execute callback immediately 223f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He callback.onMusicCatalogReady(true); 224f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return; 225f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 226f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 227f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He // Asynchronously load the music catalog in a separate thread 228f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He new AsyncTask<Void, Void, State>() { 229f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He @Override 230f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He protected State doInBackground(Void... params) { 2312d11f2cdcab1246f3db0438e061811d40e483205Jaekyun Seok if (mCurrentState == State.INITIALIZED) { 2322d11f2cdcab1246f3db0438e061811d40e483205Jaekyun Seok return mCurrentState; 2332d11f2cdcab1246f3db0438e061811d40e483205Jaekyun Seok } 234f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mCurrentState = State.INITIALIZING; 235f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (retrieveMedia()) { 236f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mCurrentState = State.INITIALIZED; 237f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } else { 238f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mCurrentState = State.NON_INITIALIZED; 239f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 240f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return mCurrentState; 241f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 242f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 243f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He @Override 244f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He protected void onPostExecute(State current) { 245f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (callback != null) { 246f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He callback.onMusicCatalogReady(current == State.INITIALIZED); 247f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 248f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 249f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 250f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He .execute(); 251f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 252f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 253f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public synchronized boolean retrieveAllPlayLists() { 254f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Cursor cursor = mContext.getContentResolver().query( 255f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, null, null, null, null); 256f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (cursor == null) { 257f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Log.e(TAG, "Failed to retreive playlist: cursor is null"); 258f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return false; 259f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 260f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (!cursor.moveToFirst()) { 261f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Log.d(TAG, "Failed to move cursor to first row (no query result)"); 262f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He cursor.close(); 263f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return true; 264f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 265f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He int idColumn = cursor.getColumnIndex(MediaStore.Audio.Playlists._ID); 266f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He int nameColumn = cursor.getColumnIndex(MediaStore.Audio.Playlists.NAME); 267f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He int pathColumn = cursor.getColumnIndex(MediaStore.Audio.Playlists.DATA); 268f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He do { 269f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He long thisId = cursor.getLong(idColumn); 270f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He String thisPath = cursor.getString(pathColumn); 271f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He String thisName = cursor.getString(nameColumn); 272f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Log.i(TAG, "PlayList ID: " + thisId + " Name: " + thisName); 273f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He List<MediaMetadata> songList = retreivePlaylistMetadata(thisId, thisPath); 274f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He LogHelper.i(TAG, "Found ", songList.size(), " items for playlist name: ", thisName); 275f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mMusicListByPlaylist.put(thisName, songList); 276f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } while (cursor.moveToNext()); 277f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He cursor.close(); 278f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return true; 279f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 280f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 281f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public synchronized List<MediaMetadata> retreivePlaylistMetadata( 282f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He long playlistId, String playlistPath) { 283f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Cursor cursor = mContext.getContentResolver().query(Uri.parse(playlistPath), null, 284f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He MediaStore.Audio.Playlists.Members.PLAYLIST_ID + " == " + playlistId, null, null); 285f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (cursor == null) { 286f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Log.e(TAG, "Failed to retreive individual playlist: cursor is null"); 287f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return null; 288f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 289f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (!cursor.moveToFirst()) { 290f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Log.d(TAG, "Failed to move cursor to first row (no query result for playlist)"); 291f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He cursor.close(); 292f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return null; 293f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 294f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He List<Song> songList = new ArrayList<>(); 295f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He int idColumn = cursor.getColumnIndex(MediaStore.Audio.Playlists.Members._ID); 296f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He int audioIdColumn = cursor.getColumnIndex(MediaStore.Audio.Playlists.Members.AUDIO_ID); 297f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He int orderColumn = cursor.getColumnIndex(MediaStore.Audio.Playlists.Members.PLAY_ORDER); 298f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He int audioPathColumn = cursor.getColumnIndex(MediaStore.Audio.Playlists.Members.DATA); 299f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He int audioNameColumn = cursor.getColumnIndex(MediaStore.Audio.Playlists.Members.TITLE); 300f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He do { 301f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He long thisId = cursor.getLong(idColumn); 302f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He long thisAudioId = cursor.getLong(audioIdColumn); 303f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He long thisOrder = cursor.getLong(orderColumn); 304f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He String thisAudioPath = cursor.getString(audioPathColumn); 305f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Log.i(TAG, 306f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He "Playlist ID: " + playlistId + " Music ID: " + thisAudioId 307f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He + " Name: " + audioNameColumn); 308f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (!mMusicListById.containsKey(thisAudioId)) { 309f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He LogHelper.d(TAG, "Music does not exist"); 310f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He continue; 311f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 312f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Song song = mMusicListById.get(thisAudioId); 313f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He song.setSortKey(thisOrder); 314f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He songList.add(song); 315f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } while (cursor.moveToNext()); 316f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He cursor.close(); 317f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He songList.sort(new Comparator<Song>() { 318f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He @Override 319f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public int compare(Song s1, Song s2) { 320f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He long key1 = s1.getSortKey(); 321f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He long key2 = s2.getSortKey(); 322f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (key1 < key2) { 323f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return -1; 324f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } else if (key1 == key2) { 325f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return 0; 326f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } else { 327f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return 1; 328f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 329f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 330f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He }); 331f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He List<MediaMetadata> metadataList = new ArrayList<>(); 332f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He for (Song song : songList) { 333f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He metadataList.add(song.getMetadata()); 334f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 335f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return metadataList; 336f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 337f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 338f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He private synchronized boolean retrieveMedia() { 33996716cec6a26e31c41d514d81afe669e8824bd5cAjay Panicker if (mContext.checkSelfPermission(READ_EXTERNAL_STORAGE) 34096716cec6a26e31c41d514d81afe669e8824bd5cAjay Panicker != PackageManager.PERMISSION_GRANTED) { 34196716cec6a26e31c41d514d81afe669e8824bd5cAjay Panicker return false; 34296716cec6a26e31c41d514d81afe669e8824bd5cAjay Panicker } 34396716cec6a26e31c41d514d81afe669e8824bd5cAjay Panicker 344f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Cursor cursor = 345f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mContext.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, 346f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He null, MUSIC_SELECT_FILTER, null, MUSIC_SORT_ORDER); 347f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (cursor == null) { 348f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Log.e(TAG, "Failed to retreive music: cursor is null"); 349f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mCurrentState = State.NON_INITIALIZED; 350f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return false; 351f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 352f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (!cursor.moveToFirst()) { 353f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Log.d(TAG, "Failed to move cursor to first row (no query result)"); 354f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He cursor.close(); 355f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return true; 356f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 357f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He int idColumn = cursor.getColumnIndex(MediaStore.Audio.Media._ID); 358f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He int titleColumn = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE); 359f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He int pathColumn = cursor.getColumnIndex(MediaStore.Audio.Media.DATA); 360f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He do { 361f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Log.i(TAG, 362f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He "Music ID: " + cursor.getString(idColumn) 363f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He + " Title: " + cursor.getString(titleColumn)); 364f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He long thisId = cursor.getLong(idColumn); 365f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He String thisPath = cursor.getString(pathColumn); 366f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He MediaMetadata metadata = retrievMediaMetadata(thisId, thisPath); 367f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Log.i(TAG, "MediaMetadata: " + metadata); 368f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (metadata == null) { 369f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He continue; 370f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 371f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Song thisSong = new Song(thisId, metadata, null); 372f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He // Construct per feature database 373f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mMusicList.add(metadata); 374f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mMusicListById.put(thisId, thisSong); 375f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mMusicListByMediaId.put(String.valueOf(thisId), thisSong); 376f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He addMusicToAlbumList(metadata); 377f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He addMusicToArtistList(metadata); 378f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } while (cursor.moveToNext()); 379f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He cursor.close(); 380f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return true; 381f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 382f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 383f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He private synchronized MediaMetadata retrievMediaMetadata(long musicId, String musicPath) { 384f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He LogHelper.d(TAG, "getting metadata for music: ", musicPath); 385f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He MediaMetadataRetriever retriever = new MediaMetadataRetriever(); 386f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Uri contentUri = ContentUris.withAppendedId( 387f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, musicId); 388f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (!(new File(musicPath).exists())) { 389f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He LogHelper.d(TAG, "Does not exist, deleting item"); 390f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mContext.getContentResolver().delete(contentUri, null, null); 391f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return null; 392f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 393f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He retriever.setDataSource(mContext, contentUri); 394f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He String title = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE); 395f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He String album = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM); 396f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He String artist = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST); 397f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He String durationString = 398f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); 399f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He long duration = durationString != null ? Long.parseLong(durationString) : 0; 400f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He MediaMetadata.Builder metadataBuilder = 401f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He new MediaMetadata.Builder() 402f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, String.valueOf(musicId)) 403f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He .putString(CUSTOM_METADATA_TRACK_SOURCE, musicPath) 404f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He .putString(MediaMetadata.METADATA_KEY_TITLE, title != null ? title : UNKOWN) 405f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He .putString(MediaMetadata.METADATA_KEY_ALBUM, album != null ? album : UNKOWN) 406f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He .putString( 407f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He MediaMetadata.METADATA_KEY_ARTIST, artist != null ? artist : UNKOWN) 408f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He .putLong(MediaMetadata.METADATA_KEY_DURATION, duration); 409f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He byte[] albumArtData = retriever.getEmbeddedPicture(); 410f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Bitmap bitmap; 411f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (albumArtData != null) { 412f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He bitmap = BitmapFactory.decodeByteArray(albumArtData, 0, albumArtData.length); 413f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He bitmap = MusicUtils.resizeBitmap(bitmap, getDefaultAlbumArt()); 414f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He metadataBuilder.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, bitmap); 415f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 416f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He retriever.release(); 417f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return metadataBuilder.build(); 418f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 419f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 420f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He private Bitmap getDefaultAlbumArt() { 421f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He BitmapFactory.Options opts = new BitmapFactory.Options(); 422f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He opts.inPreferredConfig = Bitmap.Config.ARGB_8888; 423f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return BitmapFactory.decodeStream( 424f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mContext.getResources().openRawResource(R.drawable.albumart_mp_unknown), null, 425f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He opts); 426f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 427f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 428f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He private void addMusicToAlbumList(MediaMetadata metadata) { 429f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He String thisAlbum = metadata.getString(MediaMetadata.METADATA_KEY_ALBUM); 430f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (thisAlbum == null) { 431f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He thisAlbum = UNKOWN; 432f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 433f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (!mMusicListByAlbum.containsKey(thisAlbum)) { 434f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mMusicListByAlbum.put(thisAlbum, new ArrayList<>()); 435f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 436f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mMusicListByAlbum.get(thisAlbum).add(metadata); 437f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 438f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 439f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He private void addMusicToArtistList(MediaMetadata metadata) { 440f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He String thisArtist = metadata.getString(MediaMetadata.METADATA_KEY_ARTIST); 441f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (thisArtist == null) { 442f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He thisArtist = UNKOWN; 443f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 444f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He String thisAlbum = metadata.getString(MediaMetadata.METADATA_KEY_ALBUM); 445f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (thisAlbum == null) { 446f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He thisAlbum = UNKOWN; 447f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 448f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (!mArtistAlbumDb.containsKey(thisArtist)) { 449f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He mArtistAlbumDb.put(thisArtist, new ConcurrentHashMap<>()); 450f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 451f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Map<String, MediaMetadata> albumsMap = mArtistAlbumDb.get(thisArtist); 452f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He MediaMetadata.Builder builder; 453f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He long count = 0; 454f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Bitmap thisAlbumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); 455f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (albumsMap.containsKey(thisAlbum)) { 456f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He MediaMetadata album_metadata = albumsMap.get(thisAlbum); 457f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He count = album_metadata.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS); 458f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Bitmap nAlbumArt = album_metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); 459f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He builder = new MediaMetadata.Builder(album_metadata); 460f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (nAlbumArt != null) { 461f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He thisAlbumArt = null; 462f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 463f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } else { 464f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He builder = new MediaMetadata.Builder(); 465f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He builder.putString(MediaMetadata.METADATA_KEY_ALBUM, thisAlbum) 466f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He .putString(MediaMetadata.METADATA_KEY_ARTIST, thisArtist); 467f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 468f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (thisAlbumArt != null) { 469f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He builder.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, thisAlbumArt); 470f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 471f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He builder.putLong(MediaMetadata.METADATA_KEY_NUM_TRACKS, count + 1); 472f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He albumsMap.put(thisAlbum, builder.build()); 473f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 474f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 475f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He public synchronized void updateMusic(String musicId, MediaMetadata metadata) { 476f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He Song song = mMusicListByMediaId.get(musicId); 477f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (song == null) { 478f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He return; 479f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 480f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 481f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He String oldGenre = song.getMetadata().getString(MediaMetadata.METADATA_KEY_GENRE); 482f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He String newGenre = metadata.getString(MediaMetadata.METADATA_KEY_GENRE); 483f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 484f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He song.setMetadata(metadata); 485f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He 486f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He // if genre has changed, we need to rebuild the list by genre 487f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He if (!oldGenre.equals(newGenre)) { 488f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He // buildListsByGenre(); 489f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 490f02d3c605f5d1d091ca7e27170010ad23cd22134Jack He } 4912d11f2cdcab1246f3db0438e061811d40e483205Jaekyun Seok} 492