1 package org.robolectric.shadows; 2 3 import static org.robolectric.shadows.util.DataSource.toDataSource; 4 5 import android.content.Context; 6 import android.graphics.Bitmap; 7 import android.media.MediaMetadataRetriever; 8 import android.net.Uri; 9 import java.io.FileDescriptor; 10 import java.util.HashMap; 11 import java.util.Map; 12 import org.robolectric.annotation.Implementation; 13 import org.robolectric.annotation.Implements; 14 import org.robolectric.annotation.Resetter; 15 import org.robolectric.shadows.util.DataSource; 16 17 @Implements(MediaMetadataRetriever.class) 18 public class ShadowMediaMetadataRetriever { 19 private DataSource dataSource; 20 private static final Map<DataSource, Map<Integer, String>> metadata = new HashMap<>(); 21 private static final Map<DataSource, Map<Long, Bitmap>> frames = new HashMap<>(); 22 private static final Map<DataSource, RuntimeException> exceptions = new HashMap<>(); 23 setDataSource(DataSource dataSource)24 public void setDataSource(DataSource dataSource) { 25 RuntimeException e = exceptions.get(dataSource); 26 if (e != null) { 27 e.fillInStackTrace(); 28 throw e; 29 } 30 this.dataSource = dataSource; 31 } 32 33 @Implementation setDataSource(String path)34 protected void setDataSource(String path) { 35 setDataSource(toDataSource(path)); 36 } 37 38 @Implementation setDataSource(Context context, Uri uri)39 protected void setDataSource(Context context, Uri uri) { 40 setDataSource(toDataSource(context, uri)); 41 } 42 43 @Implementation setDataSource(String uri, Map<String, String> headers)44 protected void setDataSource(String uri, Map<String, String> headers) { 45 setDataSource(toDataSource(uri, headers)); 46 } 47 48 @Implementation setDataSource(FileDescriptor fd, long offset, long length)49 protected void setDataSource(FileDescriptor fd, long offset, long length) { 50 setDataSource(toDataSource(fd, offset, length)); 51 } 52 53 @Implementation extractMetadata(int keyCode)54 protected String extractMetadata(int keyCode) { 55 if (metadata.containsKey(dataSource)) { 56 return metadata.get(dataSource).get(keyCode); 57 } 58 return null; 59 } 60 61 @Implementation getFrameAtTime(long timeUs, int option)62 protected Bitmap getFrameAtTime(long timeUs, int option) { 63 return (frames.containsKey(dataSource) ? 64 frames.get(dataSource).get(timeUs) : null); 65 } 66 67 /** 68 * Configures an exception to be thrown when {@link #setDataSource} 69 * is called for the given data source. 70 * 71 * @param ds the data source that will trigger an exception 72 * @param e the exception to trigger, or <tt>null</tt> to 73 * avoid throwing an exception. 74 */ addException(DataSource ds, RuntimeException e)75 public static void addException(DataSource ds, RuntimeException e) { 76 exceptions.put(ds, e); 77 } 78 addMetadata(DataSource ds, int keyCode, String value)79 public static void addMetadata(DataSource ds, int keyCode, String value) { 80 if (!metadata.containsKey(ds)) { 81 metadata.put(ds, new HashMap<Integer, String>()); 82 } 83 metadata.get(ds).put(keyCode, value); 84 } 85 86 /** 87 * Adds the given keyCode/value pair for the given data source. 88 * Uses <tt>path</tt> to call {@link org.robolectric.shadows.util.DataSource#toDataSource(String)} and 89 * then calls {@link #addMetadata(DataSource, int, String)}. This 90 * method is retained mostly for backwards compatibility; 91 * you can call {@link #addMetadata(DataSource, int, String)} directly. 92 * 93 * @param path the path to the data source whose metadata is being set. 94 * @param keyCode the keyCode for the metadata being set, as used by {@link MediaMetadataRetriever#extractMetadata(int)}. 95 * @param value the value for the specified metadata. 96 */ addMetadata(String path, int keyCode, String value)97 public static void addMetadata(String path, int keyCode, String value) { 98 addMetadata(toDataSource(path), keyCode, value); 99 } 100 addFrame(DataSource ds, long time, Bitmap bitmap)101 public static void addFrame(DataSource ds, long time, Bitmap bitmap) { 102 if (!frames.containsKey(ds)) { 103 frames.put(ds, new HashMap<Long, Bitmap>()); 104 } 105 frames.get(ds).put(time, bitmap); 106 } 107 108 /** 109 * Adds the given bitmap at the given time for the given data source. 110 * Uses <tt>path</tt> to call {@link org.robolectric.shadows.util.DataSource#toDataSource(String)} and 111 * then calls {@link #addFrame(DataSource, long, Bitmap)}. This 112 * method is retained mostly for backwards compatibility; 113 * you can call {@link #addFrame(DataSource, long, Bitmap)} directly. 114 * 115 * @param path the path to the data source. 116 * @param time the playback time at which the specified bitmap 117 * should be retrieved. 118 * @param bitmap the bitmap to retrieve. 119 */ addFrame(String path, long time, Bitmap bitmap)120 public static void addFrame(String path, long time, Bitmap bitmap) { 121 addFrame(toDataSource(path), time, bitmap); 122 } 123 124 /** 125 * Adds the given bitmap at the given time for the given data source. 126 * Uses <tt>path</tt> to call {@link org.robolectric.shadows.util.DataSource#toDataSource(Context, Uri)} and 127 * then calls {@link #addFrame(DataSource, long, Bitmap)}. This 128 * method is retained mostly for backwards compatibility; 129 * you can call {@link #addFrame(DataSource, long, Bitmap)} directly. 130 * 131 * @param context the Context object to match on the data source. 132 * @param uri the Uri of the data source. 133 * @param time the playback time at which the specified bitmap 134 * should be retrieved. 135 * @param bitmap the bitmap to retrieve. 136 */ addFrame(Context context, Uri uri, long time, Bitmap bitmap)137 public static void addFrame(Context context, Uri uri, long time, Bitmap bitmap) { 138 addFrame(toDataSource(context, uri), time, bitmap); 139 } 140 141 /** 142 * Adds the given bitmap at the given time for the given data source. 143 * Uses <tt>path</tt> to call {@link org.robolectric.shadows.util.DataSource#toDataSource(String, Map)} and 144 * then calls {@link #addFrame(DataSource, long, Bitmap)}. This 145 * method is retained mostly for backwards compatibility; 146 * you can call {@link #addFrame(DataSource, long, Bitmap)} directly. 147 * 148 * @param uri the Uri of the data source. 149 * @param headers the headers to use when requesting the specified uri. 150 * @param time the playback time at which the specified bitmap 151 * should be retrieved. 152 * @param bitmap the bitmap to retrieve. 153 */ addFrame(String uri, Map<String, String> headers, long time, Bitmap bitmap)154 public static void addFrame(String uri, Map<String, String> headers, long time, Bitmap bitmap) { 155 addFrame(toDataSource(uri, headers), time, bitmap); 156 } 157 158 /** 159 * Adds the given bitmap at the given time for the given data source. 160 * Uses <tt>path</tt> to call {@link org.robolectric.shadows.util.DataSource#toDataSource(FileDescriptor)} and 161 * then calls {@link #addFrame(DataSource, long, Bitmap)}. This 162 * method is retained mostly for backwards compatibility; 163 * you can call {@link #addFrame(DataSource, long, Bitmap)} directly. 164 * 165 * @param fd file descriptor of the data source. 166 * @param time the playback time at which the specified bitmap 167 * should be retrieved. 168 * @param bitmap the bitmap to retrieve. 169 */ addFrame(FileDescriptor fd, long time, Bitmap bitmap)170 public static void addFrame(FileDescriptor fd, long time, Bitmap bitmap) { 171 addFrame(toDataSource(fd), time, bitmap); 172 } 173 174 /** 175 * Adds the given bitmap at the given time for the given data source. 176 * Uses <tt>path</tt> to call {@link org.robolectric.shadows.util.DataSource#toDataSource(FileDescriptor, long, long)} and 177 * then calls {@link #addFrame(DataSource, long, Bitmap)}. This 178 * method is retained mostly for backwards compatibility; 179 * you can call {@link #addFrame(DataSource, long, Bitmap)} directly. 180 * 181 * @param fd file descriptor of the data source. 182 * @param offset the byte offset within the specified file from which to start reading the data. 183 * @param length the number of bytes to read from the file. 184 * @param time the playback time at which the specified bitmap 185 * should be retrieved. 186 * @param bitmap the bitmap to retrieve. 187 */ addFrame(FileDescriptor fd, long offset, long length, long time, Bitmap bitmap)188 public static void addFrame(FileDescriptor fd, long offset, long length, 189 long time, Bitmap bitmap) { 190 addFrame(toDataSource(fd, offset, length), time, bitmap); 191 } 192 193 @Resetter reset()194 public static void reset() { 195 metadata.clear(); 196 frames.clear(); 197 exceptions.clear(); 198 } 199 } 200