diff --git a/aFileChooser/build.xml b/aFileChooser/build.xml
new file mode 100644
index 0000000..98d72f9
--- /dev/null
+++ b/aFileChooser/build.xml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aFileChooser/proguard-project.txt b/aFileChooser/proguard-project.txt
new file mode 100644
index 0000000..f2fe155
--- /dev/null
+++ b/aFileChooser/proguard-project.txt
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/aFileChooser/project.properties b/aFileChooser/project.properties
index acfc74e..f9e4d0b 100644
--- a/aFileChooser/project.properties
+++ b/aFileChooser/project.properties
@@ -8,5 +8,5 @@
# project structure.
# Project target.
-target=android-16
+target=android-10
android.library=true
diff --git a/aFileChooser/src/com/ipaulpro/afilechooser/FileChooserActivity.java b/aFileChooser/src/com/ipaulpro/afilechooser/FileChooserActivity.java
index 07d1099..7e4cc7b 100644
--- a/aFileChooser/src/com/ipaulpro/afilechooser/FileChooserActivity.java
+++ b/aFileChooser/src/com/ipaulpro/afilechooser/FileChooserActivity.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011 Paul Burke
+ * (Modified by Zhuowei Zhang for the PocketInvEditor project)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +22,8 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
import android.app.ListActivity;
import android.content.BroadcastReceiver;
@@ -62,6 +65,7 @@ public class FileChooserActivity extends ListActivity {
private File mExternalDir;
private ArrayList mList = new ArrayList();
+ private Set extendedMimeTypes = new HashSet();
/**
* File (not directories) filter.
@@ -69,8 +73,10 @@ public class FileChooserActivity extends ListActivity {
private FileFilter mFileFilter = new FileFilter() {
public boolean accept(File file) {
final String fileName = file.getName();
+ final String mimeType = FileUtils.getMimeType(FileChooserActivity.this, file);
// Return files only (not directories) and skip hidden files
- return file.isFile() && !fileName.startsWith(HIDDEN_PREFIX);
+ return file.isFile() && !fileName.startsWith(HIDDEN_PREFIX) &&
+ (mimeType.equals(getIntent().getType()) || extendedMimeTypes.contains(mimeType));
}
};
@@ -97,6 +103,15 @@ public int compare(File f1, File f2) {
}
};
+ private Comparator mLastModifiedComparator = new Comparator() {
+ public int compare(File f1, File f2) {
+ long a = f1.lastModified();
+ long b = f2.lastModified();
+ if (a == b) return 0;
+ return a < b? 1: -1;
+ }
+ };
+
/**
* External storage state broadcast receiver.
*/
@@ -311,9 +326,23 @@ protected void onFileDisconnect(){
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ String[] extraMimeTypes = getIntent().getStringArrayExtra(FileUtils.EXTRA_MIME_TYPES);
+ extendedMimeTypes.clear();
+ if (extraMimeTypes != null) {
+ for (String s: extraMimeTypes)
+ extendedMimeTypes.add(s);
+ }
+
// Get the external storage directory.
this.mExternalDir = Environment.getExternalStorageDirectory();
+ String sortMethod = getIntent().getStringExtra(FileUtils.EXTRA_SORT_METHOD);
+ if (sortMethod != null) {
+ if (sortMethod.equals(FileUtils.SORT_LAST_MODIFIED)) {
+ this.mComparator = this.mLastModifiedComparator;
+ }
+ }
+
if (getListAdapter() == null) {
// Assign the list adapter to the ListView
setListAdapter(new FileListAdapter(this));
@@ -324,6 +353,8 @@ protected void onCreate(Bundle savedInstanceState) {
} else {
// Set the external storage directory as the current path
this.mPath = this.mExternalDir.getAbsolutePath();
+ String startPath = getIntent().getStringExtra("startPath");
+ if (startPath != null) this.mPath = startPath;
// Add the current path to the breadcrumb
updateBreadcrumb(true);
@@ -423,4 +454,4 @@ private void restoreMe(Bundle state) {
this.mBreadcrumb = state.getStringArrayList(BREADCRUMB);
fillList(state.getInt(POSTIION));
}
-}
\ No newline at end of file
+}
diff --git a/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java b/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java
index e753a74..af6ab67 100644
--- a/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java
+++ b/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java
@@ -17,11 +17,17 @@
package com.ipaulpro.afilechooser.utils;
import java.io.File;
+import java.io.FileFilter;
import java.net.URISyntaxException;
import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
import android.content.res.XmlResourceParser;
import android.database.Cursor;
import android.graphics.Bitmap;
@@ -42,14 +48,17 @@
public class FileUtils {
/** TAG for log messages. */
static final String TAG = "FileUtils";
- private static final boolean DEBUG = true; // Set to false to disable logging
+ private static final boolean DEBUG = false; // Set to true to enable logging
- public static final String TYPE_AUDIO = "audio";
- public static final String TYPE_DOC = "doc";
- public static final String TYPE_IMAGE = "image";
- public static final String TYPE_OTHER = "other";
- public static final String TYPE_VIDEO = "video";
- public static final String TYPE_APP = "app";
+ public static final String MIME_TYPE_AUDIO = "audio/*";
+ public static final String MIME_TYPE_TEXT = "text/*";
+ public static final String MIME_TYPE_IMAGE = "image/*";
+ public static final String MIME_TYPE_VIDEO = "video/*";
+ public static final String MIME_TYPE_APP = "application/*";
+
+ public static final String EXTRA_MIME_TYPES = "net.zhuoweizhang.afilechooser.extra.MIME_TYPES";
+ public static final String EXTRA_SORT_METHOD = "net.zhuoweizhang.afilechooser.extra.SORT_METHOD";
+ public static final String SORT_LAST_MODIFIED = "net.zhuoweizhang.afilechooser.extra.SORT_LAST_MODIFIED";
/**
* Whether the filename is a video file.
@@ -106,11 +115,12 @@ public static String getExtension(String uri) {
* @param uri
* @return
*/
- public static boolean isMediaUri(String uri) {
- if (uri.startsWith(Audio.Media.INTERNAL_CONTENT_URI.toString())
- || uri.startsWith(Audio.Media.EXTERNAL_CONTENT_URI.toString())
- || uri.startsWith(Video.Media.INTERNAL_CONTENT_URI.toString())
- || uri.startsWith(Video.Media.EXTERNAL_CONTENT_URI.toString())) {
+ public static boolean isMediaUri(Uri uri) {
+ String uriString = uri.toString();
+ if (uriString.startsWith(Audio.Media.INTERNAL_CONTENT_URI.toString())
+ || uriString.startsWith(Audio.Media.EXTERNAL_CONTENT_URI.toString())
+ || uriString.startsWith(Video.Media.INTERNAL_CONTENT_URI.toString())
+ || uriString.startsWith(Video.Media.EXTERNAL_CONTENT_URI.toString())) {
return true;
} else {
return false;
@@ -191,6 +201,16 @@ public static File getFile(File curdir, String file) {
}
+ /**
+ * Get a file path from a Uri.
+ *
+ * @param context
+ * @param uri
+ * @return
+ * @throws URISyntaxException
+ *
+ * @author paulburke
+ */
public static String getPath(Context context, Uri uri) throws URISyntaxException {
if(DEBUG) Log.d(TAG+" File -",
@@ -226,6 +246,14 @@ else if ("file".equalsIgnoreCase(uri.getScheme())) {
return null;
}
+ /**
+ * Get the file size in a human-readable string.
+ *
+ * @param size
+ * @return
+ *
+ * @author paulburke
+ */
public static String getReadableFileSize(int size) {
final int BYTES_IN_KILOBYTES = 1024;
final DecimalFormat dec = new DecimalFormat("###.#");
@@ -251,10 +279,12 @@ public static String getReadableFileSize(int size) {
}
/**
+ * Load MIME types from XML
+ *
* @param context
* @return
*/
- public static MimeTypes getMimeTypes(Context context) {
+ private static MimeTypes getMimeTypes(Context context) {
MimeTypes mimeTypes = null;
final MimeTypeParser mtp = new MimeTypeParser();
final XmlResourceParser in = context.getResources().getXml(R.xml.mimetypes);
@@ -268,6 +298,8 @@ public static MimeTypes getMimeTypes(Context context) {
}
/**
+ * Get the file MIME type
+ *
* @param context
* @param file
* @return
@@ -280,13 +312,55 @@ public static String getMimeType(Context context, File file) {
}
/**
+ * Attempt to retrieve the thumbnail of given File from the MediaStore.
+ *
+ * This should not be called on the UI thread.
+ *
+ * @param context
+ * @param file
+ * @return
+ *
+ * @author paulburke
+ */
+ public static Bitmap getThumbnail(Context context, File file) {
+ return getThumbnail(context, getUri(file), getMimeType(context, file));
+ }
+
+ /**
+ * Attempt to retrieve the thumbnail of given Uri from the MediaStore.
+ *
+ * This should not be called on the UI thread.
+ *
+ * @param context
+ * @param uri
+ * @return
+ *
+ * @author paulburke
+ */
+ public static Bitmap getThumbnail(Context context, Uri uri) {
+ return getThumbnail(context, uri, getMimeType(context, getFile(uri)));
+ }
+
+ /**
+ * Attempt to retrieve the thumbnail of given Uri from the MediaStore.
+ *
+ * This should not be called on the UI thread.
+ *
* @param context
* @param uri
* @param mimeType
* @return
+ *
+ * @author paulburke
*/
public static Bitmap getThumbnail(Context context, Uri uri, String mimeType) {
if(DEBUG) Log.d(TAG, "Attempting to get thumbnail");
+
+ if (isMediaUri(uri)) {
+ Log.e(TAG, "You can only retrieve thumbnails for images and videos.");
+ return null;
+ }
+
Bitmap bm = null;
if (uri != null) {
final ContentResolver resolver = context.getContentResolver();
@@ -304,7 +378,7 @@ public static Bitmap getThumbnail(Context context, Uri uri, String mimeType) {
MediaStore.Video.Thumbnails.MINI_KIND,
null);
}
- else if (mimeType.contains("image")) {
+ else if (mimeType.contains(FileUtils.MIME_TYPE_IMAGE)) {
bm = MediaStore.Images.Thumbnails.getThumbnail(
resolver,
id,
@@ -320,4 +394,98 @@ else if (mimeType.contains("image")) {
}
return bm;
}
+
+ private static final String HIDDEN_PREFIX = ".";
+
+ /**
+ * File and folder comparator.
+ * TODO Expose sorting option method
+ *
+ * @author paulburke
+ */
+ private static Comparator mComparator = new Comparator() {
+ public int compare(File f1, File f2) {
+ // Sort alphabetically by lower case, which is much cleaner
+ return f1.getName().toLowerCase().compareTo(
+ f2.getName().toLowerCase());
+ }
+ };
+
+ /**
+ * File (not directories) filter.
+ *
+ * @author paulburke
+ */
+ private static FileFilter mFileFilter = new FileFilter() {
+ public boolean accept(File file) {
+ final String fileName = file.getName();
+ // Return files only (not directories) and skip hidden files
+ return file.isFile() && !fileName.startsWith(HIDDEN_PREFIX);
+ }
+ };
+
+ /**
+ * Folder (directories) filter.
+ *
+ * @author paulburke
+ */
+ private static FileFilter mDirFilter = new FileFilter() {
+ public boolean accept(File file) {
+ final String fileName = file.getName();
+ // Return directories only and skip hidden directories
+ return file.isDirectory() && !fileName.startsWith(HIDDEN_PREFIX);
+ }
+ };
+
+ /**
+ * Get a list of Files in the give path
+ *
+ * @param path
+ * @return Collection of files in give directory
+
+ * @author paulburke
+ */
+ public static List getFileList(String path) {
+ ArrayList list = new ArrayList();
+
+ // Current directory File instance
+ final File pathDir = new File(path);
+
+ // List file in this directory with the directory filter
+ final File[] dirs = pathDir.listFiles(mDirFilter);
+ if (dirs != null) {
+ // Sort the folders alphabetically
+ Arrays.sort(dirs, mComparator);
+ // Add each folder to the File list for the list adapter
+ for (File dir : dirs) list.add(dir);
+ }
+
+ // List file in this directory with the file filter
+ final File[] files = pathDir.listFiles(mFileFilter);
+ if (files != null) {
+ // Sort the files alphabetically
+ Arrays.sort(files, mComparator);
+ // Add each file to the File list for the list adapter
+ for (File file : files) list.add(file);
+ }
+
+ return list;
+ }
+
+ /**
+ * Get the Intent for selecting content to be used in an Intent Chooser.
+ *
+ * @return The intent for opening a file with Intent.createChooser()
+ *
+ * @author paulburke
+ */
+ public static Intent createGetContentIntent() {
+ // Implicitly allow the user to select a particular kind of data
+ final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ // The MIME data type filter
+ intent.setType("*/*");
+ // Only return URIs that can be opened with ContentResolver
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ return intent;
+ }
}