You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2013/03/14 17:45:03 UTC

android commit: [CB-2435] Split common methods out of FileUtils into FileHelpers

Updated Branches:
  refs/heads/master ee38b2ef0 -> ac2969c3f


[CB-2435] Split common methods out of FileUtils into FileHelpers

Also included in this change:
- Fixed getMimeType for content:// URIs.
- Made getRealPath take a URI string.
- Added basic android_asset handling.
There is no such thing as a "real path" for a file:///android_asset URI.  However, it is possible to get an input stream to one.

And even more minor changes:
- removed unused FileReader/FileWriter instance variables
- added logging when getRealPath fails
- fixed indentation issues
- removed a try/catch in favor of throwing
- removed a null check in favor of throwing
- moved getEntry back to FilePlugin


Project: http://git-wip-us.apache.org/repos/asf/cordova-android/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-android/commit/ac2969c3
Tree: http://git-wip-us.apache.org/repos/asf/cordova-android/tree/ac2969c3
Diff: http://git-wip-us.apache.org/repos/asf/cordova-android/diff/ac2969c3

Branch: refs/heads/master
Commit: ac2969c3f80a1ec72f5dcb2276d2a82900d6bf0b
Parents: ee38b2e
Author: Max Woghiren <ma...@gmail.com>
Authored: Tue Mar 12 11:19:08 2013 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Thu Mar 14 12:39:51 2013 -0400

----------------------------------------------------------------------
 framework/src/org/apache/cordova/AudioHandler.java |    6 +-
 .../src/org/apache/cordova/CameraLauncher.java     |   16 +-
 framework/src/org/apache/cordova/Capture.java      |    8 +-
 framework/src/org/apache/cordova/FileHelper.java   |  142 ++++++++++
 framework/src/org/apache/cordova/FileTransfer.java |    3 +-
 framework/src/org/apache/cordova/FileUtils.java    |  204 +++++----------
 6 files changed, 217 insertions(+), 162 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/ac2969c3/framework/src/org/apache/cordova/AudioHandler.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/AudioHandler.java b/framework/src/org/apache/cordova/AudioHandler.java
index ed5757f..fd8c9df 100644
--- a/framework/src/org/apache/cordova/AudioHandler.java
+++ b/framework/src/org/apache/cordova/AudioHandler.java
@@ -68,13 +68,13 @@ public class AudioHandler extends CordovaPlugin {
         String result = "";
 
         if (action.equals("startRecordingAudio")) {
-            this.startRecordingAudio(args.getString(0), FileUtils.stripFileProtocol(args.getString(1)));
+            this.startRecordingAudio(args.getString(0), FileHelper.stripFileProtocol(args.getString(1)));
         }
         else if (action.equals("stopRecordingAudio")) {
             this.stopRecordingAudio(args.getString(0));
         }
         else if (action.equals("startPlayingAudio")) {
-            this.startPlayingAudio(args.getString(0), FileUtils.stripFileProtocol(args.getString(1)));
+            this.startPlayingAudio(args.getString(0), FileHelper.stripFileProtocol(args.getString(1)));
         }
         else if (action.equals("seekToAudio")) {
             this.seekToAudio(args.getString(0), args.getInt(1));
@@ -102,7 +102,7 @@ public class AudioHandler extends CordovaPlugin {
         }
         else if (action.equals("create")) {
             String id = args.getString(0);
-            String src = FileUtils.stripFileProtocol(args.getString(1));
+            String src = FileHelper.stripFileProtocol(args.getString(1));
             AudioPlayer audio = new AudioPlayer(this, id, src);
             this.players.put(id, audio);
         }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/ac2969c3/framework/src/org/apache/cordova/CameraLauncher.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CameraLauncher.java b/framework/src/org/apache/cordova/CameraLauncher.java
index aec0def..9473828 100755
--- a/framework/src/org/apache/cordova/CameraLauncher.java
+++ b/framework/src/org/apache/cordova/CameraLauncher.java
@@ -289,7 +289,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
 
                     // If sending base64 image back
                     if (destType == DATA_URL) {
-                        bitmap = getScaledBitmap(FileUtils.stripFileProtocol(imageUri.toString()));
+                        bitmap = getScaledBitmap(FileHelper.stripFileProtocol(imageUri.toString()));
                         if (bitmap == null) {
                             // Try to get the bitmap from intent.
                             bitmap = (Bitmap)intent.getExtras().get("data");
@@ -329,7 +329,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
 
                             this.callbackContext.success(uri.toString());
                         } else {
-                            bitmap = getScaledBitmap(FileUtils.stripFileProtocol(imageUri.toString()));
+                            bitmap = getScaledBitmap(FileHelper.stripFileProtocol(imageUri.toString()));
 
                             if (rotate != 0 && this.correctOrientation) {
                                 bitmap = getRotatedBitmap(rotate, bitmap, exif);
@@ -344,7 +344,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                             if (this.encodingType == JPEG) {
                                 String exifPath;
                                 if (this.saveToPhotoAlbum) {
-                                    exifPath = FileUtils.getRealPathFromURI(uri, this.cordova);
+                                    exifPath = FileHelper.getRealPath(uri, this.cordova);
                                 } else {
                                     exifPath = uri.getPath();
                                 }
@@ -395,8 +395,8 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                         this.callbackContext.success(uri.toString());
                     } else {
                         // Get the path to the image. Makes loading so much easier.
-                        String imagePath = FileUtils.getRealPathFromURI(uri, this.cordova);
-                        String mimeType = FileUtils.getMimeType(imagePath);
+                        String imagePath = FileHelper.getRealPath(uri, this.cordova);
+                        String mimeType = FileHelper.getMimeType(imagePath, this.cordova);
                         // Log.d(LOG_TAG, "Real path = " + imagePath);
                         // Log.d(LOG_TAG, "mime type = " + mimeType);
                         // If we don't have a valid image so quit.
@@ -458,7 +458,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
 
                                     // Restore exif data to file
                                     if (this.encodingType == JPEG) {
-                                        exif.createOutFile(FileUtils.getRealPathFromURI(uri, this.cordova));
+                                        exif.createOutFile(FileHelper.getRealPath(uri, this.cordova));
                                         exif.writeExifData();
                                     }
 
@@ -521,7 +521,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
      */
     private void writeUncompressedImage(Uri uri) throws FileNotFoundException,
             IOException {
-        FileInputStream fis = new FileInputStream(FileUtils.stripFileProtocol(imageUri.toString()));
+        FileInputStream fis = new FileInputStream(FileHelper.stripFileProtocol(imageUri.toString()));
         OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri);
         byte[] buffer = new byte[4096];
         int len;
@@ -685,7 +685,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
         }
 
         // Clean up initial camera-written image file.
-        (new File(FileUtils.stripFileProtocol(oldImage.toString()))).delete();
+        (new File(FileHelper.stripFileProtocol(oldImage.toString()))).delete();
 
         checkForDuplicateImage(imageType);
         // Scan for the gallery to update pic refs in gallery

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/ac2969c3/framework/src/org/apache/cordova/Capture.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/Capture.java b/framework/src/org/apache/cordova/Capture.java
index 3eecf37..1ed99d0 100644
--- a/framework/src/org/apache/cordova/Capture.java
+++ b/framework/src/org/apache/cordova/Capture.java
@@ -128,7 +128,7 @@ public class Capture extends CordovaPlugin {
         // If the mimeType isn't set the rest will fail
         // so let's see if we can determine it.
         if (mimeType == null || mimeType.equals("") || "null".equals(mimeType)) {
-            mimeType = FileUtils.getMimeType(filePath);
+            mimeType = FileHelper.getMimeType(filePath, cordova);
         }
         Log.d(LOG_TAG, "Mime type = " + mimeType);
 
@@ -155,7 +155,7 @@ public class Capture extends CordovaPlugin {
     private JSONObject getImageData(String filePath, JSONObject obj) throws JSONException {
         BitmapFactory.Options options = new BitmapFactory.Options();
         options.inJustDecodeBounds = true;
-        BitmapFactory.decodeFile(FileUtils.stripFileProtocol(filePath), options);
+        BitmapFactory.decodeFile(FileHelper.stripFileProtocol(filePath), options);
         obj.put("height", options.outHeight);
         obj.put("width", options.outWidth);
         return obj;
@@ -346,7 +346,7 @@ public class Capture extends CordovaPlugin {
      * @throws IOException
      */
     private JSONObject createMediaFile(Uri data) {
-        File fp = new File(FileUtils.getRealPathFromURI(data, this.cordova));
+        File fp = new File(FileHelper.getRealPath(data, this.cordova));
         JSONObject obj = new JSONObject();
 
         try {
@@ -363,7 +363,7 @@ public class Capture extends CordovaPlugin {
                     obj.put("type", VIDEO_3GPP);
                 }
             } else {
-                obj.put("type", FileUtils.getMimeType(fp.getAbsolutePath()));
+                obj.put("type", FileHelper.getMimeType(fp.getAbsolutePath(), cordova));
             }
 
             obj.put("lastModifiedDate", fp.lastModified());

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/ac2969c3/framework/src/org/apache/cordova/FileHelper.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/FileHelper.java b/framework/src/org/apache/cordova/FileHelper.java
new file mode 100644
index 0000000..c10ed96
--- /dev/null
+++ b/framework/src/org/apache/cordova/FileHelper.java
@@ -0,0 +1,142 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+ */
+package org.apache.cordova;
+
+import android.database.Cursor;
+import android.net.Uri;
+import android.webkit.MimeTypeMap;
+
+import org.apache.cordova.api.CordovaInterface;
+import org.apache.cordova.api.LOG;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class FileHelper {
+    private static final String LOG_TAG = "FileUtils";
+    private static final String _DATA = "_data";
+
+    /**
+     * Returns the real path of the given URI string.
+     * If the given URI string represents a content:// URI, the real path is retrieved from the media store.
+     *
+     * @param uriString the URI string of the audio/image/video
+     * @param cordova the current application context
+     * @return the full path to the file
+     */
+    @SuppressWarnings("deprecation")
+    public static String getRealPath(String uriString, CordovaInterface cordova) {
+        String realPath = null;
+
+        if (uriString.startsWith("content://")) {
+            String[] proj = { _DATA };
+            Cursor cursor = cordova.getActivity().managedQuery(Uri.parse(uriString), proj, null, null, null);
+            int column_index = cursor.getColumnIndexOrThrow(_DATA);
+            cursor.moveToFirst();
+            realPath = cursor.getString(column_index);
+            if (realPath == null) {
+                LOG.e(LOG_TAG, "Could get real path for URI string %s", uriString);
+            }
+        } else if (uriString.startsWith("file://")) {
+            realPath = uriString.substring(7);
+            if (realPath.startsWith("/android_asset/")) {
+                LOG.e(LOG_TAG, "Cannot get real path for URI string %s because it is a file:///android_asset/ URI.", uriString);
+                realPath = null;
+            }
+        } else {
+            realPath = uriString;
+        }
+
+        return realPath;
+    }
+
+    /**
+     * Returns the real path of the given URI.
+     * If the given URI is a content:// URI, the real path is retrieved from the media store.
+     *
+     * @param uri the URI of the audio/image/video
+     * @param cordova the current application context
+     * @return the full path to the file
+     */
+    public static String getRealPath(Uri uri, CordovaInterface cordova) {
+        return FileHelper.getRealPath(uri.toString(), cordova);
+    }
+
+    /**
+     * Returns an input stream based on given URI string.
+     *
+     * @param uriString the URI string from which to obtain the input stream
+     * @param cordova the current application context
+     * @return an input stream into the data at the given URI or null if given an invalid URI string
+     * @throws IOException
+     */
+    public static InputStream getInputStreamFromUriString(String uriString, CordovaInterface cordova) throws IOException {
+        if (uriString.startsWith("content")) {
+            Uri uri = Uri.parse(uriString);
+            return cordova.getActivity().getContentResolver().openInputStream(uri);
+        } else if (uriString.startsWith("file:///android_asset/")) {
+            String relativePath = uriString.substring(22);
+            return cordova.getActivity().getAssets().open(relativePath);
+        } else {
+            return new FileInputStream(getRealPath(uriString, cordova));
+        }
+    }
+
+    /**
+     * Removes the "file://" prefix from the given URI string, if applicable.
+     * If the given URI string doesn't have a "file://" prefix, it is returned unchanged.
+     *
+     * @param uriString the URI string to operate on
+     * @return a path without the "file://" prefix
+     */
+    public static String stripFileProtocol(String uriString) {
+        if (uriString.startsWith("file://")) {
+            uriString = uriString.substring(7);
+        }
+        return uriString;
+    }
+
+    /**
+     * Returns the mime type of the data specified by the given URI string.
+     *
+     * @param uriString the URI string of the data
+     * @return the mime type of the specified data
+     */
+    public static String getMimeType(String uriString, CordovaInterface cordova) {
+        String mimeType = null;
+
+        if (uriString.startsWith("content://")) {
+            Uri uri = Uri.parse(uriString);
+            mimeType = cordova.getActivity().getContentResolver().getType(uri);
+        } else {
+            // MimeTypeMap.getFileExtensionFromUrl has a bug that occurs when the filename has a space, so we encode it.
+            // We also convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
+            String encodedUriString = uriString.replace(" ", "%20").toLowerCase();
+            String extension = MimeTypeMap.getFileExtensionFromUrl(encodedUriString);
+            if (extension.equals("3ga")) {
+                mimeType = "audio/3gpp";
+            } else {
+                mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+            }
+        }
+
+        return mimeType;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/ac2969c3/framework/src/org/apache/cordova/FileTransfer.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/FileTransfer.java b/framework/src/org/apache/cordova/FileTransfer.java
index 5b97463..dba29af 100644
--- a/framework/src/org/apache/cordova/FileTransfer.java
+++ b/framework/src/org/apache/cordova/FileTransfer.java
@@ -750,8 +750,7 @@ public class FileTransfer extends CordovaPlugin {
                     Log.d(LOG_TAG, "Saved file: " + target);
     
                     // create FileEntry object
-                    FileUtils fileUtil = new FileUtils();
-                    JSONObject fileEntry = fileUtil.getEntry(file);
+                    JSONObject fileEntry = FileUtils.getEntry(file);
                     
                     result = new PluginResult(PluginResult.Status.OK, fileEntry);
                 } catch (FileNotFoundException e) {

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/ac2969c3/framework/src/org/apache/cordova/FileUtils.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/FileUtils.java b/framework/src/org/apache/cordova/FileUtils.java
index 69e11f6..afcabfb 100755
--- a/framework/src/org/apache/cordova/FileUtils.java
+++ b/framework/src/org/apache/cordova/FileUtils.java
@@ -15,18 +15,16 @@
        KIND, either express or implied.  See the License for the
        specific language governing permissions and limitations
        under the License.
-*/
+ */
 package org.apache.cordova;
 
-import java.io.*;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLDecoder;
-import java.nio.channels.FileChannel;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Environment;
+import android.provider.MediaStore;
 
 import org.apache.commons.codec.binary.Base64;
 import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaInterface;
 import org.apache.cordova.api.CordovaPlugin;
 import org.apache.cordova.api.PluginResult;
 import org.apache.cordova.file.EncodingException;
@@ -38,12 +36,20 @@ import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.nio.channels.FileChannel;
 //import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Environment;
-import android.provider.MediaStore;
-import android.webkit.MimeTypeMap;
 
 //import android.app.Activity;
 
@@ -53,8 +59,7 @@ import android.webkit.MimeTypeMap;
  */
 public class FileUtils extends CordovaPlugin {
     @SuppressWarnings("unused")
-    private static final String LOG_TAG = "FileUtils";
-    private static final String _DATA = "_data";    // The column name where the file path is stored
+    private static final String LOG_TAG = "FilePlugin";
 
     public static int NOT_FOUND_ERR = 1;
     public static int SECURITY_ERR = 2;
@@ -75,9 +80,6 @@ public class FileUtils extends CordovaPlugin {
     public static int RESOURCE = 2;
     public static int APPLICATION = 3;
 
-    FileReader f_in;
-    FileWriter f_out;
-
     /**
      * Constructor.
      */
@@ -250,11 +252,11 @@ public class FileUtils extends CordovaPlugin {
      * @param filePath the path to check
      */
     private void notifyDelete(String filePath) {
-        String newFilePath = getRealPathFromURI(Uri.parse(filePath), cordova);
+        String newFilePath = FileHelper.getRealPath(filePath, cordova);
         try {
             this.cordova.getActivity().getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
-                MediaStore.Images.Media.DATA + " = ?",
-                new String[] { newFilePath });
+                    MediaStore.Images.Media.DATA + " = ?",
+                    new String[] { newFilePath });
         } catch (UnsupportedOperationException t) {
             // Was seeing this on the File mobile-spec tests on 4.0.3 x86 emulator.
             // The ContentResolver applies only when the file was registered in the
@@ -357,8 +359,8 @@ public class FileUtils extends CordovaPlugin {
      * @throws FileExistsException
      */
     private JSONObject transferTo(String fileName, String newParent, String newName, boolean move) throws JSONException, NoModificationAllowedException, IOException, InvalidModificationException, EncodingException, FileExistsException {
-        String newFileName = getRealPathFromURI(Uri.parse(fileName), cordova);
-        newParent = getRealPathFromURI(Uri.parse(newParent), cordova);
+        String newFileName = FileHelper.getRealPath(fileName, cordova);
+        newParent = FileHelper.getRealPath(newParent, cordova);
 
         // Check for invalid file name
         if (newName != null && newName.contains(":")) {
@@ -397,14 +399,14 @@ public class FileUtils extends CordovaPlugin {
             }
         } else {
             if (move) {
-            	JSONObject newFileEntry = moveFile(source, destination);
+                JSONObject newFileEntry = moveFile(source, destination);
 
-            	// If we've moved a file given its content URI, we need to clean up.
-            	if (fileName.startsWith("content://")) {
-            		notifyDelete(fileName);
-            	}
+                // If we've moved a file given its content URI, we need to clean up.
+                if (fileName.startsWith("content://")) {
+                    notifyDelete(fileName);
+                }
 
-            	return newFileEntry;
+                return newFileEntry;
             } else {
                 return copyFile(source, destination);
             }
@@ -761,7 +763,7 @@ public class FileUtils extends CordovaPlugin {
         if (fileName.startsWith("/")) {
             fp = new File(fileName);
         } else {
-            dirPath = getRealPathFromURI(Uri.parse(dirPath), cordova);
+            dirPath = FileHelper.getRealPath(dirPath, cordova);
             fp = new File(dirPath + File.separator + fileName);
         }
         return fp;
@@ -776,7 +778,7 @@ public class FileUtils extends CordovaPlugin {
      * @throws JSONException
      */
     private JSONObject getParent(String filePath) throws JSONException {
-        filePath = getRealPathFromURI(Uri.parse(filePath), cordova);
+        filePath = FileHelper.getRealPath(filePath, cordova);
 
         if (atRootDirectory(filePath)) {
             return getEntry(filePath);
@@ -792,7 +794,7 @@ public class FileUtils extends CordovaPlugin {
      * @return true if we are at the root, false otherwise.
      */
     private boolean atRootDirectory(String filePath) {
-        filePath = getRealPathFromURI(Uri.parse(filePath), cordova);
+        filePath = FileHelper.getRealPath(filePath, cordova);
 
         if (filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + cordova.getActivity().getPackageName() + "/cache") ||
                 filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath()) ||
@@ -803,26 +805,13 @@ public class FileUtils extends CordovaPlugin {
     }
 
     /**
-     * This method removes the "file://" from the passed in filePath
-     *
-     * @param filePath to be checked.
-     * @return
-     */
-    public static String stripFileProtocol(String filePath) {
-        if (filePath.startsWith("file://")) {
-            filePath = filePath.substring(7);
-        }
-        return filePath;
-    }
-
-    /**
      * Create a File object from the passed in path
      *
      * @param filePath
      * @return
      */
     private File createFileObject(String filePath) {
-    	filePath = getRealPathFromURI(Uri.parse(filePath), cordova);
+        filePath = FileHelper.getRealPath(filePath, cordova);
 
         File file = new File(filePath);
         return file;
@@ -862,7 +851,7 @@ public class FileUtils extends CordovaPlugin {
 
         JSONObject metadata = new JSONObject();
         metadata.put("size", file.length());
-        metadata.put("type", getMimeType(filePath));
+        metadata.put("type", FileHelper.getMimeType(filePath, cordova));
         metadata.put("name", file.getName());
         metadata.put("fullPath", filePath);
         metadata.put("lastModifiedDate", file.lastModified());
@@ -913,21 +902,21 @@ public class FileUtils extends CordovaPlugin {
     }
 
     /**
-     * Returns a JSON Object representing a directory on the device's file system
+     * Returns a JSON object representing the given File.
      *
-     * @param path to the directory
-     * @return
+     * @param file the File to convert
+     * @return a JSON representation of the given File
      * @throws JSONException
      */
-    public JSONObject getEntry(File file) throws JSONException {
+    public static JSONObject getEntry(File file) throws JSONException {
         JSONObject entry = new JSONObject();
 
         entry.put("isFile", file.isFile());
         entry.put("isDirectory", file.isDirectory());
         entry.put("name", file.getName());
         entry.put("fullPath", "file://" + file.getAbsolutePath());
-        // I can't add the next thing it as it would be an infinite loop
-        //entry.put("filesystem", null);
+        // The file system can't be specified, as it would lead to an infinite loop.
+        // entry.put("filesystem", null);
 
         return entry;
     }
@@ -983,7 +972,7 @@ public class FileUtils extends CordovaPlugin {
     public String readAsText(String filename, String encoding, int start, int end) throws FileNotFoundException, IOException {
         int diff = end - start;
         byte[] bytes = new byte[1000];
-        BufferedInputStream bis = new BufferedInputStream(getPathFromUri(filename), 1024);
+        BufferedInputStream bis = new BufferedInputStream(FileHelper.getInputStreamFromUriString(filename, cordova), 1024);
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
         int numRead = 0;
 
@@ -1001,6 +990,7 @@ public class FileUtils extends CordovaPlugin {
 
     /**
      * Helper method to read a text file and return its contents as a byte[].
+     *
      * @param filename          The name of the file.
      * @param start             Start position in the file.
      * @param end               End position to stop at (exclusive).
@@ -1010,7 +1000,7 @@ public class FileUtils extends CordovaPlugin {
     public byte[] readAsBinary(String filename, int start, int end) throws FileNotFoundException, IOException {
         int diff = end - start;
         byte[] bytes = new byte[1000];
-        BufferedInputStream bis = new BufferedInputStream(getPathFromUri(filename), 1024);
+        BufferedInputStream bis = new BufferedInputStream(FileHelper.getInputStreamFromUriString(filename, cordova), 1024);
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
         int numRead = 0;
 
@@ -1029,54 +1019,22 @@ public class FileUtils extends CordovaPlugin {
     /**
      * Read content of a file and return as base64 encoded data url.
      *
-     * @param filename			The name of the file.
-     * @param start             Start position in the file.
-     * @param end               End position to stop at (exclusive).
-     * @return					Contents of file = data:<media type>;base64,<data>
+     * @param filename        The name of the file.
+     * @param start           Start position in the file.
+     * @param end             End position to stop at (exclusive).
+     * @return                Contents of file = data:<media type>;base64,<data>
      * @throws FileNotFoundException, IOException
      */
     public String readAsDataURL(String filename, int start, int end) throws FileNotFoundException, IOException {
-    	// Determine content type from file name
-        String contentType = null;
-        if (filename.startsWith("content:")) {
-            Uri fileUri = Uri.parse(filename);
-            contentType = this.cordova.getActivity().getContentResolver().getType(fileUri);
-        }
-        else {
-            contentType = getMimeType(filename);
-        }
+        // Determine content type from file name
+        String contentType = FileHelper.getMimeType(filename, cordova);
 
-    	byte[] base64 = Base64.encodeBase64(readAsBinary(filename, start, end));
+        byte[] base64 = Base64.encodeBase64(readAsBinary(filename, start, end));
         String data = "data:" + contentType + ";base64," + new String(base64);
         return data;
     }
 
     /**
-     * Looks up the mime type of a given file name.
-     *
-     * @param filename
-     * @return a mime type
-     */
-    public static String getMimeType(String filename) {
-        if (filename != null) {
-            // Stupid bug in getFileExtensionFromUrl when the file name has a space
-            // So we need to replace the space with a url encoded %20
-
-            // CB-2185: Stupid bug not putting JPG extension in the mime-type map
-            String url = filename.replace(" ", "%20").toLowerCase();
-            MimeTypeMap map = MimeTypeMap.getSingleton();
-            String extension = MimeTypeMap.getFileExtensionFromUrl(url);
-            if (extension.toLowerCase().equals("3ga")) {
-                return "audio/3gpp";
-            } else {
-                return map.getMimeTypeFromExtension(extension);
-            }
-        } else {
-            return "";
-        }
-    }
-
-    /**
      * Write contents of file.
      *
      * @param filename			The name of the file.
@@ -1087,11 +1045,11 @@ public class FileUtils extends CordovaPlugin {
      */
     /**/
     public long write(String filename, String data, int offset) throws FileNotFoundException, IOException, NoModificationAllowedException {
-    	if (filename.startsWith("content://")) {
-    		throw new NoModificationAllowedException("Couldn't write to file given its content URI");
-    	}
+        if (filename.startsWith("content://")) {
+            throw new NoModificationAllowedException("Couldn't write to file given its content URI");
+        }
 
-        filename = getRealPathFromURI(Uri.parse(filename), cordova);
+        filename = FileHelper.getRealPath(filename, cordova);
 
         boolean append = false;
         if (offset > 0) {
@@ -1120,11 +1078,11 @@ public class FileUtils extends CordovaPlugin {
      * @throws NoModificationAllowedException
      */
     private long truncateFile(String filename, long size) throws FileNotFoundException, IOException, NoModificationAllowedException {
-    	if (filename.startsWith("content://")) {
-    		throw new NoModificationAllowedException("Couldn't truncate file given its content URI");
-    	}
+        if (filename.startsWith("content://")) {
+            throw new NoModificationAllowedException("Couldn't truncate file given its content URI");
+        }
 
-        filename = getRealPathFromURI(Uri.parse(filename), cordova);
+        filename = FileHelper.getRealPath(filename, cordova);
 
         RandomAccessFile raf = new RandomAccessFile(filename, "rw");
         try {
@@ -1139,48 +1097,4 @@ public class FileUtils extends CordovaPlugin {
             raf.close();
         }
     }
-
-    /**
-     * Get an input stream based on file path or content:// uri
-     *
-     * @param path
-     * @return an input stream
-     * @throws FileNotFoundException
-     */
-    private InputStream getPathFromUri(String path) throws FileNotFoundException {
-        if (path.startsWith("content")) {
-            Uri uri = Uri.parse(path);
-            return cordova.getActivity().getContentResolver().openInputStream(uri);
-        }
-        else {
-            path = getRealPathFromURI(Uri.parse(path), cordova);
-            return new FileInputStream(path);
-        }
-    }
-
-    /**
-     * Queries the media store to find out what the file path is for the Uri we supply
-     *
-     * @param contentUri the Uri of the audio/image/video
-     * @param cordova the current application context
-     * @return the full path to the file
-     */
-    @SuppressWarnings("deprecation")
-    protected static String getRealPathFromURI(Uri contentUri, CordovaInterface cordova) {
-        final String scheme = contentUri.getScheme();
-
-        if (scheme == null) {
-        	return contentUri.toString();
-    	} else if (scheme.compareTo("content") == 0) {
-            String[] proj = { _DATA };
-            Cursor cursor = cordova.getActivity().managedQuery(contentUri, proj, null, null, null);
-            int column_index = cursor.getColumnIndexOrThrow(_DATA);
-            cursor.moveToFirst();
-            return cursor.getString(column_index);
-        } else if (scheme.compareTo("file") == 0) {
-            return contentUri.getPath();
-        } else {
-            return contentUri.toString();
-        }
-    }
 }