1 /* 2 * Copyright (C) 2018 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.bluetooth.audio_util; 18 19 import android.content.Context; 20 import android.content.pm.PackageManager; 21 import android.media.MediaDescription; 22 import android.media.MediaMetadata; 23 import android.media.browse.MediaBrowser.MediaItem; 24 import android.media.session.MediaSession; 25 import android.os.Bundle; 26 import android.util.Log; 27 28 import com.android.bluetooth.R; 29 30 import java.util.ArrayList; 31 import java.util.List; 32 33 class Util { 34 public static String TAG = "audio_util.Util"; 35 public static boolean DEBUG = false; 36 37 private static final String GPM_KEY = "com.google.android.music.mediasession.music_metadata"; 38 39 // TODO (apanicke): Remove this prefix later, for now it makes debugging easier. 40 public static final String NOW_PLAYING_PREFIX = "NowPlayingId"; 41 42 /** 43 * Get an empty set of Metadata 44 */ empty_data()45 public static final Metadata empty_data() { 46 Metadata ret = new Metadata(); 47 ret.mediaId = "Not Provided"; 48 ret.title = "Not Provided"; 49 ret.artist = ""; 50 ret.album = ""; 51 ret.genre = ""; 52 ret.trackNum = "1"; 53 ret.numTracks = "1"; 54 ret.duration = "0"; 55 ret.image = null; 56 return ret; 57 } 58 59 /** 60 * Get whether or not Bluetooth is configured to support URI images or not. 61 * 62 * Note that creating URI images will dramatically increase memory usage. 63 */ areUriImagesSupported(Context context)64 public static boolean areUriImagesSupported(Context context) { 65 if (context == null) return false; 66 return context.getResources().getBoolean(R.bool.avrcp_target_cover_art_uri_images); 67 } 68 69 /** 70 * Translate a bundle of MediaMetadata keys to audio_util's Metadata 71 */ toMetadata(Context context, Bundle bundle)72 public static Metadata toMetadata(Context context, Bundle bundle) { 73 Metadata.Builder builder = new Metadata.Builder(); 74 return builder.useContext(context).useDefaults().fromBundle(bundle).build(); 75 } 76 77 /** 78 * Translate a MediaDescription to audio_util's Metadata 79 */ toMetadata(Context context, MediaDescription desc)80 public static Metadata toMetadata(Context context, MediaDescription desc) { 81 // Find GPM_KEY data if it exists 82 MediaMetadata data = null; 83 Bundle extras = (desc != null ? desc.getExtras() : null); 84 if (extras != null && extras.containsKey(GPM_KEY)) { 85 data = (MediaMetadata) extras.get(GPM_KEY); 86 } 87 88 Metadata.Builder builder = new Metadata.Builder(); 89 return builder.useContext(context).useDefaults().fromMediaDescription(desc) 90 .fromMediaMetadata(data).build(); 91 } 92 93 /** 94 * Translate a MediaItem to audio_util's Metadata 95 */ toMetadata(Context context, MediaItem item)96 public static Metadata toMetadata(Context context, MediaItem item) { 97 Metadata.Builder builder = new Metadata.Builder(); 98 return builder.useContext(context).useDefaults().fromMediaItem(item).build(); 99 } 100 101 /** 102 * Translate a MediaSession.QueueItem to audio_util's Metadata 103 */ toMetadata(Context context, MediaSession.QueueItem item)104 public static Metadata toMetadata(Context context, MediaSession.QueueItem item) { 105 Metadata.Builder builder = new Metadata.Builder().useDefaults().fromQueueItem(item); 106 // For Queue Items, the Media Id will always be just its Queue ID 107 // We don't need to use its actual ID since we don't promise UIDS being valid 108 // between a file system and it's now playing list. 109 if (item != null) builder.setMediaId(NOW_PLAYING_PREFIX + item.getQueueId()); 110 return builder.build(); 111 } 112 113 /** 114 * Translate a MediaMetadata to audio_util's Metadata 115 */ toMetadata(Context context, MediaMetadata data)116 public static Metadata toMetadata(Context context, MediaMetadata data) { 117 Metadata.Builder builder = new Metadata.Builder(); 118 // This will always be currsong. The AVRCP service will overwrite the mediaId if it needs to 119 // TODO (apanicke): Remove when the service is ready, right now it makes debugging much more 120 // convenient 121 return builder.useContext(context).useDefaults().fromMediaMetadata(data) 122 .setMediaId("currsong").build(); 123 } 124 125 /** 126 * Translate a list of MediaSession.QueueItem to a list of audio_util's Metadata 127 */ toMetadataList(Context context, List<MediaSession.QueueItem> items)128 public static List<Metadata> toMetadataList(Context context, 129 List<MediaSession.QueueItem> items) { 130 ArrayList<Metadata> list = new ArrayList<Metadata>(); 131 132 if (items == null) return list; 133 134 for (int i = 0; i < items.size(); i++) { 135 Metadata data = toMetadata(context, items.get(i)); 136 data.trackNum = "" + (i + 1); 137 data.numTracks = "" + items.size(); 138 list.add(data); 139 } 140 141 return list; 142 } 143 144 // Helper method to close a list of ListItems so that if the callee wants 145 // to mutate the list they can do it without affecting any internally cached info cloneList(List<ListItem> list)146 public static List<ListItem> cloneList(List<ListItem> list) { 147 List<ListItem> clone = new ArrayList<ListItem>(list.size()); 148 for (ListItem item : list) clone.add(item.clone()); 149 return clone; 150 } 151 getDisplayName(Context context, String packageName)152 public static String getDisplayName(Context context, String packageName) { 153 try { 154 PackageManager manager = context.getPackageManager(); 155 return manager.getApplicationLabel(manager.getApplicationInfo(packageName, 0)) 156 .toString(); 157 } catch (Exception e) { 158 Log.w(TAG, "Name Not Found using package name: " + packageName); 159 return packageName; 160 } 161 } 162 } 163