1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.music.utils; 18 19 import android.media.MediaDescription; 20 import android.media.MediaMetadata; 21 import android.media.session.MediaSession; 22 import android.os.Bundle; 23 24 import java.util.ArrayList; 25 import java.util.Collections; 26 import java.util.Iterator; 27 import java.util.List; 28 29 import static com.android.music.utils.MediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST; 30 import static com.android.music.utils.MediaIDHelper.MEDIA_ID_MUSICS_BY_SEARCH; 31 import static com.android.music.utils.MediaIDHelper.MEDIA_ID_MUSICS_BY_SONG; 32 import static com.android.music.utils.MediaIDHelper.MEDIA_ID_MUSICS_BY_PLAYLIST; 33 import static com.android.music.utils.MediaIDHelper.MEDIA_ID_MUSICS_BY_ALBUM; 34 35 /** 36 * Utility class to help on queue related tasks. 37 */ 38 public class QueueHelper { 39 private static final String TAG = LogHelper.makeLogTag(QueueHelper.class); 40 41 public static List<MediaSession.QueueItem> getPlayingQueue( 42 String mediaId, MusicProvider musicProvider) { 43 // extract the browsing hierarchy from the media ID: 44 String[] hierarchy = MediaIDHelper.getHierarchy(mediaId); 45 46 if (hierarchy.length != 2) { 47 LogHelper.e(TAG, "Could not build a playing queue for this mediaId: ", mediaId); 48 return null; 49 } 50 51 String categoryType = hierarchy[0]; 52 String categoryValue = hierarchy[1]; 53 LogHelper.d(TAG, "Creating playing queue for ", categoryType, ", ", categoryValue); 54 55 Iterable<MediaMetadata> tracks = null; 56 // This sample only supports genre and by_search category types. 57 switch (categoryType) { 58 case MEDIA_ID_MUSICS_BY_SONG: 59 tracks = musicProvider.getMusicList(); 60 break; 61 case MEDIA_ID_MUSICS_BY_ALBUM: 62 tracks = musicProvider.getMusicsByAlbum(categoryValue); 63 break; 64 case MEDIA_ID_MUSICS_BY_ARTIST: 65 LogHelper.d(TAG, "Not supported"); 66 break; 67 default: 68 break; 69 } 70 71 if (tracks == null) { 72 LogHelper.e( 73 TAG, "Unrecognized category type: ", categoryType, " for mediaId ", mediaId); 74 return null; 75 } 76 77 return convertToQueue(tracks, hierarchy[0], hierarchy[1]); 78 } 79 80 public static List<MediaSession.QueueItem> getPlayingQueueFromSearch( 81 String query, MusicProvider musicProvider) { 82 LogHelper.d(TAG, "Creating playing queue for musics from search ", query); 83 84 return convertToQueue(musicProvider.searchMusic(query), MEDIA_ID_MUSICS_BY_SEARCH, query); 85 } 86 87 public static int getMusicIndexOnQueue(Iterable<MediaSession.QueueItem> queue, String mediaId) { 88 int index = 0; 89 for (MediaSession.QueueItem item : queue) { 90 if (mediaId.equals(item.getDescription().getMediaId())) { 91 return index; 92 } 93 index++; 94 } 95 return -1; 96 } 97 98 public static int getMusicIndexOnQueue(Iterable<MediaSession.QueueItem> queue, long queueId) { 99 int index = 0; 100 for (MediaSession.QueueItem item : queue) { 101 if (queueId == item.getQueueId()) { 102 return index; 103 } 104 index++; 105 } 106 return -1; 107 } 108 109 private static List<MediaSession.QueueItem> convertToQueue( 110 Iterable<MediaMetadata> tracks, String... categories) { 111 List<MediaSession.QueueItem> queue = new ArrayList<>(); 112 int count = 0; 113 for (MediaMetadata track : tracks) { 114 // We create a hierarchy-aware mediaID, so we know what the queue is about by looking 115 // at the QueueItem media IDs. 116 String hierarchyAwareMediaID = 117 MediaIDHelper.createMediaID(track.getDescription().getMediaId(), categories); 118 long duration = track.getLong(MediaMetadata.METADATA_KEY_DURATION); 119 MediaDescription.Builder descriptionBuilder = new MediaDescription.Builder(); 120 MediaDescription description = track.getDescription(); 121 Bundle extras = description.getExtras(); 122 if (extras == null) { 123 extras = new Bundle(); 124 } 125 extras.putLong(MediaMetadata.METADATA_KEY_DURATION, duration); 126 descriptionBuilder.setExtras(extras) 127 .setMediaId(hierarchyAwareMediaID) 128 .setTitle(description.getTitle()) 129 .setSubtitle(track.getString(MediaMetadata.METADATA_KEY_ARTIST)) 130 .setIconBitmap(description.getIconBitmap()) 131 .setIconUri(description.getIconUri()) 132 .setMediaUri(description.getMediaUri()) 133 .setDescription(description.getDescription()); 134 135 // We don't expect queues to change after created, so we use the item index as the 136 // queueId. Any other number unique in the queue would work. 137 MediaSession.QueueItem item = 138 new MediaSession.QueueItem(descriptionBuilder.build(), count++); 139 queue.add(item); 140 } 141 return queue; 142 } 143 144 /** 145 * Create a random queue. For simplicity sake, instead of a random queue, we create a 146 * queue using the first genre. 147 * 148 * @param musicProvider the provider used for fetching music. 149 * @return list containing {@link android.media.session.MediaSession.QueueItem}'s 150 */ 151 public static List<MediaSession.QueueItem> getRandomQueue(MusicProvider musicProvider) { 152 Iterator<String> genres = musicProvider.getArtists().iterator(); 153 if (!genres.hasNext()) { 154 return Collections.emptyList(); 155 } 156 String genre = genres.next(); 157 Iterable<MediaMetadata> tracks = musicProvider.getMusicsByAlbum(genre); 158 159 return convertToQueue(tracks, MEDIA_ID_MUSICS_BY_ARTIST, genre); 160 } 161 162 public static boolean isIndexPlayable(int index, List<MediaSession.QueueItem> queue) { 163 return (queue != null && index >= 0 && index < queue.size()); 164 } 165 } 166