1 /* 2 * Copyright (C) 2020 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 package com.android.bluetooth.audio_util; 17 18 import android.content.Context; 19 import android.graphics.Bitmap; 20 import android.graphics.BitmapFactory; 21 import android.media.MediaDescription; 22 import android.media.MediaMetadata; 23 import android.net.Uri; 24 import android.os.Bundle; 25 import android.util.Log; 26 27 import java.io.IOException; 28 import java.io.InputStream; 29 30 /** 31 * An object to represent an image from the Media Framework 32 * 33 * This object abstracts away the method used to get the bitmap and provides a way for us to 34 * determine image equality in an application/folder/item agnostic way. 35 */ 36 public class Image { 37 private static final String TAG = "Image"; 38 private static final boolean DEBUG = false; 39 40 public static int SOURCE_NONE = 0; 41 public static int SOURCE_URI = 1; 42 public static int SOURCE_BITMAP = 2; 43 44 private final Context mContext; 45 46 private int mSource = SOURCE_NONE; 47 private Bitmap mImage = null; 48 49 // For use with other applications so they can conveniently assign the handle their storage 50 // solution has picked for this image and pass this object on directly. 51 private String mImageHandle = null; 52 53 /** 54 * Create an Image object from a MediaMetadata object 55 */ Image(Context context, MediaMetadata metadata)56 public Image(Context context, MediaMetadata metadata) { 57 mContext = context; 58 59 String uri_art = metadata.getString(MediaMetadata.METADATA_KEY_ART_URI); 60 String uri_album_art = metadata.getString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI); 61 String uri_icon = metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI); 62 Bitmap bmp_art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ART); 63 Bitmap bmp_album_art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); 64 Bitmap bmp_icon = metadata.getBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON); 65 66 if (bmp_art != null) { 67 setImage(bmp_art); 68 } else if (bmp_album_art != null) { 69 setImage(bmp_album_art); 70 } else if (bmp_icon != null) { 71 setImage(bmp_icon); 72 } else if (uri_art != null) { 73 setImage(uri_art); 74 } else if (uri_album_art != null) { 75 setImage(uri_album_art); 76 } else if (uri_icon != null) { 77 setImage(uri_icon); 78 } 79 } 80 81 /** 82 * Create an image out of a bundle of MediaMetadata keyed values 83 */ Image(Context context, Bundle bundle)84 public Image(Context context, Bundle bundle) { 85 mContext = context; 86 87 String uri_art = bundle.getString(MediaMetadata.METADATA_KEY_ART_URI); 88 String uri_album_art = bundle.getString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI); 89 String uri_icon = bundle.getString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI); 90 Bitmap bmp_art = bundle.getParcelable(MediaMetadata.METADATA_KEY_ART); 91 Bitmap bmp_album_art = bundle.getParcelable(MediaMetadata.METADATA_KEY_ALBUM_ART); 92 Bitmap bmp_icon = bundle.getParcelable(MediaMetadata.METADATA_KEY_DISPLAY_ICON); 93 94 if (bmp_art != null) { 95 setImage(bmp_art); 96 } else if (bmp_album_art != null) { 97 setImage(bmp_album_art); 98 } else if (bmp_icon != null) { 99 setImage(bmp_icon); 100 } else if (uri_art != null) { 101 setImage(uri_art); 102 } else if (uri_album_art != null) { 103 setImage(uri_album_art); 104 } else if (uri_icon != null) { 105 setImage(uri_icon); 106 } 107 } 108 109 /** 110 * Create an Image object from a MediaDescription object 111 */ Image(Context context, MediaDescription desc)112 public Image(Context context, MediaDescription desc) { 113 mContext = context; 114 Uri uri = desc.getIconUri(); 115 Bitmap bitmap = desc.getIconBitmap(); 116 if (bitmap != null) { 117 setImage(bitmap); 118 } else if (uri != null) { 119 setImage(uri); 120 } 121 } 122 123 /** 124 * Create an Image object from a raw image uri 125 */ Image(Context context, Uri uri)126 public Image(Context context, Uri uri) { 127 mContext = context; 128 setImage(uri); 129 } 130 131 /** 132 * Create an Image object from a raw image 133 */ Image(Context context, Bitmap image)134 public Image(Context context, Bitmap image) { 135 mContext = context; 136 setImage(image); 137 } 138 139 /** 140 * Set the image by resolving a URI to a bitmap 141 */ setImage(String uriString)142 private void setImage(String uriString) { 143 if (uriString == null) return; 144 Uri uri = Uri.parse(uriString); 145 setImage(uri); 146 } 147 148 /** 149 * Set the image by resolving a URI to a bitmap 150 */ setImage(Uri uri)151 private void setImage(Uri uri) { 152 if (uri == null) return; 153 Bitmap image = getImageFromUri(uri); 154 if (image == null) return; 155 setImage(image); 156 setSource(SOURCE_URI); 157 } 158 159 /** 160 * Set the image directly from a bitmap 161 */ setImage(Bitmap image)162 private void setImage(Bitmap image) { 163 if (image == null) return; 164 mImage = image; 165 setSource(SOURCE_BITMAP); 166 } 167 168 /** 169 * Get the bitmap associated with this Image 170 */ getImage()171 public Bitmap getImage() { 172 return mImage; 173 } 174 175 /** 176 * Get an image Bitmap from a Uri 177 * 178 * Used to convert Uris into the images they represent 179 * 180 * @param uri A Uri pointing to an image 181 * @return A Bitmap object representing the image at the given Uri 182 */ getImageFromUri(Uri uri)183 private Bitmap getImageFromUri(Uri uri) { 184 if (uri == null) return null; 185 Bitmap art = null; 186 InputStream input = null; 187 try { 188 if (mContext == null) return null; 189 input = mContext.getContentResolver().openInputStream(uri); 190 art = BitmapFactory.decodeStream(input); 191 } catch (Exception e) { 192 Log.w("Failed to fetch image at uri=" + uri, e); 193 art = null; 194 } 195 try { 196 if (input != null) { 197 input.close(); 198 } 199 } catch (IOException e) { 200 Log.e(TAG, "Failed to close image file stream, exception=" + e); 201 } 202 return art; 203 } 204 205 /** 206 * Get the source of the image, if known 207 * 208 * Images currently come from either raw bitmaps or a URI that points to a ContentProvider. 209 * This allows us to set where it came from, largely used for debug purposes. 210 */ getSource()211 public int getSource() { 212 return mSource; 213 } 214 215 /** 216 * Set the source of the image. 217 * 218 * Images currently come from either raw bitmaps or a URI that points to a ContentProvider. 219 * This allows us to set where it came from, largely used for debug purposes. 220 */ setSource(int source)221 private void setSource(int source) { 222 mSource = source; 223 } 224 225 /** 226 * Assign a handle value from your storage solution to this image 227 */ setImageHandle(String handle)228 public void setImageHandle(String handle) { 229 mImageHandle = handle; 230 } 231 232 /** 233 * Get the handle value associated with this image from your storage situation 234 */ getImageHandle()235 public String getImageHandle() { 236 return mImageHandle; 237 } 238 239 /** 240 * Determine if two image objects are the same. 241 */ 242 @Override equals(Object o)243 public boolean equals(Object o) { 244 if (o == null) return false; 245 if (!(o instanceof Image)) return false; 246 final Image image = (Image) o; 247 final Bitmap bmp = image.getImage(); 248 if (bmp == null) return (mImage == null); 249 return bmp.sameAs(mImage); 250 } 251 252 /** 253 * Get a string representation of the image and its metadata 254 */ 255 @Override toString()256 public String toString() { 257 return "<Image source=" + mSource + ">"; 258 } 259 } 260