package cgeo.geocaching.files; import cgeo.geocaching.R; import cgeo.geocaching.Settings; import cgeo.geocaching.activity.AbstractListActivity; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import android.app.ProgressDialog; import android.content.DialogInterface; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.util.Log; import android.widget.ArrayAdapter; import java.io.File; import java.util.ArrayList; import java.util.List; public abstract class FileList> extends AbstractListActivity { private List files = new ArrayList(); private T adapter = null; private ProgressDialog waitDialog = null; private loadFiles searchingThread = null; private boolean endSearching = false; private int listId = 1; final private Handler changeWaitDialogHandler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.obj != null && waitDialog != null) { waitDialog.setMessage(res.getString(R.string.file_searching_in) + " " + (String) msg.obj); } } }; final private Handler loadFilesHandler = new Handler() { @Override public void handleMessage(Message msg) { try { if (CollectionUtils.isEmpty(files)) { if (waitDialog != null) { waitDialog.dismiss(); } showToast(res.getString(R.string.file_list_no_files)); finish(); return; } else { if (adapter != null) { adapter.notifyDataSetChanged(); } } if (waitDialog != null) { waitDialog.dismiss(); } } catch (Exception e) { if (waitDialog != null) { waitDialog.dismiss(); } Log.e(Settings.tag, "cgFileList.loadFilesHandler: " + e.toString()); } } }; private String[] extensions; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTheme(); setContentView(R.layout.gpx); setTitle(); Bundle extras = getIntent().getExtras(); if (extras != null) { listId = extras.getInt("list"); } if (listId <= 0) { listId = 1; } setAdapter(); waitDialog = ProgressDialog.show( this, res.getString(R.string.file_title_searching), res.getString(R.string.file_searching), true, true, new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface arg0) { if (searchingThread != null && searchingThread.isAlive()) { searchingThread.notifyEnd(); } if (files.isEmpty()) { finish(); } } } ); endSearching = false; searchingThread = new loadFiles(); searchingThread.start(); } @Override public void onResume() { super.onResume(); } protected abstract T getAdapter(List files); private void setAdapter() { if (adapter == null) { adapter = getAdapter(files); setListAdapter(adapter); } } /** * Gets the base folder for file searches * * @return The folder to start the recursive search in */ protected abstract File[] getBaseFolders(); /** * Triggers the deriving class to set the title */ protected abstract void setTitle(); private class loadFiles extends Thread { public void notifyEnd() { endSearching = true; } @Override public void run() { List list = new ArrayList(); try { if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { boolean loaded = false; for (final File dir : getBaseFolders()) { if (dir.exists() && dir.isDirectory()) { listDir(list, dir); if (list.size() > 0) { loaded = true; break; } } } if (!loaded) { listDir(list, Environment.getExternalStorageDirectory()); } } else { Log.w(Settings.tag, "No external media mounted."); } } catch (Exception e) { Log.e(Settings.tag, "cgFileList.loadFiles.run: " + e.toString()); } final Message msg = new Message(); msg.obj = "loaded directories"; changeWaitDialogHandler.sendMessage(msg); files.addAll(list); list.clear(); loadFilesHandler.sendMessage(new Message()); } } private void listDir(List result, File directory) { if (directory == null || !directory.isDirectory() || !directory.canRead()) { return; } final File[] files = directory.listFiles(); if (ArrayUtils.isNotEmpty(files)) { for (File file : files) { if (endSearching) { return; } if (!file.canRead()) { continue; } String name = file.getName(); if (file.isFile()) { if (filenameBelongsToList(name)) { result.add(file); // add file to list } } else if (file.isDirectory()) { if (name.charAt(0) == '.') { continue; // skip hidden directories } if (name.length() > 16) { name = name.substring(0, 14) + "..."; } final Message msg = new Message(); msg.obj = name; changeWaitDialogHandler.sendMessage(msg); listDir(result, file); // go deeper } } } return; } /** * Check if a filename belongs to the FileList. This implementation checks for file extensions. * Subclasses may override this method to filter out specific files. * * @param filename * @return true if the filename belongs to the list */ protected boolean filenameBelongsToList(final String filename) { for (String ext : extensions) { if (StringUtils.endsWithIgnoreCase(filename, ext)) { return true; } } return false; } protected FileList(final String extension) { setExtensions(new String[] { extension }); } protected FileList(final String[] extensions) { setExtensions(extensions); } private void setExtensions(String[] extensionsIn) { for (int i = 0; i < extensionsIn.length; i++) { String extension = extensionsIn[i]; if (extension.length() == 0 || extension.charAt(0) != '.') { extensionsIn[i] = "." + extension; } } extensions = extensionsIn; } }