Source Code: Find files by type + play media file
Jul 08
Android, Applications, Development, General, Tutorial find files on sd card, ListActivity, ListView, MediaPlayer, Source Code No Comments
I was perusing StackOverflow for Android items and came across this question Getting the Contents of a Specific Directory on the SDCard. I love StackOverflow… but for some reason I can’t post xml code examples and the code field doesn’t always work currently so you end up with code outside of the code box…. So, anyway, I decided to make an example for Edward and post it here so that everything would be formatted correctly.
This examples focus is the FileUtils class that I created for the purpose of finding files recursively on the SD Card. Here is the class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | public class FileUtils { public File[] listFilesAsArray(File directory, FilenameFilter[] filter, int recurse) { Collection<File> files = listFiles(directory, filter, recurse); File[] arr = new File[files.size()]; return files.toArray(arr); } public Collection<File> listFiles(File directory, FilenameFilter[] filter, int recurse) { Vector<File> files = new Vector<File>(); File[] entries = directory.listFiles(); if (entries != null) { for (File entry : entries) { for (FilenameFilter filefilter : filter) { if (filter == null || filefilter .accept(directory, entry.getName())) { files.add(entry); Log.v("FileUtils", "Added: " + entry.getName()); } } if ((recurse <= -1) || (recurse > 0 && entry.isDirectory())) { recurse--; files.addAll(listFiles(entry, filter, recurse)); recurse++; } } } return files; } } |
Edward needs to find files by type (specifically ringtones) from a path… either on the phone (as in the following example) or on the SD Card. He could use the MediaStore.Audio.Media Content Provider to accomplish this task… however, it would give him all of the audio media on the phone. It is sometimes necessary to list files by a particular mimetype without using the Content Providers. In my example, this is accomplished by using a list of file extensions and searching the desired path for files that match those file extensions. There are two ways you could go about it… you could make a String[] array of the extensions or you could use the Resources array as I have done. Below is the xml for the mimetypes we are looking for.
/res/values/mimetypes.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="audio"> <item>aif</item> <item>aifc</item> <item>aiff</item> <item>au</item> <item>mid</item> <item>mp3</item> <item>ogg</item> <item>snd</item> <item>wav</item> </string-array> </resources> |
Using a Resources string array is very convenient and provides a way for you to store arrays in files so that you can use them on demand rather than keeping them in memory. They are very simple to use. In my example you can see how they are used in the FindFiles function as seen here:
1 2 3 4 | Resources resources = getResources(); // array of valid audio file extensions String[] audioTypes = resources.getStringArray(R.array.audio); FilenameFilter[] filter = new FilenameFilter[audioTypes.length]; |
Of particular interest in the above example is the FilenameFilter object. This allows us to define an array of file extension filters that works very quickly and only returns the files we want.
Here is the example application that I created for Edward. It lists all of the audio files in /system/media/audio/ringtones/ and displays them in a ListView. When you click a particular file in the ListView it starts playing. There is a menu item to stop the ringtone from playing (there seems to be an issue with MediaPlayer.setLooping(false) when dealing with ogg files) and to quit the application. The complete Eclipse project is available for download at the bottom of the post.
/res/layout/main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?xml version="1.0" encoding="UTF-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <ListView android:id="@android:id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" android:drawSelectorOnTop="false" /> <TextView android:id="@android:id/empty" android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="No ringtones found." /> </LinearLayout> |
/res/layout/list_item.xml
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="utf-8"?> <TextView android:id="@+id/ringtone" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="40dip" android:textSize="18dip" android:textStyle="bold" android:textColor="#FFFFE0" /> |
/src/com/androidworks/findfiles/FindFilesByType.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | package com.androidworkz.findfiles; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Vector; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import android.app.AlertDialog; import android.app.ListActivity; import android.content.res.Resources; import android.media.MediaPlayer; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.AdapterView.OnItemClickListener; public class FindFilesByType extends ListActivity { private static final int EXIT = 0; private static final int STOP = 1; private static final String DIRECTORY = "/system/media/audio/ringtones/"; private MediaPlayer mp = new MediaPlayer(); List<String> Ringtones = new ArrayList<String>(); Boolean hasErrors = false; int currentPosition = 0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ListView lv = getListView(); File ringtones_directory = new File(DIRECTORY); if (!ringtones_directory.exists()) { AlertDialog.Builder ad = new AlertDialog.Builder( FindFilesByType.this); ad.setTitle("Directory Not Found"); ad.setMessage("Sorry! The ringtones directory doesn't exist."); ad.setPositiveButton("OK", null); ad.show(); hasErrors = true; } if (!ringtones_directory.canRead()) { AlertDialog.Builder ad = new AlertDialog.Builder( FindFilesByType.this); ad.setTitle("Permissions"); ad.setMessage("Sorry! You don't have permission to list the files in that folder"); ad.setPositiveButton("OK", null); ad.show(); hasErrors = true; } else { Ringtones = FindFiles(false); if (Ringtones.size() < 1) { AlertDialog.Builder ad = new AlertDialog.Builder( FindFilesByType.this); ad.setTitle("Permissions"); ad.setMessage("Sorry! No ringtones exists in " + DIRECTORY + "."); ad.setPositiveButton("OK", null); ad.show(); Log.e("Ringtones", "No ringtones were found."); hasErrors = true; } } if (!hasErrors) { setListAdapter(new ArrayAdapter<String>(FindFilesByType.this, R.layout.list_item, Ringtones)); lv.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> aView, View v, int position, long id) { currentPosition = position; playRingtone(DIRECTORY+Ringtones.get(position)); } }); } } public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); int NONE = Menu.NONE; if (mp.isPlaying()) { menu.add(NONE, STOP, 0, "Stop"); } menu.add(NONE, EXIT, 1, "Exit"); return true; } public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case STOP: mp.stop(); break; case EXIT: quit(); break; } return super.onOptionsItemSelected(item); } private void playRingtone(String ringtone) { try { mp.reset(); mp.setDataSource(ringtone); mp.prepare(); mp.start(); } catch (IOException e) { Log.v("Ringtone", e.getMessage()); } } private List<String> FindFiles(Boolean fullPath) { final List<String> tFileList = new ArrayList<String>(); Resources resources = getResources(); // array of valid audio file extensions String[] audioTypes = resources.getStringArray(R.array.audio); FilenameFilter[] filter = new FilenameFilter[audioTypes.length]; int i = 0; for (final String type : audioTypes) { filter[i] = new FilenameFilter() { public boolean accept(File dir, String name) { return name.endsWith("." + type); } }; i++; } FileUtils fileUtils = new FileUtils(); File[] allMatchingFiles = fileUtils.listFilesAsArray( new File(DIRECTORY), filter, -1); for (File f : allMatchingFiles) { if (fullPath) { tFileList.add(f.getAbsolutePath()); } else { tFileList.add(f.getName()); } } return tFileList; } public class FileUtils { public void saveArray(String filename, List<String> output_field) { try { FileOutputStream fos = new FileOutputStream(filename); GZIPOutputStream gzos = new GZIPOutputStream(fos); ObjectOutputStream out = new ObjectOutputStream(gzos); out.writeObject(output_field); out.flush(); out.close(); } catch (IOException e) { e.getStackTrace(); } } @SuppressWarnings("unchecked") public List<String> loadArray(String filename) { try { FileInputStream fis = new FileInputStream(filename); GZIPInputStream gzis = new GZIPInputStream(fis); ObjectInputStream in = new ObjectInputStream(gzis); List<String> read_field = (List<String>) in.readObject(); in.close(); return read_field; } catch (Exception e) { e.getStackTrace(); } return null; } public File[] listFilesAsArray(File directory, FilenameFilter[] filter, int recurse) { Collection<File> files = listFiles(directory, filter, recurse); File[] arr = new File[files.size()]; return files.toArray(arr); } public Collection<File> listFiles(File directory, FilenameFilter[] filter, int recurse) { Vector<File> files = new Vector<File>(); File[] entries = directory.listFiles(); if (entries != null) { for (File entry : entries) { for (FilenameFilter filefilter : filter) { if (filter == null || filefilter .accept(directory, entry.getName())) { files.add(entry); Log.v("FileUtils", "Added: " + entry.getName()); } } if ((recurse <= -1) || (recurse > 0 && entry.isDirectory())) { recurse--; files.addAll(listFiles(entry, filter, recurse)); recurse++; } } } return files; } } public void quit() { int pid = android.os.Process.myPid(); android.os.Process.killProcess(pid); System.exit(0); } } |
You can download the Eclipse Project Here: Download FindFilesByType.zip
