Java tutorial
/* * Copyright (C) 2014 The Android Open Source Project * * 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.appdevper.mediaplayer.model; import android.graphics.Bitmap; import android.media.MediaMetadata; import android.support.v4.media.MediaMetadataCompat; import android.util.Log; import com.appdevper.mediaplayer.util.ContentItem; import com.appdevper.mediaplayer.util.LogHelper; import com.appdevper.mediaplayer.util.Utils; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** * Utility class to get a list of MusicTrack's based on a server-side JSON * configuration. */ public class MusicProvider { private static final String TAG = LogHelper.makeLogTag(MusicProvider.class); private static MusicProvider musicProvider; // Categorized caches for music track data: private ConcurrentMap<String, List<MediaMetadataCompat>> mMusicListByGenre; private final ConcurrentMap<String, MutableMediaMetadata> mMusicListById; private final Set<String> mFavoriteTracks; enum State { NON_INITIALIZED, INITIALIZING, INITIALIZED } private volatile State mCurrentState = State.NON_INITIALIZED; public static MusicProvider getInstance() { if (musicProvider == null) { musicProvider = new MusicProvider(); } return musicProvider; } public MusicProvider() { mMusicListByGenre = new ConcurrentHashMap<>(); mMusicListById = new ConcurrentHashMap<>(); mFavoriteTracks = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>()); } /** * Get an iterator over the list of genres * * @return genres */ public Iterable<String> getGenres() { if (mCurrentState != State.INITIALIZED) { return Collections.emptyList(); } return mMusicListByGenre.keySet(); } /** * Get music tracks of the given genre */ public Iterable<MediaMetadataCompat> getMusicsByGenre(String genre) { if (mCurrentState != State.INITIALIZED || !mMusicListByGenre.containsKey(genre)) { return Collections.emptyList(); } return mMusicListByGenre.get(genre); } /** * Very basic implementation of a search that filter music tracks with title containing * the given query. */ public Iterable<MediaMetadataCompat> searchMusicBySongTitle(String query) { return searchMusic(MediaMetadataCompat.METADATA_KEY_TITLE, query); } public Iterable<MediaMetadataCompat> searchMusicByID(String query) { return searchMusic(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, query); } /** * Very basic implementation of a search that filter music tracks with album containing * the given query. */ public Iterable<MediaMetadataCompat> searchMusicByAlbum(String query) { return searchMusic(MediaMetadataCompat.METADATA_KEY_ALBUM, query); } /** * Very basic implementation of a search that filter music tracks with artist containing * the given query. */ public Iterable<MediaMetadataCompat> searchMusicByArtist(String query) { return searchMusic(MediaMetadataCompat.METADATA_KEY_ARTIST, query); } Iterable<MediaMetadataCompat> searchMusic(String metadataField, String query) { if (mCurrentState != State.INITIALIZED) { return Collections.emptyList(); } ArrayList<MediaMetadataCompat> result = new ArrayList<>(); query = query.toLowerCase(Locale.US); for (MutableMediaMetadata track : mMusicListById.values()) { if (track.metadata.getString(metadataField).toLowerCase(Locale.US).contains(query)) { result.add(track.metadata); } } return result; } public Iterable<MediaMetadataCompat> getAllMusic() { if (mCurrentState != State.INITIALIZED) { return Collections.emptyList(); } ArrayList<MediaMetadataCompat> result = new ArrayList<>(); for (MutableMediaMetadata track : mMusicListById.values()) { result.add(track.metadata); } return result; } public ArrayList<MediaMetadataCompat> getListMusic() { ArrayList<MediaMetadataCompat> result = new ArrayList<>(); for (MutableMediaMetadata track : mMusicListById.values()) { result.add(track.metadata); } return result; } /** * Return the MediaMetadata for the given musicID. * * @param musicId The unique, non-hierarchical music ID. */ public MediaMetadataCompat getMusic(String musicId) { return mMusicListById.containsKey(musicId) ? mMusicListById.get(musicId).metadata : null; } public synchronized void updateMusic(String musicId, MediaMetadataCompat metadata) { MutableMediaMetadata track = mMusicListById.get(musicId); if (track == null) { return; } String oldGenre = track.metadata.getString(MediaMetadataCompat.METADATA_KEY_GENRE); String newGenre = metadata.getString(MediaMetadataCompat.METADATA_KEY_GENRE); track.metadata = metadata; // if genre has changed, we need to rebuild the list by genre if (!oldGenre.equals(newGenre)) { buildListsByGenre(); } } public void setFavorite(String musicId, boolean favorite) { if (favorite) { mFavoriteTracks.add(musicId); } else { mFavoriteTracks.remove(musicId); } } public boolean isFavorite(String musicId) { return mFavoriteTracks.contains(musicId); } private synchronized void buildListsByGenre() { ConcurrentMap<String, List<MediaMetadataCompat>> newMusicListByGenre = new ConcurrentHashMap<>(); for (MutableMediaMetadata m : mMusicListById.values()) { String genre = m.metadata.getString(MediaMetadataCompat.METADATA_KEY_GENRE); List<MediaMetadataCompat> list = newMusicListByGenre.get(genre); if (list == null) { list = new ArrayList<>(); newMusicListByGenre.put(genre, list); } list.add(m.metadata); } mMusicListByGenre = newMusicListByGenre; } public synchronized void retrieveMedia(ArrayList<ContentItem> contentItems) { //if (mCurrentState == State.NON_INITIALIZED) { mCurrentState = State.INITIALIZING; for (ContentItem contentItem : contentItems) { MediaMetadataCompat item = buildFromContent(contentItem); String musicId = item.getString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID); Log.i("retrieveMedia", "musicId: " + musicId); if (!mMusicListById.containsKey(musicId)) mMusicListById.put(musicId, new MutableMediaMetadata(musicId, item)); } buildListsByGenre(); mCurrentState = State.INITIALIZED; // } } public synchronized void updateMusicArt(String musicId, Bitmap albumArt, Bitmap icon) { MediaMetadataCompat metadata = getMusic(musicId); metadata = new MediaMetadataCompat.Builder(metadata) // set high resolution bitmap in METADATA_KEY_ALBUM_ART. This is used, for // example, on the lockscreen background when the media session is active. .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, albumArt) // set small version of the album art in the DISPLAY_ICON. This is used on // the MediaDescription and thus it should be small to be serialized if // necessary .putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, icon) .build(); MutableMediaMetadata mutableMetadata = mMusicListById.get(musicId); if (mutableMetadata == null) { throw new IllegalStateException("Unexpected error: Inconsistent data structures in " + "MusicProvider"); } mutableMetadata.metadata = metadata; } private MediaMetadataCompat buildFromContent(ContentItem contentItem) { String title = contentItem.toString(); String album = contentItem.getSubtitle(); String artist = contentItem.getItem().getCreator(); String genre = contentItem.getMimeType(); String source = contentItem.getResourceUri(); String iconUrl = contentItem.getAlbumArtworkUri(); int trackNumber = 0; int totalTrackCount = 0; long duration = Utils.strToMilli(contentItem.getDuration()); // ms String id = String.valueOf(source.hashCode()); Log.i(TAG, "MediaMetadata id " + id); return new MediaMetadataCompat.Builder().putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, id) .putString(MusicProviderSource.CUSTOM_METADATA_TRACK_SOURCE, source) .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, album) .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist) .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration) .putString(MediaMetadataCompat.METADATA_KEY_GENRE, genre) .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, iconUrl) .putString(MediaMetadataCompat.METADATA_KEY_TITLE, title) .putLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, trackNumber) .putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, totalTrackCount).build(); } }